batman-rails 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  module Batman
2
2
  module Rails
3
- VERSION = "0.0.8"
4
- BATMAN_VERSION = "0.12.0"
3
+ VERSION = "0.0.9"
4
+ BATMAN_VERSION = "0.13.1"
5
5
  end
6
6
  end
@@ -1,5 +1,57 @@
1
1
  (function() {
2
2
 
3
+ Batman.extend(Batman.DOM, {
4
+ querySelectorAll: function(node, selector) {
5
+ return jQuery(selector, node);
6
+ },
7
+ querySelector: function(node, selector) {
8
+ return jQuery(selector, node)[0];
9
+ },
10
+ setInnerHTML: function(node, html) {
11
+ var child, childNodes, result, _i, _j, _len, _len1;
12
+ childNodes = (function() {
13
+ var _i, _len, _ref, _results;
14
+ _ref = node.childNodes;
15
+ _results = [];
16
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
17
+ child = _ref[_i];
18
+ _results.push(child);
19
+ }
20
+ return _results;
21
+ })();
22
+ for (_i = 0, _len = childNodes.length; _i < _len; _i++) {
23
+ child = childNodes[_i];
24
+ Batman.DOM.willRemoveNode(child);
25
+ }
26
+ result = jQuery(node).html(html);
27
+ for (_j = 0, _len1 = childNodes.length; _j < _len1; _j++) {
28
+ child = childNodes[_j];
29
+ Batman.DOM.didRemoveNode(child);
30
+ }
31
+ return result;
32
+ },
33
+ removeNode: function(node) {
34
+ var _ref;
35
+ Batman.DOM.willRemoveNode(node);
36
+ if ((_ref = node.parentNode) != null) {
37
+ _ref.removeChild(node);
38
+ }
39
+ return Batman.DOM.didRemoveNode(node);
40
+ },
41
+ destroyNode: function(node) {
42
+ Batman.DOM.willDestroyNode(node);
43
+ Batman.DOM.willRemoveNode(node);
44
+ jQuery(node).remove();
45
+ Batman.DOM.didRemoveNode(node);
46
+ return Batman.DOM.didDestroyNode(node);
47
+ },
48
+ appendChild: function(parent, child) {
49
+ Batman.DOM.willInsertNode(child);
50
+ jQuery(parent).append(child);
51
+ return Batman.DOM.didInsertNode(child);
52
+ }
53
+ });
54
+
3
55
  Batman.Request.prototype._parseResponseHeaders = function(xhr) {
4
56
  var headers;
5
57
  return headers = xhr.getAllResponseHeaders().split('\n').reduce(function(acc, header) {
@@ -12,7 +12,7 @@
12
12
  })(Batman.Object, mixins, function(){});
13
13
  };
14
14
 
15
- Batman.version = '0.10.0';
15
+ Batman.version = '0.13.0';
16
16
 
17
17
  Batman.config = {
18
18
  pathPrefix: '/',
@@ -2269,20 +2269,6 @@
2269
2269
  var _ref;
2270
2270
  return (_ref = document.getElementById(elementID)) != null ? typeof _ref.scrollIntoView === "function" ? _ref.scrollIntoView() : void 0 : void 0;
2271
2271
  },
2272
- querySelectorAll: (typeof window !== "undefined" && window !== null ? window.jQuery : void 0) != null ? function(node, selector) {
2273
- return jQuery(selector, node);
2274
- } : (typeof document !== "undefined" && document !== null ? document.querySelectorAll : void 0) != null ? function(node, selector) {
2275
- return node.querySelectorAll(selector);
2276
- } : function() {
2277
- return Batman.developer.error("Please include either jQuery or a querySelectorAll polyfill, or set Batman.DOM.querySelectorAll to return an empty array.");
2278
- },
2279
- querySelector: (typeof window !== "undefined" && window !== null ? window.jQuery : void 0) != null ? function(node, selector) {
2280
- return jQuery(selector, node)[0];
2281
- } : (typeof document !== "undefined" && document !== null ? document.querySelector : void 0) != null ? function(node, selector) {
2282
- return node.querySelector(selector);
2283
- } : function() {
2284
- return Batman.developer.error("Please include either jQuery or a querySelector polyfill, or set Batman.DOM.querySelector to an empty function.");
2285
- },
2286
2272
  partial: function(container, path, context, renderer) {
2287
2273
  var view;
2288
2274
  renderer.prevent('rendered');
@@ -2291,12 +2277,12 @@
2291
2277
  context: context
2292
2278
  });
2293
2279
  return view.on('ready', function() {
2294
- Batman.setInnerHTML(container, '');
2295
- Batman.appendChild(container, view.get('node'));
2280
+ Batman.DOM.setInnerHTML(container, '');
2281
+ Batman.DOM.appendChild(container, view.get('node'));
2296
2282
  return renderer.allowAndFire('rendered');
2297
2283
  });
2298
2284
  },
2299
- propagateBindingEvent: Batman.propagateBindingEvent = function(binding, node) {
2285
+ propagateBindingEvent: function(binding, node) {
2300
2286
  var current, parentBinding, parentBindings, _i, _len;
2301
2287
  while ((current = (current || node).parentNode)) {
2302
2288
  parentBindings = Batman._data(current, 'bindings');
@@ -2310,21 +2296,21 @@
2310
2296
  }
2311
2297
  }
2312
2298
  },
2313
- propagateBindingEvents: Batman.propagateBindingEvents = function(newNode) {
2299
+ propagateBindingEvents: function(newNode) {
2314
2300
  var binding, bindings, child, _i, _j, _len, _len1, _ref;
2315
2301
  _ref = newNode.childNodes;
2316
2302
  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
2317
2303
  child = _ref[_i];
2318
- Batman.propagateBindingEvents(child);
2304
+ Batman.DOM.propagateBindingEvents(child);
2319
2305
  }
2320
2306
  if (bindings = Batman._data(newNode, 'bindings')) {
2321
2307
  for (_j = 0, _len1 = bindings.length; _j < _len1; _j++) {
2322
2308
  binding = bindings[_j];
2323
- Batman.propagateBindingEvent(binding, newNode);
2309
+ Batman.DOM.propagateBindingEvent(binding, newNode);
2324
2310
  }
2325
2311
  }
2326
2312
  },
