batman-rails 0.0.8 → 0.0.9

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.
@@ -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;