2327
- trackBinding: Batman.trackBinding = function(binding, node) {
2313
+ trackBinding: function(binding, node) {
2328
2314
  var bindings;
2329
2315
  if (bindings = Batman._data(node, 'bindings')) {
2330
2316
  bindings.push(binding);
@@ -2332,10 +2318,10 @@
2332
2318
  Batman._data(node, 'bindings', [binding]);
2333
2319
  }
2334
2320
  Batman.DOM.fire('bindingAdded', binding);
2335
- Batman.propagateBindingEvent(binding, node);
2321
+ Batman.DOM.propagateBindingEvent(binding, node);
2336
2322
  return true;
2337
2323
  },
2338
- onParseExit: Batman.onParseExit = function(node, callback) {
2324
+ onParseExit: function(node, callback) {
2339
2325
  var set;
2340
2326
  set = Batman._data(node, 'onParseExit') || Batman._data(node, 'onParseExit', new Batman.SimpleSet);
2341
2327
  if (callback != null) {
@@ -2343,7 +2329,7 @@
2343
2329
  }
2344
2330
  return set;
2345
2331
  },
2346
- forgetParseExit: Batman.forgetParseExit = function(node, callback) {
2332
+ forgetParseExit: function(node, callback) {
2347
2333
  return Batman.removeData(node, 'onParseExit', true);
2348
2334
  },
2349
2335
  defineView: function(name, node) {
@@ -2352,55 +2338,14 @@
2352
2338
  Batman.View.store.set(Batman.Navigator.normalizePath(name), contents);
2353
2339
  return contents;
2354
2340
  },
2355
- setInnerHTML: Batman.setInnerHTML = function(node, html) {
2356
- var child, childNodes, result, _i, _j, _len, _len1;
2357
- childNodes = (function() {
2358
- var _i, _len, _ref, _results;
2359
- _ref = node.childNodes;
2360
- _results = [];
2361
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
2362
- child = _ref[_i];
2363
- _results.push(child);
2364
- }
2365
- return _results;
2366
- })();
2367
- for (_i = 0, _len = childNodes.length; _i < _len; _i++) {
2368
- child = childNodes[_i];
2369
- Batman.DOM.willRemoveNode(child);
2370
- }
2371
- result = node.innerHTML = html;
2372
- for (_j = 0, _len1 = childNodes.length; _j < _len1; _j++) {
2373
- child = childNodes[_j];
2374
- Batman.DOM.didRemoveNode(child);
2375
- }
2376
- return result;
2377
- },
2378
- setStyleProperty: Batman.setStyleProperty = function(node, property, value, importance) {
2341
+ setStyleProperty: function(node, property, value, importance) {
2379
2342
  if (node.style.setAttribute) {
2380
2343
  return node.style.setAttribute(property, value, importance);
2381
2344
  } else {
2382
2345
  return node.style.setProperty(property, value, importance);
2383
2346
  }
2384
2347
  },
2385
- removeNode: Batman.removeNode = function(node) {
2386
- var _ref;
2387
- Batman.DOM.willRemoveNode(node);
2388
- if ((_ref = node.parentNode) != null) {
2389
- _ref.removeChild(node);
2390
- }
2391
- return Batman.DOM.didRemoveNode(node);
2392
- },
2393
- destroyNode: Batman.destroyNode = function(node) {
2394
- Batman.DOM.willDestroyNode(node);
2395
- Batman.removeNode(node);
2396
- return Batman.DOM.didDestroyNode(node);
2397
- },
2398
- appendChild: Batman.appendChild = function(parent, child) {
2399
- Batman.DOM.willInsertNode(child);
2400
- parent.appendChild(child);
2401
- return Batman.DOM.didInsertNode(child);
2402
- },
2403
- removeOrDestroyNode: Batman.removeOrDestroyNode = function(node) {
2348
+ removeOrDestroyNode: function(node) {
2404
2349
  var view;
2405
2350
  view = Batman._data(node, 'view');
2406
2351
  view || (view = Batman._data(node, 'yielder'));
@@ -2410,12 +2355,12 @@
2410
2355
  return Batman.DOM.destroyNode(node);
2411
2356
  }
2412
2357
  },
2413
- insertBefore: Batman.insertBefore = function(parentNode, newNode, referenceNode) {
2358
+ insertBefore: function(parentNode, newNode, referenceNode) {
2414
2359
  if (referenceNode == null) {
2415
2360
  referenceNode = null;
2416
2361
  }
2417
2362
  if (!referenceNode || parentNode.childNodes.length <= 0) {
2418
- return Batman.appendChild(parentNode, newNode);
2363
+ return Batman.DOM.appendChild(parentNode, newNode);
2419
2364
  } else {
2420
2365
  Batman.DOM.willInsertNode(newNode);
2421
2366
  parentNode.insertBefore(newNode, referenceNode);
@@ -2447,7 +2392,7 @@
2447
2392
  break;
2448
2393
  default:
2449
2394
  if (isSetting) {
2450
- return Batman.setInnerHTML(node, escapeValue ? Batman.escapeHTML(value) : value);
2395
+ return Batman.DOM.setInnerHTML(node, escapeValue ? Batman.escapeHTML(value) : value);
2451
2396
  } else {
2452
2397
  return node.innerHTML;
2453
2398
  }
@@ -2457,7 +2402,7 @@
2457
2402
  var _ref;
2458
2403
  return (_ref = node.nodeName.toUpperCase()) === 'INPUT' || _ref === 'TEXTAREA' || _ref === 'SELECT';
2459
2404
  },
2460
- addEventListener: Batman.addEventListener = function(node, eventName, callback) {
2405
+ addEventListener: function(node, eventName, callback) {
2461
2406
  var listeners;
2462
2407
  if (!(listeners = Batman._data(node, 'listeners'))) {
2463
2408
  listeners = Batman._data(node, 'listeners', {});
@@ -2466,13 +2411,13 @@
2466
2411
  listeners[eventName] = [];
2467
2412
  }
2468
2413
  listeners[eventName].push(callback);
2469
- if (Batman.hasAddEventListener) {
2414
+ if (Batman.DOM.hasAddEventListener) {
2470
2415
  return node.addEventListener(eventName, callback, false);
2471
2416
  } else {
2472
2417
  return node.attachEvent("on" + eventName, callback);
2473
2418
  }
2474
2419
  },
2475
- removeEventListener: Batman.removeEventListener = function(node, eventName, callback) {
2420
+ removeEventListener: function(node, eventName, callback) {
2476
2421
  var eventListeners, index, listeners;
2477
2422
  if (listeners = Batman._data(node, 'listeners')) {
2478
2423
  if (eventListeners = listeners[eventName]) {
@@ -2482,21 +2427,21 @@
2482
2427
  }
2483
2428
  }
2484
2429
  }
2485
- if (Batman.hasAddEventListener) {
2430
+ if (Batman.DOM.hasAddEventListener) {
2486
2431
  return node.removeEventListener(eventName, callback, false);
2487
2432
  } else {
2488
2433
  return node.detachEvent('on' + eventName, callback);
2489
2434
  }
2490
2435
  },
2491
- hasAddEventListener: Batman.hasAddEventListener = !!(typeof window !== "undefined" && window !== null ? window.addEventListener : void 0),
2492
- preventDefault: Batman.preventDefault = function(e) {
2436
+ hasAddEventListener: !!(typeof window !== "undefined" && window !== null ? window.addEventListener : void 0),
2437
+ preventDefault: function(e) {
2493
2438
  if (typeof e.preventDefault === "function") {
2494
2439
  return e.preventDefault();
2495
2440
  } else {
2496
2441
  return e.returnValue = false;
2497
2442
  }
2498
2443
  },
2499
- stopPropagation: Batman.stopPropagation = function(e) {
2444
+ stopPropagation: function(e) {
2500
2445
  if (e.stopPropagation) {
2501
2446
  return e.stopPropagation();
2502
2447
  } else {
@@ -2609,7 +2554,7 @@
2609
2554
  for (eventName in listeners) {
2610
2555
  eventListeners = listeners[eventName];
2611
2556
  eventListeners.forEach(function(listener) {
2612
- return Batman.removeEventListener(node, eventName, listener);
2557
+ return Batman.DOM.removeEventListener(node, eventName, listener);
2613
2558
  });
2614
2559
  }
2615
2560
  }
@@ -2713,7 +2658,7 @@
2713
2658
  return true;
2714
2659
  },
2715
2660
  defineview: function(node, name, context, renderer) {
2716
- Batman.onParseExit(node, function() {
2661
+ Batman.DOM.onParseExit(node, function() {
2717
2662
  var _ref;
2718
2663
  return (_ref = node.parentNode) != null ? _ref.removeChild(node) : void 0;
2719
2664
  });
@@ -2725,7 +2670,7 @@
2725
2670
  return false;
2726
2671
  },
2727
2672
  "yield": function(node, key) {
2728
- Batman.onParseExit(node, function() {
2673
+ Batman.DOM.onParseExit(node, function() {
2729
2674
  return Batman.DOM.Yield.withName(key).set('containerNode', node);
2730
2675
  });
2731
2676
  return true;
@@ -2734,7 +2679,7 @@
2734
2679
  if (action == null) {
2735
2680
  action = 'append';
2736
2681
  }
2737
- Batman.onParseExit(node, function() {
2682
+ Batman.DOM.onParseExit(node, function() {
2738
2683
  var _ref;
2739
2684
  if ((_ref = node.parentNode) != null) {
2740
2685
  _ref.removeChild(node);
@@ -2760,11 +2705,14 @@
2760
2705
  if (eventName == null) {
2761
2706
  eventName = 'click';
2762
2707
  }
2763
- Batman.addEventListener(node, eventName, function() {
2764
- var args;
2765
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
2766
- callback.apply(null, [node].concat(__slice.call(args), [context]));
2767
- return Batman.preventDefault(args[0]);
2708
+ Batman.DOM.addEventListener(node, eventName, function() {
2709
+ var args, event;
2710
+ event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
2711
+ if (event.metaKey || event.ctrlKey) {
2712
+ return;
2713
+ }
2714
+ callback.apply(null, [node, event].concat(__slice.call(args), [context]));
2715
+ return Batman.DOM.preventDefault(event);
2768
2716
  });
2769
2717
  if (node.nodeName.toUpperCase() === 'A' && !node.href) {
2770
2718
  node.href = '#';
@@ -2802,7 +2750,7 @@
2802
2750
  _results = [];
2803
2751
  for (_i = 0, _len = eventNames.length; _i < _len; _i++) {
2804
2752
  eventName = eventNames[_i];
2805
- _results.push(Batman.addEventListener(node, eventName, function() {
2753
+ _results.push(Batman.DOM.addEventListener(node, eventName, function() {
2806
2754
  var args;
2807
2755
  args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
2808
2756
  return callback.apply(null, [node].concat(__slice.call(args), [context]));
@@ -2816,36 +2764,36 @@
2816
2764
  },
2817
2765
  submit: function(node, callback, context) {
2818
2766
  if (Batman.DOM.nodeIsEditable(node)) {
2819
- Batman.addEventListener(node, 'keydown', function() {
2767
+ Batman.DOM.addEventListener(node, 'keydown', function() {
2820
2768
  var args;
2821
2769
  args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
2822
2770
  if (Batman.DOM.events.isEnter(args[0])) {
2823
2771
  return Batman.DOM._keyCapturingNode = node;
2824
2772
  }
2825
2773
  });
2826
- Batman.addEventListener(node, 'keyup', function() {
2774
+ Batman.DOM.addEventListener(node, 'keyup', function() {
2827
2775
  var args;
2828
2776
  args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
2829
2777
  if (Batman.DOM.events.isEnter(args[0])) {
2830
2778
  if (Batman.DOM._keyCapturingNode === node) {
2831
- Batman.preventDefault(args[0]);
2779
+ Batman.DOM.preventDefault(args[0]);
2832
2780
  callback.apply(null, [node].concat(__slice.call(args), [context]));
2833
2781
  }
2834
2782
  return Batman.DOM._keyCapturingNode = null;
2835
2783
  }
2836
2784
  });
2837
2785
  } else {
2838
- Batman.addEventListener(node, 'submit', function() {
2786
+ Batman.DOM.addEventListener(node, 'submit', function() {
2839
2787
  var args;
2840
2788
  args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
2841
- Batman.preventDefault(args[0]);
2789
+ Batman.DOM.preventDefault(args[0]);
2842
2790
  return callback.apply(null, [node].concat(__slice.call(args), [context]));
2843
2791
  });
2844
2792
  }
2845
2793
  return node;
2846
2794
  },
2847
2795
  other: function(node, eventName, callback, context) {
2848
- return Batman.addEventListener(node, eventName, function() {
2796
+ return Batman.DOM.addEventListener(node, eventName, function() {
2849
2797
  var args;
2850
2798
  args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
2851
2799
  return callback.apply(null, [node].concat(__slice.call(args), [context]));
@@ -3016,25 +2964,31 @@
3016
2964
  };
3017
2965
 
3018
2966
  promiseWrapper = function(fetcher) {
3019
- return function(core) {
2967
+ return function(defaultAccessor) {
3020
2968
  return {
3021
2969
  get: function(key) {
3022
- var deliver, returned, val,
2970
+ var asyncDeliver, existingValue, newValue, _base, _name, _ref,
3023
2971
  _this = this;
3024
- val = core.get.apply(this, arguments);
3025
- if (typeof val !== 'undefined') {
3026
- return val;
2972
+ if ((existingValue = defaultAccessor.get.apply(this, arguments)) != null) {
2973
+ return existingValue;
3027
2974
  }
3028
- returned = false;
3029
- deliver = function(err, result) {
3030
- if (returned) {
3031
- _this.set(key, result);
3032
- }
3033
- return val = result;
3034
- };
3035
- fetcher.call(this, deliver, key);
3036
- returned = true;
3037
- return val;
2975
+ asyncDeliver = false;
2976
+ newValue = void 0;
2977
+ if ((_ref = (_base = this._batman)[_name = "promise" + key + "Fetched"]) == null) {
2978
+ _base[_name] = (function() {
2979
+ var deliver;
2980
+ deliver = function(err, result) {
2981
+ if (asyncDeliver) {
2982
+ _this.set(key, result);
2983
+ }
2984
+ return newValue = result;
2985
+ };
2986
+ fetcher.call(_this, deliver, key);
2987
+ return true;
2988
+ })();
2989
+ }
2990
+ asyncDeliver = true;
2991
+ return newValue;
3038
2992
  },
3039
2993
  cache: true
3040
2994
  };
@@ -3272,7 +3226,7 @@
3272
3226
  } else if (result instanceof Batman.RenderContext) {
3273
3227
  oldContext = this.context;
3274
3228
  this.context = result;
3275
- Batman.onParseExit(node, function() {
3229
+ Batman.DOM.onParseExit(node, function() {
3276
3230
  return _this.context = oldContext;
3277
3231
  });
3278
3232
  }
@@ -3294,12 +3248,12 @@
3294
3248
  }
3295
3249
  }
3296
3250
  sibling = node.nextSibling;
3297
- if ((_ref1 = Batman.onParseExit(node)) != null) {
3251
+ if ((_ref1 = Batman.DOM.onParseExit(node)) != null) {
3298
3252
  _ref1.forEach(function(callback) {
3299
3253
  return callback();
3300
3254
  });
3301
3255
  }
3302
- Batman.forgetParseExit(node);
3256
+ Batman.DOM.forgetParseExit(node);
3303
3257
  if (this.node === node) {
3304
3258
  return;
3305
3259
  }
@@ -3309,12 +3263,12 @@
3309
3263
  nextParent = node;
3310
3264
  while (nextParent = nextParent.parentNode) {
3311
3265
  parentSibling = nextParent.nextSibling;
3312
- if ((_ref2 = Batman.onParseExit(nextParent)) != null) {
3266
+ if ((_ref2 = Batman.DOM.onParseExit(nextParent)) != null) {
3313
3267
  _ref2.forEach(function(callback) {
3314
3268
  return callback();
3315
3269
  });
3316
3270
  }
3317
- Batman.forgetParseExit(nextParent);
3271
+ Batman.DOM.forgetParseExit(nextParent);
3318
3272
  if (this.node === nextParent) {
3319
3273
  return;
3320
3274
  }
@@ -3643,7 +3597,7 @@
3643
3597
  if (typeof (hide = Batman.data(this.node, 'hide')) === 'function') {
3644
3598
  hide.call(this.node);
3645
3599
  } else {
3646
- Batman.setStyleProperty(this.node, 'display', 'none', 'important');
3600
+ Batman.DOM.setStyleProperty(this.node, 'display', 'none', 'important');
3647
3601
  }
3648
3602
  return view != null ? view.fire('disappear', this.node) : void 0;
3649
3603
  }
@@ -4054,7 +4008,7 @@
4054
4008
  this.contextName = contextName;
4055
4009
  delete this.attributeName;
4056
4010
  Batman.DOM.events.submit(this.get('node'), function(node, e) {
4057
- return Batman.preventDefault(e);
4011
+ return Batman.DOM.preventDefault(e);
4058
4012
  });
4059
4013
  this.setupErrorsList();
4060
4014
  }
@@ -4072,7 +4026,7 @@
4072
4026
 
4073
4027
  FormBinding.prototype.setupErrorsList = function() {
4074
4028
  if (this.errorsListNode = Batman.DOM.querySelector(this.get('node'), this.get('errorsListSelector'))) {
4075
- Batman.setInnerHTML(this.errorsListNode, this.errorsListHTML());
4029
+ Batman.DOM.setInnerHTML(this.errorsListNode, this.errorsListHTML());
4076
4030
  if (!this.errorsListNode.getAttribute('data-showif')) {
4077
4031
  return this.errorsListNode.setAttribute('data-showif', "" + this.contextName + ".errors.length");
4078
4032
  }
@@ -4139,8 +4093,8 @@
4139
4093
  if (keys.length > 1) {
4140
4094
  functionKey = keys.pop();
4141
4095
  keyContext = Batman.getPath(this, ['keyContext'].concat(keys));
4096
+ keyContext = Batman.RenderContext.deProxy(keyContext);
4142
4097
  if (keyContext != null) {
4143
- keyContext = Batman.RenderContext.deProxy(keyContext);
4144
4098
  return keyContext[functionKey];
4145
4099
  }
4146
4100
  }
@@ -4513,11 +4467,11 @@
4513
4467
  if (Batman.canDeleteExpando) {
4514
4468
  delete sourceNode[Batman.expando];
4515
4469
  }
4516
- Batman.insertBefore(sourceNode.parentNode, this.startNode, previousSiblingNode);
4517
- Batman.insertBefore(sourceNode.parentNode, this.endNode, previousSiblingNode);
4470
+ Batman.DOM.insertBefore(sourceNode.parentNode, this.startNode, previousSiblingNode);
4471
+ Batman.DOM.insertBefore(sourceNode.parentNode, this.endNode, previousSiblingNode);
4518
4472
  this.parentRenderer.prevent('rendered');
4519
4473
  Batman.DOM.onParseExit(sourceNode.parentNode, function() {
4520
- Batman.destroyNode(sourceNode);
4474
+ Batman.DOM.destroyNode(sourceNode);
4521
4475
  _this.bind();
4522
4476
  return _this.parentRenderer.allowAndFire('rendered');
4523
4477
  });
@@ -4553,15 +4507,17 @@
4553
4507
  parentNode = this.parentNode();
4554
4508
  startIndex = this._getStartNodeIndex() + 1;
4555
4509
  unseenNodeMap = this.nodeMap.merge();
4556
- for (index = _i = 0, _len = newItems.length; _i < _len; index = ++_i) {
4557
- newItem = newItems[index];
4558
- nodeAtIndex = parentNode.childNodes[startIndex + index];
4559
- if ((nodeAtIndex != null) && this._itemForNode(nodeAtIndex) === newItem) {
4560
- unseenNodeMap.unset(newItem);
4561
- continue;
4562
- } else {
4563
- node = (existingNode = this.nodeMap.get(newItem)) ? (unseenNodeMap.unset(newItem), existingNode) : this._newNodeForItem(newItem);
4564
- Batman.insertBefore(this.parentNode(), node, nodeAtIndex);
4510
+ if (newItems != null) {
4511
+ for (index = _i = 0, _len = newItems.length; _i < _len; index = ++_i) {
4512
+ newItem = newItems[index];
4513
+ nodeAtIndex = parentNode.childNodes[startIndex + index];
4514
+ if ((nodeAtIndex != null) && this._itemForNode(nodeAtIndex) === newItem) {
4515
+ unseenNodeMap.unset(newItem);
4516
+ continue;
4517
+ } else {
4518
+ node = (existingNode = this.nodeMap.get(newItem)) ? (unseenNodeMap.unset(newItem), existingNode) : this._newNodeForItem(newItem);
4519
+ Batman.DOM.insertBefore(this.parentNode(), node, nodeAtIndex);
4520
+ }
4565
4521
  }
4566
4522
  }
4567
4523
  unseenNodeMap.forEach(function(item, node) {
@@ -4582,7 +4538,7 @@
4582
4538
  this.parentRenderer.prevent('rendered');
4583
4539
  renderer = new Batman.Renderer(newNode, this.renderContext.descend(newItem, this.iteratorName), this.parentRenderer.view);
4584
4540
  renderer.on('rendered', function() {
4585
- Batman.propagateBindingEvents(newNode);
4541
+ Batman.DOM.propagateBindingEvents(newNode);
4586
4542
  _this.fire('nodeAdded', newNode, newItem);
4587
4543
  return _this.parentRenderer.allowAndFire('rendered');
4588
4544
  });
@@ -4604,7 +4560,7 @@
4604
4560
  IteratorBinding.prototype._removeItem = function(item) {
4605
4561
  var node;
4606
4562
  node = this.nodeMap.unset(item);
4607
- Batman.destroyNode(node);
4563
+ Batman.DOM.destroyNode(node);
4608
4564
  return this.fire('nodeRemoved', node, item);
4609
4565
  };
4610
4566
 
@@ -4753,6 +4709,76 @@
4753
4709
 
4754
4710
  })(StorageAdapter.StorageError);
4755
4711
 
4712
+ StorageAdapter.NotAllowedError = (function(_super1) {
4713
+
4714
+ __extends(NotAllowedError, _super1);
4715
+
4716
+ NotAllowedError.prototype.name = "NotAllowedError";
4717
+
4718
+ function NotAllowedError(message) {
4719
+ NotAllowedError.__super__.constructor.call(this, message || "Storage operation denied access to the operation!");
4720
+ }
4721
+
4722
+ return NotAllowedError;
4723
+
4724
+ })(StorageAdapter.StorageError);
4725
+
4726
+ StorageAdapter.NotAcceptableError = (function(_super1) {
4727
+
4728
+ __extends(NotAcceptableError, _super1);
4729
+
4730
+ NotAcceptableError.prototype.name = "NotAcceptableError";
4731
+
4732
+ function NotAcceptableError(message) {
4733
+ NotAcceptableError.__super__.constructor.call(this, message || "Storage operation permitted but the request was malformed!");
4734
+ }
4735
+
4736
+ return NotAcceptableError;
4737
+
4738
+ })(StorageAdapter.StorageError);
4739
+
4740
+ StorageAdapter.UnprocessableRecordError = (function(_super1) {
4741
+
4742
+ __extends(UnprocessableRecordError, _super1);
4743
+
4744
+ UnprocessableRecordError.prototype.name = "UnprocessableRecordError";
4745
+
4746
+ function UnprocessableRecordError(message) {
4747
+ UnprocessableRecordError.__super__.constructor.call(this, message || "Storage adapter could not process the record!");
4748
+ }
4749
+
4750
+ return UnprocessableRecordError;
4751
+
4752
+ })(StorageAdapter.StorageError);
4753
+
4754
+ StorageAdapter.InternalStorageError = (function(_super1) {
4755
+
4756
+ __extends(InternalStorageError, _super1);
4757
+
4758
+ InternalStorageError.prototype.name = "InternalStorageError";
4759
+
4760
+ function InternalStorageError(message) {
4761
+ InternalStorageError.__super__.constructor.call(this, message || "An error occured during the storage operation!");
4762
+ }
4763
+
4764
+ return InternalStorageError;
4765
+
4766
+ })(StorageAdapter.StorageError);
4767
+
4768
+ StorageAdapter.NotImplementedError = (function(_super1) {
4769
+
4770
+ __extends(NotImplementedError, _super1);
4771
+
4772
+ NotImplementedError.prototype.name = "NotImplementedError";
4773
+
4774
+ function NotImplementedError(message) {
4775
+ NotImplementedError.__super__.constructor.call(this, message || "This operation is not implemented by the storage adpater!");
4776
+ }
4777
+
4778
+ return NotImplementedError;
4779
+
4780
+ })(StorageAdapter.StorageError);
4781
+
4756
4782
  function StorageAdapter(model) {
4757
4783
  var constructor;
4758
4784
  StorageAdapter.__super__.constructor.call(this, {
@@ -4921,6 +4947,20 @@
4921
4947
 
4922
4948
  __extends(RestStorage, _super);
4923
4949
 
4950
+ RestStorage.CommunicationError = (function(_super1) {
4951
+
4952
+ __extends(CommunicationError, _super1);
4953
+
4954
+ CommunicationError.prototype.name = 'CommunicationError';
4955
+
4956
+ function CommunicationError(message) {
4957
+ CommunicationError.__super__.constructor.call(this, message || "A communication error has occurred!");
4958
+ }
4959
+
4960
+ return CommunicationError;
4961
+
4962
+ })(RestStorage.StorageError);
4963
+
4924
4964
  RestStorage.JSONContentType = 'application/json';
4925
4965
 
4926
4966
  RestStorage.PostBodyContentType = 'application/x-www-form-urlencoded';
@@ -5230,6 +5270,37 @@
5230
5270
  _fn(key);
5231
5271
  }
5232
5272
 
5273
+ RestStorage.prototype.after('all', function(env, next) {
5274
+ if (env.error) {
5275
+ env.error = this._errorFor(env.error, env);
5276
+ }
5277
+ return next();
5278
+ });
5279
+
5280
+ RestStorage._statusCodeErrors = {
5281
+ '0': RestStorage.CommunicationError,
5282
+ '403': RestStorage.NotAllowedError,
5283
+ '404': RestStorage.NotFoundError,
5284
+ '406': RestStorage.NotAcceptableError,
5285
+ '422': RestStorage.UnprocessableRecordError,
5286
+ '500': RestStorage.InternalStorageError,
5287
+ '501': RestStorage.NotImplementedError
5288
+ };
5289
+
5290
+ RestStorage.prototype._errorFor = function(error, env) {
5291
+ var errorClass, request;
5292
+ if (error instanceof Error || !(error.request != null)) {
5293
+ return error;
5294
+ }
5295
+ if (errorClass = this.constructor._statusCodeErrors[error.request.status]) {
5296
+ request = error.request;
5297
+ error = new errorClass;
5298
+ error.request = request;
5299
+ error.env = env;
5300
+ }
5301
+ return error;
5302
+ };
5303
+
5233
5304
  return RestStorage;
5234
5305
 
5235
5306
  }).call(this, Batman.StorageAdapter);
@@ -5835,6 +5906,7 @@
5835
5906
  }
5836
5907
  pattern = templatePath.replace(regexps.escapeRegExp, '\\$&');
5837
5908
  regexp = RegExp("^" + (pattern.replace(regexps.openOptParam, '(?:').replace(regexps.closeOptParam, ')?').replace(regexps.namedParam, '([^\/]+)').replace(regexps.splatParam, '(.*?)')) + regexps.queryParam + "$");
5909
+ regexps.namedOrSplat.lastIndex = 0;
5838
5910
  namedArguments = ((function() {
5839
5911
  var _results;
5840
5912
  _results = [];
@@ -6312,6 +6384,7 @@
6312
6384
  var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
6313
6385
  __hasProp = {}.hasOwnProperty,
6314
6386
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
6387
+ __slice = [].slice,
6315
6388
  __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
6316
6389
 
6317
6390
  Batman.Controller = (function(_super) {
@@ -6384,8 +6457,71 @@
6384
6457
  }
6385
6458
  });
6386
6459
 
6460
+ Controller.catchError = function() {
6461
+ var currentHandlers, error, errors, handlers, options, _base, _i, _j, _len, _results;
6462
+ errors = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), options = arguments[_i++];
6463
+ Batman.initializeObject(this);
6464
+ (_base = this._batman).errorHandlers || (_base.errorHandlers = new Batman.SimpleHash);
6465
+ handlers = Batman.typeOf(options["with"]) === 'Array' ? options["with"] : [options["with"]];
6466
+ _results = [];
6467
+ for (_j = 0, _len = errors.length; _j < _len; _j++) {
6468
+ error = errors[_j];
6469
+ currentHandlers = this._batman.errorHandlers.get(error) || [];
6470
+ _results.push(this._batman.errorHandlers.set(error, currentHandlers.concat(handlers)));
6471
+ }
6472
+ return _results;
6473
+ };
6474
+
6475
+ Controller.prototype.errorHandler = function(callback) {
6476
+ var errorFrame, _ref,
6477
+ _this = this;
6478
+ errorFrame = (_ref = this._actionFrames) != null ? _ref[this._actionFrames.length - 1] : void 0;
6479
+ return function(err, result, env) {
6480
+ if (err) {
6481
+ if (errorFrame != null ? errorFrame.error : void 0) {
6482
+ return;
6483
+ }
6484
+ if (errorFrame != null) {
6485
+ errorFrame.error = err;
6486
+ }
6487
+ if (!_this.handleError(err)) {
6488
+ throw err;
6489
+ }
6490
+ } else {
6491
+ return typeof callback === "function" ? callback(result, env) : void 0;
6492
+ }
6493
+ };
6494
+ };
6495
+
6496
+ Controller.prototype.handleError = function(error) {
6497
+ var handled, _ref,
6498
+ _this = this;
6499
+ handled = false;
6500
+ if ((_ref = this.constructor._batman.getAll('errorHandlers')) != null) {
6501
+ _ref.forEach(function(hash) {
6502
+ return hash.forEach(function(key, value) {
6503
+ var handler, _i, _len, _results;
6504
+ if (error instanceof key) {
6505
+ handled = true;
6506
+ _results = [];
6507
+ for (_i = 0, _len = value.length; _i < _len; _i++) {
6508
+ handler = value[_i];
6509
+ _results.push(handler.call(_this, error));
6510
+ }
6511
+ return _results;
6512
+ }
6513
+ });
6514
+ });
6515
+ }
6516
+ return handled;
6517
+ };
6518
+
6387
6519
  function Controller() {
6388
6520
  this.redirect = __bind(this.redirect, this);
6521
+
6522
+ this.handleError = __bind(this.handleError, this);
6523
+
6524
+ this.errorHandler = __bind(this.errorHandler, this);
6389
6525
  Controller.__super__.constructor.apply(this, arguments);
6390
6526
  this._resetActionFrames();
6391
6527
  }
@@ -7178,11 +7314,13 @@
7178
7314
 
7179
7315
  Model.primaryKey = 'id';
7180
7316
 
7181
- Model.persist = function(mechanism, options) {
7317
+ Model.persist = function() {
7318
+ var mechanism, options;
7319
+ mechanism = arguments[0], options = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
7182
7320
  Batman.initializeObject(this.prototype);
7183
7321
  mechanism = mechanism.isStorageAdapter ? mechanism : new mechanism(this);
7184
- if (options) {
7185
- Batman.mixin(mechanism, options);
7322
+ if (options.length > 0) {
7323
+ Batman.mixin.apply(Batman, [mechanism].concat(__slice.call(options)));
7186
7324
  }
7187
7325
  this.prototype._batman.storage = mechanism;
7188
7326
  return mechanism;
@@ -7266,38 +7404,6 @@
7266
7404
  }
7267
7405
  };
7268
7406
 
7269
- Model.LifecycleStateMachine = (function(_super1) {
7270
-
7271
- __extends(LifecycleStateMachine, _super1);
7272
-
7273
- function LifecycleStateMachine() {
7274
- return LifecycleStateMachine.__super__.constructor.apply(this, arguments);
7275
- }
7276
-
7277
- LifecycleStateMachine.transitions({
7278
- load: {
7279
- empty: 'loading',
7280
- loaded: 'loading',
7281
- loading: 'loading'
7282
- },
7283
- loaded: {
7284
- loading: 'loaded'
7285
- },
7286
- error: {
7287
- loading: 'error'
7288
- }
7289
- });
7290
-
7291
- return LifecycleStateMachine;
7292
-
7293
- })(Batman.DelegatingStateMachine);
7294
-
7295
- Model.classAccessor('lifecycle', function() {
7296
- var _base;
7297
- this._batman.check(this);
7298
- return (_base = this._batman).lifecycle || (_base.lifecycle = new this.LifecycleStateMachine('empty', this));
7299
- });
7300
-
7301
7407
  Model.classAccessor('resourceName', {
7302
7408
  get: function() {
7303
7409
  if (this.resourceName != null) {
@@ -7366,38 +7472,34 @@
7366
7472
  };
7367
7473
 
7368
7474
  Model.load = function(options, callback) {
7369
- var lifecycle, _ref,
7475
+ var _ref,
7370
7476
  _this = this;
7371
7477
  if ((_ref = typeof options) === 'function' || _ref === 'undefined') {
7372
7478
  callback = options;
7373
7479
  options = {};
7374
7480
  }
7375
- lifecycle = this.get('lifecycle');
7376
- if (lifecycle.load()) {
7377
- return this._doStorageOperation('readAll', {
7378
- data: options
7379
- }, function(err, records, env) {
7380
- var mappedRecords, record;
7381
- if (err != null) {
7382
- lifecycle.error();
7383
- return typeof callback === "function" ? callback(err, []) : void 0;
7384
- } else {
7385
- mappedRecords = (function() {
7386
- var _i, _len, _results;
7387
- _results = [];
7388
- for (_i = 0, _len = records.length; _i < _len; _i++) {
7389
- record = records[_i];
7390
- _results.push(this._mapIdentity(record));
7391
- }
7392
- return _results;
7393
- }).call(_this);
7394
- lifecycle.loaded();
7395
- return typeof callback === "function" ? callback(err, mappedRecords, env) : void 0;
7396
- }
7397
- });
7398
- } else {
7399
- return callback(new Batman.StateMachine.InvalidTransitionError("Can't load while in state " + (lifecycle.get('state'))));
7400
- }
7481
+ this.fire('loading', options);
7482
+ return this._doStorageOperation('readAll', {
7483
+ data: options
7484
+ }, function(err, records, env) {
7485
+ var mappedRecords, record;
7486
+ if (err != null) {
7487
+ _this.fire('error', err);
7488
+ return typeof callback === "function" ? callback(err, []) : void 0;
7489
+ } else {
7490
+ mappedRecords = (function() {
7491
+ var _i, _len, _results;
7492
+ _results = [];
7493
+ for (_i = 0, _len = records.length; _i < _len; _i++) {
7494
+ record = records[_i];
7495
+ _results.push(this._mapIdentity(record));
7496
+ }
7497
+ return _results;
7498
+ }).call(_this);
7499
+ _this.fire('loaded', mappedRecords, env);
7500
+ return typeof callback === "function" ? callback(err, mappedRecords, env) : void 0;
7501
+ }
7502
+ });
7401
7503
  };
7402
7504
 
7403
7505
  Model.create = function(attrs, callback) {
@@ -7561,6 +7663,10 @@
7561
7663
  return this.isNew();
7562
7664
  });
7563
7665
 
7666
+ Model.accessor('isDirty', function() {
7667
+ return this.isDirty();
7668
+ });
7669
+
7564
7670
  Model.accessor(Model.defaultAccessor = {
7565
7671
  get: function(k) {
7566
7672
  return Batman.getPath(this, ['attributes', k]);
@@ -7608,6 +7714,10 @@
7608
7714
  return typeof this.get('id') === 'undefined';
7609
7715
  };
7610
7716
 
7717
+ Model.prototype.isDirty = function() {
7718
+ return this.get('lifecycle.state') === 'dirty';
7719
+ };
7720
+
7611
7721
  Model.prototype.updateAttributes = function(attrs) {
7612
7722
  this.mixin(attrs);
7613
7723
  return this;
@@ -7990,17 +8100,27 @@
7990
8100
  var _this = this;
7991
8101
  this.fetch(function(err, proxiedRecord) {
7992
8102
  if (!err) {
7993
- _this.set('loaded', true);
7994
- _this.set('target', proxiedRecord);
8103
+ _this._setTarget(proxiedRecord);
7995
8104
  }
7996
8105
  return typeof callback === "function" ? callback(err, proxiedRecord) : void 0;
7997
8106
  });
7998
8107
  return this.get('target');
7999
8108
  };
8000
8109
 
8110
+ AssociationProxy.prototype.loadFromLocal = function() {
8111
+ var target;
8112
+ if (!this._canLoad()) {
8113
+ return;
8114
+ }
8115
+ if (target = this.fetchFromLocal()) {
8116
+ this._setTarget(target);
8117
+ }
8118
+ return target;
8119
+ };
8120
+
8001
8121
  AssociationProxy.prototype.fetch = function(callback) {
8002
8122
  var record;
8003
- if ((this.get('foreignValue') || this.get('primaryValue')) == null) {
8123
+ if (!this._canLoad()) {
8004
8124
  return callback(void 0, void 0);
8005
8125
  }
8006
8126
  record = this.fetchFromLocal();
@@ -8022,6 +8142,16 @@
8022
8142
  }
8023
8143
  });
8024
8144
 
8145
+ AssociationProxy.prototype._canLoad = function() {
8146
+ return (this.get('foreignValue') || this.get('primaryValue')) != null;
8147
+ };
8148
+
8149
+ AssociationProxy.prototype._setTarget = function(target) {
8150
+ this.set('target', target);
8151
+ this.set('loaded', true);
8152
+ return this.fire('loaded', target);
8153
+ };
8154
+
8025
8155
  return AssociationProxy;
8026
8156
 
8027
8157
  })(Batman.Proxy);
@@ -8408,6 +8538,9 @@
8408
8538
  if (first == null) {
8409
8539
  first = false;
8410
8540
  }
8541
+ if (object instanceof Batman.container.File) {
8542
+ return [[key, object]];
8543
+ }
8411
8544
  return list = (function() {
8412
8545
  switch (Batman.typeOf(object)) {
8413
8546
  case 'Object':
@@ -9016,14 +9149,27 @@
9016
9149
  }
9017
9150
 
9018
9151
  AssociationSetIndex.prototype._resultSetForKey = function(key) {
9152
+ return this.association.setForKey(key);
9153
+ };
9154
+
9155
+ AssociationSetIndex.prototype.forEach = function(iterator, ctx) {
9019
9156
  var _this = this;
9020
- return this._storage.getOrSet(key, function() {
9021
- return new _this.association.proxyClass(key, _this.association);
9157
+ return this.association.proxies.forEach(function(record, set) {
9158
+ var key;
9159
+ key = _this.association.indexValueForRecord(record);
9160
+ if (set.get('length') > 0) {
9161
+ return iterator.call(ctx, key, set, _this);
9162
+ }
9022
9163
  });
9023
9164
  };
9024
9165
 
9025
- AssociationSetIndex.prototype._setResultSet = function(key, set) {
9026
- return this._storage.set(key, set);
9166
+ AssociationSetIndex.prototype.toArray = function() {
9167
+ var results;
9168
+ results = [];
9169
+ this.forEach(function(key) {
9170
+ return results.push(key);
9171
+ });
9172
+ return results;
9027
9173
  };
9028
9174
 
9029
9175
  return AssociationSetIndex;
@@ -9250,11 +9396,11 @@
9250
9396
  };
9251
9397
 
9252
9398
  PushStateNavigator.prototype.startWatching = function() {
9253
- return Batman.addEventListener(window, 'popstate', this.handleCurrentLocation);
9399
+ return Batman.DOM.addEventListener(window, 'popstate', this.handleCurrentLocation);
9254
9400
  };
9255
9401
 
9256
9402
  PushStateNavigator.prototype.stopWatching = function() {
9257
- return Batman.removeEventListener(window, 'popstate', this.handleCurrentLocation);
9403
+ return Batman.DOM.removeEventListener(window, 'popstate', this.handleCurrentLocation);
9258
9404
  };
9259
9405
 
9260
9406
  PushStateNavigator.prototype.pushState = function(stateObject, title, path) {
@@ -9308,10 +9454,10 @@
9308
9454
 
9309
9455
  if ((typeof window !== "undefined" && window !== null) && 'onhashchange' in window) {
9310
9456
  HashbangNavigator.prototype.startWatching = function() {
9311
- return Batman.addEventListener(window, 'hashchange', this.handleCurrentLocation);
9457
+ return Batman.DOM.addEventListener(window, 'hashchange', this.handleCurrentLocation);
9312
9458
  };
9313
9459
  HashbangNavigator.prototype.stopWatching = function() {
9314
- return Batman.removeEventListener(window, 'hashchange', this.handleCurrentLocation);
9460
+ return Batman.DOM.removeEventListener(window, 'hashchange', this.handleCurrentLocation);
9315
9461
  };
9316
9462
  } else {
9317
9463
  HashbangNavigator.prototype.startWatching = function() {
@@ -9635,7 +9781,7 @@
9635
9781
  options = Batman.extend({}, this.baseOptions, options);
9636
9782
  options[cardinality] = true;
9637
9783
  routeTemplate = this.constructor.ROUTES[cardinality];
9638
- resourceRoot = options.controller;
9784
+ resourceRoot = Batman.helpers.underscore(options.controller);
9639
9785
  for (_j = 0, _len = names.length; _j < _len; _j++) {
9640
9786
  name = names[_j];
9641
9787
  routeOptions = Batman.extend({
@@ -10025,21 +10171,62 @@
10025
10171
 
10026
10172
  __extends(PluralAssociation, _super);
10027
10173
 
10028
- function PluralAssociation() {
10029
- return PluralAssociation.__super__.constructor.apply(this, arguments);
10030
- }
10031
-
10032
10174
  PluralAssociation.prototype.proxyClass = Batman.AssociationSet;
10033
10175
 
10034
10176
  PluralAssociation.prototype.isSingular = false;
10035
10177
 
10036
- PluralAssociation.prototype.setForRecord = Batman.Property.wrapTrackingPrevention(function(record) {
10037
- var id;
10038
- if (id = record.get(this.primaryKey)) {
10039
- return this.setIndex().get(id);
10178
+ function PluralAssociation() {
10179
+ PluralAssociation.__super__.constructor.apply(this, arguments);
10180
+ this._resetSetHashes();
10181
+ }
10182
+
10183
+ PluralAssociation.prototype.setForRecord = function(record) {
10184
+ var childModelSetIndex, indexValue,
10185
+ _this = this;
10186
+ indexValue = this.indexValueForRecord(record);
10187
+ childModelSetIndex = this.setIndex();
10188
+ Batman.Property.withoutTracking(function() {
10189
+ return _this._setsByRecord.getOrSet(record, function() {
10190
+ var existingValueSet, newSet;
10191
+ if (indexValue != null) {
10192
+ existingValueSet = _this._setsByValue.get(indexValue);
10193
+ if (existingValueSet != null) {
10194
+ return existingValueSet;
10195
+ }
10196
+ }
10197
+ newSet = new _this.proxyClass(indexValue, _this);
10198
+ if (indexValue != null) {
10199
+ _this._setsByValue.set(indexValue, newSet);
10200
+ }
10201
+ return newSet;
10202
+ });
10203
+ });
10204
+ if (indexValue != null) {
10205
+ return childModelSetIndex.get(indexValue);
10040
10206
  } else {
10041
- return new this.proxyClass(void 0, this);
10207
+ return this._setsByRecord.get(record);
10208
+ }
10209
+ };
10210
+
10211
+ PluralAssociation.prototype.setForKey = Batman.Property.wrapTrackingPrevention(function(indexValue) {
10212
+ var foundSet,
10213
+ _this = this;
10214
+ foundSet = void 0;
10215
+ this._setsByRecord.forEach(function(record, set) {
10216
+ if (foundSet != null) {
10217
+ return;
10218
+ }
10219
+ if (_this.indexValueForRecord(record) === indexValue) {
10220
+ return foundSet = set;
10221
+ }
10222
+ });
10223
+ if (foundSet != null) {
10224
+ foundSet.foreignKeyValue = indexValue;
10225
+ return foundSet;
10042
10226
  }
10227
+ return this._setsByValue.getOrSet(indexValue, function() {
10228
+ return new _this.proxyClass(indexValue, _this);
10229
+ });
10043
10230
  });
10044
10231
 
10045
10232
  PluralAssociation.prototype.getAccessor = function(self, model, label) {
@@ -10071,6 +10258,20 @@
10071
10258
  return this.index;
10072
10259
  };
10073
10260
 
10261
+ PluralAssociation.prototype.indexValueForRecord = function(record) {
10262
+ return record.get(this.primaryKey);
10263
+ };
10264
+
10265
+ PluralAssociation.prototype.reset = function() {
10266
+ PluralAssociation.__super__.reset.apply(this, arguments);
10267
+ return this._resetSetHashes();
10268
+ };
10269
+
10270
+ PluralAssociation.prototype._resetSetHashes = function() {
10271
+ this._setsByRecord = new Batman.SimpleHash;
10272
+ return this._setsByValue = new Batman.SimpleHash;
10273
+ };
10274
+
10074
10275
  return PluralAssociation;
10075
10276
 
10076
10277
  })(Batman.Association);
@@ -10279,18 +10480,33 @@
10279
10480
  SingularAssociation.prototype.isSingular = true;
10280
10481
 
10281
10482
  SingularAssociation.prototype.getAccessor = function(self, model, label) {
10282
- var proxy, recordInAttributes;
10483
+ var parent, proxy, record, recordInAttributes, _ref;
10283
10484
  if (recordInAttributes = self.getFromAttributes(this)) {
10284
10485
  return recordInAttributes;
10285
10486
  }
10286
10487
  if (self.getRelatedModel()) {
10287
10488
  proxy = this.associationProxy(self);
10288
- Batman.Property.withoutTracking(function() {
10289
- if (!proxy.get('loaded') && self.options.autoload) {
10290
- return proxy.load();
10489
+ record = false;
10490
+ parent = this;
10491
+ if ((_ref = proxy._loadSetter) == null) {
10492
+ proxy._loadSetter = proxy.once('loaded', function(child) {
10493
+ return parent._withoutDirtyTracking(function() {
10494
+ return this.set(self.label, child);
10495
+ });
10496
+ });
10497
+ }
10498
+ if (!Batman.Property.withoutTracking(function() {
10499
+ return proxy.get('loaded');
10500
+ })) {
10501
+ if (self.options.autoload) {
10502
+ Batman.Property.withoutTracking(function() {
10503
+ return proxy.load();
10504
+ });
10505
+ } else {
10506
+ record = proxy.loadFromLocal();
10291
10507
  }
10292
- });
10293
- return proxy;
10508
+ }
10509
+ return record || proxy;
10294
10510
  }
10295
10511
  };
10296
10512
 
@@ -10352,6 +10568,9 @@
10352
10568
  association = this;
10353
10569
  return function(data, _, __, ___, parentRecord) {
10354
10570
  var record, relatedModel;
10571
+ if (!data) {
10572
+ return;
10573
+ }
10355
10574
  relatedModel = association.getRelatedModel();
10356
10575
  record = relatedModel.createFromJSON(data);
10357
10576
  if (association.options.inverseOf) {
@@ -11008,8 +11227,10 @@
11008
11227
  return parentNode.removeChild(this.placeholderNode);
11009
11228
  }
11010
11229
  } else {
11011
- parentNode.insertBefore(this.placeholderNode, this.node);
11012
- return Batman.DOM.removeNode(this.node);
11230
+ if (this.node.parentNode != null) {
11231
+ parentNode.insertBefore(this.placeholderNode, this.node);
11232
+ return Batman.DOM.removeNode(this.node);
11233
+ }
11013
11234
  }
11014
11235
  };
11015
11236
 
@@ -11177,7 +11398,7 @@
11177
11398
 
11178
11399
  buntUndefined = function(f) {
11179
11400
  return function(value) {
11180
- if (typeof value === 'undefined') {
11401
+ if (value == null) {
11181
11402
  return void 0;
11182
11403
  } else {
11183
11404
  return f.apply(this, arguments);
@@ -11240,10 +11461,10 @@
11240
11461
  }
11241
11462
  },
11242
11463
  prepend: function(value, string, binding) {
11243
- return string + value;
11464
+ return string + (value != null ? value : '');
11244
11465
  },
11245
11466
  append: function(value, string, binding) {
11246
- return value + string;
11467
+ return (value != null ? value : '') + string;
11247
11468
  },
11248
11469
  replace: buntUndefined(function(value, searchFor, replaceWith, flags, binding) {
11249
11470
  if (!binding) {
@@ -11677,7 +11898,7 @@
11677
11898
  }
11678
11899
  this.node = document.createElement('div');
11679
11900
  this._setNodeOwner(this.node);
11680
- Batman.setInnerHTML(this.node, html);
11901
+ Batman.DOM.setInnerHTML(this.node, html);
11681
11902
  }
11682
11903
  return this.node;
11683
11904
  },
@@ -11688,7 +11909,7 @@
11688
11909
  this._setNodeOwner(node);
11689
11910
  updateHTML = function(html) {
11690
11911
  if (html != null) {
11691
- Batman.setInnerHTML(_this.node, html);
11912
+ Batman.DOM.setInnerHTML(_this.node, html);
11692
11913
  return _this.forget('html', updateHTML);
11693
11914
  }
11694
11915
  };
@@ -11930,7 +12151,7 @@
11930
12151
  _results = [];
11931
12152
  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
11932
12153
  child = _ref[_i];
11933
- _results.push(Batman.removeOrDestroyNode(child));
12154
+ _results.push(Batman.DOM.removeOrDestroyNode(child));
11934
12155
  }
11935
12156
  return _results;
11936
12157
  });
@@ -11951,7 +12172,7 @@
11951
12172
  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
11952
12173
  child = _ref[_i];
11953
12174
  if (!~this.currentVersionNodes.indexOf(child)) {
11954
- _results.push(Batman.removeOrDestroyNode(child));
12175
+ _results.push(Batman.DOM.removeOrDestroyNode(child));
11955
12176
  }
11956
12177
  }
11957
12178
  return _results;
@@ -11959,7 +12180,7 @@
11959
12180
 
11960
12181
  Yield.prototype.append = Yield.queued(function(node) {
11961
12182
  this.currentVersionNodes.push(node);
11962
- return Batman.appendChild(this.containerNode, node, true);
12183
+ return Batman.DOM.appendChild(this.containerNode, node, true);
11963
12184
  });
11964
12185
 
11965
12186
  Yield.prototype.replace = Yield.queued(function(node) {
@@ -11979,8 +12200,6 @@
11979
12200
 
11980
12201
  }).call(this);
11981
12202
 
11982
- (function() {
11983
-
11984
12203
  /*!
11985
12204
  * Reqwest! A general purpose XHR connection manager
11986
12205
  * (c) Dustin Diaz 2011
@@ -12355,13 +12574,69 @@
12355
12574
  }
12356
12575
 
12357
12576
  return reqwest
12358
- })
12577
+ });
12359
12578
 
12360
- ;
12579
+ (function() {
12580
+ var _ref, _ref1;
12361
12581
 
12362
- var prefixes;
12582
+ Batman.extend(Batman.DOM, {
12583
+ querySelectorAll: (typeof window !== "undefined" && window !== null ? (_ref = window.document) != null ? _ref.querySelectorAll : void 0 : void 0) != null ? function(node, selector) {
12584
+ return node.querySelectorAll(selector);
12585
+ } : function() {
12586
+ return Batman.developer.error("Please include either jQuery or a querySelectorAll polyfill, or set Batman.DOM.querySelectorAll to return an empty array.");
12587
+ },
12588
+ querySelector: (typeof window !== "undefined" && window !== null ? (_ref1 = window.document) != null ? _ref1.querySelector : void 0 : void 0) != null ? function(node, selector) {
12589
+ return node.querySelector(selector);
12590
+ } : function() {
12591
+ return Batman.developer.error("Please include either jQuery or a querySelector polyfill, or set Batman.DOM.querySelector to an empty function.");
12592
+ },
12593
+ setInnerHTML: function(node, html) {
12594
+ var child, childNodes, result, _i, _j, _len, _len1;
12595
+ childNodes = (function() {
12596
+ var _i, _len, _ref2, _results;
12597
+ _ref2 = node.childNodes;
12598
+ _results = [];
12599
+ for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
12600
+ child = _ref2[_i];
12601
+ _results.push(child);
12602
+ }
12603
+ return _results;
12604
+ })();
12605
+ for (_i = 0, _len = childNodes.length; _i < _len; _i++) {
12606
+ child = childNodes[_i];
12607
+ Batman.DOM.willRemoveNode(child);
12608
+ }
12609
+ result = node.innerHTML = html;
12610
+ for (_j = 0, _len1 = childNodes.length; _j < _len1; _j++) {
12611
+ child = childNodes[_j];
12612
+ Batman.DOM.didRemoveNode(child);
12613
+ }
12614
+ return result;
12615
+ },
12616
+ removeNode: function(node) {
12617
+ var _ref2;
12618
+ Batman.DOM.willRemoveNode(node);
12619
+ if ((_ref2 = node.parentNode) != null) {
12620
+ _ref2.removeChild(node);
12621
+ }
12622
+ return Batman.DOM.didRemoveNode(node);
12623
+ },
12624
+ destroyNode: function(node) {
12625
+ Batman.DOM.willDestroyNode(node);
12626
+ Batman.DOM.removeNode(node);
12627
+ return Batman.DOM.didDestroyNode(node);
12628
+ },
12629
+ appendChild: function(parent, child) {
12630
+ Batman.DOM.willInsertNode(child);
12631
+ parent.appendChild(child);
12632
+ return Batman.DOM.didInsertNode(child);
12633
+ }
12634
+ });
12363
12635
 
12364
- (typeof exports !== "undefined" && exports !== null ? exports : this).reqwest = typeof window !== "undefined" && window !== null ? window.reqwest : reqwest;
12636
+ }).call(this);
12637
+
12638
+ (function() {
12639
+ var prefixes;
12365
12640
 
12366
12641
  Batman.Request.prototype._parseResponseHeaders = function(xhr) {
12367
12642
  var headers;