luca 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/CHANGELOG +9 -0
  2. data/ROADMAP +15 -3
  3. data/Rakefile +33 -7
  4. data/app.rb +0 -1
  5. data/assets/javascripts/dependencies.coffee +0 -1
  6. data/assets/javascripts/sandbox/application.coffee +1 -1
  7. data/assets/javascripts/sandbox/templates/main.luca +52 -34
  8. data/assets/javascripts/sandbox/templates/sandbox/navigation.luca +3 -1
  9. data/assets/stylesheets/bootstrap-responsive.min.css +0 -1
  10. data/assets/stylesheets/bootstrap.min.css +48 -29
  11. data/assets/stylesheets/sandbox/sandbox.scss +11 -28
  12. data/lib/luca/rails/version.rb +1 -1
  13. data/site/assets/dependencies.js +94 -0
  14. data/site/assets/glyphicons-halflings-white.png +0 -0
  15. data/site/assets/glyphicons-halflings.png +0 -0
  16. data/site/assets/luca-ui-bootstrap.css +1313 -0
  17. data/site/assets/luca-ui-bootstrap.js +9 -0
  18. data/site/assets/luca-ui-development-tools.css +224 -0
  19. data/site/assets/luca-ui-development-tools.js +18561 -0
  20. data/site/assets/sandbox.css +14 -0
  21. data/site/assets/sandbox.js +131 -0
  22. data/site/index.html +20 -0
  23. data/spec/core/collection_spec.coffee +6 -6
  24. data/spec/core/view_spec.coffee +1 -0
  25. data/spec/framework_spec.coffee +7 -0
  26. data/spec/managers/collection_manager_spec.coffee +2 -1
  27. data/src/components/application.coffee +8 -4
  28. data/src/components/collection_view.coffee +8 -2
  29. data/src/components/fields/checkbox_array.coffee +3 -1
  30. data/src/components/form_view.coffee +46 -21
  31. data/src/components/grid_view.coffee +2 -4
  32. data/src/components/nav_bar.coffee +3 -7
  33. data/src/containers/tab_view.coffee +15 -2
  34. data/src/containers/viewport.coffee +13 -4
  35. data/src/core/collection.coffee +68 -53
  36. data/src/core/core.coffee +7 -2
  37. data/src/core/panel.coffee +32 -17
  38. data/src/core/registry.coffee +11 -3
  39. data/src/core/util.coffee +17 -1
  40. data/src/core/view.coffee +6 -5
  41. data/src/framework.coffee +46 -2
  42. data/src/managers/collection_manager.coffee +22 -81
  43. data/src/stylesheets/components/checkbox_array.scss +5 -0
  44. data/src/templates/components/form_alert +0 -0
  45. data/src/templates/components/form_alert.luca +3 -0
  46. data/src/templates/containers/tab_view.luca +1 -1
  47. data/src/tools/console.coffee +3 -0
  48. data/vendor/assets/javascripts/luca-ui-base.js +266 -128
  49. data/vendor/assets/javascripts/luca-ui-development-tools.js +3 -161
  50. data/vendor/assets/javascripts/luca-ui-development-tools.min.js +15 -0
  51. data/vendor/assets/javascripts/luca-ui-spec.js +380 -176
  52. data/vendor/assets/javascripts/luca-ui.js +348 -166
  53. data/vendor/assets/javascripts/luca-ui.min.js +4 -3
  54. data/vendor/assets/stylesheets/luca-ui-bootstrap.css +50 -29
  55. data/vendor/assets/stylesheets/luca-ui-spec.css +2 -0
  56. data/vendor/assets/stylesheets/luca-ui.css +2 -0
  57. metadata +16 -4
  58. data/src/templates/components/form_view.luca +0 -4
  59. data/src/tools/development_console.coffee +0 -147
@@ -18,7 +18,7 @@
18
18
  };
19
19
 
20
20
  _.extend(Luca, {
21
- VERSION: "0.9.1",
21
+ VERSION: "0.9.2",
22
22
  core: {},
23
23
  containers: {},
24
24
  components: {},
@@ -30,6 +30,8 @@
30
30
 
31
31
  _.extend(Luca, Backbone.Events);
32
32
 
33
+ Luca.autoRegister = true;
34
+
33
35
  Luca.developmentMode = false;
34
36
 
35
37
  Luca.enableGlobalObserver = false;
@@ -64,6 +66,10 @@
64
66
  return Luca.isBackboneModel(obj) || Luca.isBackboneView(obj) || Luca.isBackboneCollection(obj);
65
67
  };
66
68
 
69
+ Luca.isComponentPrototype = function(obj) {
70
+ return Luca.isViewPrototype(obj) || Luca.isModelPrototype(obj) || Luca.isCollectionPrototype(obj);
71
+ };
72
+
67
73
  Luca.isBackboneModel = function(obj) {
68
74
  return _.isFunction(obj != null ? obj.set : void 0) && _.isFunction(obj != null ? obj.get : void 0) && _.isObject(obj != null ? obj.attributes : void 0);
69
75
  };
@@ -76,6 +82,52 @@
76
82
  return _.isFunction(obj != null ? obj.fetch : void 0) && _.isFunction(obj != null ? obj.reset : void 0);
77
83
  };
78
84
 
85
+ Luca.isViewPrototype = function(obj) {
86
+ return (obj != null) && (obj.prototype != null) && (obj.prototype.make != null) && (obj.prototype.$ != null) && (obj.prototype.render != null);
87
+ };
88
+
89
+ Luca.isModelPrototype = function(obj) {
90
+ return (obj != null) && (typeof obj.prototype === "function" ? obj.prototype((obj.prototype.save != null) && (obj.prototype.changedAttributes != null)) : void 0);
91
+ };
92
+
93
+ Luca.isCollectionPrototype = function(obj) {
94
+ return (obj != null) && (obj.prototype != null) && !Luca.isModelPrototype(obj) && (obj.prototype.reset != null) && (obj.prototype.select != null) && (obj.prototype.reject != null);
95
+ };
96
+
97
+ Luca.inheritanceChain = function(obj) {
98
+ return _(Luca.parentClasses(obj)).map(function(className) {
99
+ return Luca.util.resolve(className);
100
+ });
101
+ };
102
+
103
+ Luca.parentClasses = function(obj) {
104
+ var classes, list, _ref;
105
+ list = [];
106
+ if (_.isString(obj)) obj = Luca.util.resolve(obj);
107
+ list.push(obj.displayName || ((_ref = obj.prototype) != null ? _ref.displayName : void 0) || Luca.parentClass(obj));
108
+ classes = (function() {
109
+ var _results;
110
+ _results = [];
111
+ while (!!(Luca.parentClass(obj) != null)) {
112
+ _results.push(obj = Luca.parentClass(obj));
113
+ }
114
+ return _results;
115
+ })();
116
+ list = list.concat(classes);
117
+ return _.uniq(list);
118
+ };
119
+
120
+ Luca.parentClass = function(obj) {
121
+ var list, _base, _ref;
122
+ list = [];
123
+ if (_.isString(obj)) obj = Luca.util.resolve(obj);
124
+ if (Luca.isComponent(obj)) {
125
+ return obj.displayName;
126
+ } else if (Luca.isComponentPrototype(obj)) {
127
+ return typeof (_base = obj.prototype)._superClass === "function" ? (_ref = _base._superClass()) != null ? _ref.displayName : void 0 : void 0;
128
+ }
129
+ };
130
+
79
131
  Luca.template = function(template_name, variables) {
80
132
  var jst, luca, needle, template, _ref;
81
133
  window.JST || (window.JST = {});
@@ -252,6 +304,30 @@
252
304
  return document.body.appendChild(script);
253
305
  };
254
306
 
307
+ Luca.util.make = Backbone.View.prototype.make;
308
+
309
+ Luca.util.label = function(contents, type, baseClass) {
310
+ var cssClass;
311
+ if (contents == null) contents = "";
312
+ if (baseClass == null) baseClass = "label";
313
+ cssClass = baseClass;
314
+ if (type != null) cssClass += " " + baseClass + "-" + type;
315
+ return Luca.util.make("span", {
316
+ "class": cssClass
317
+ }, contents);
318
+ };
319
+
320
+ Luca.util.badge = function(contents, type, baseClass) {
321
+ var cssClass;
322
+ if (contents == null) contents = "";
323
+ if (baseClass == null) baseClass = "badge";
324
+ cssClass = baseClass;
325
+ if (type != null) cssClass += " " + baseClass + "-" + type;
326
+ return Luca.util.make("span", {
327
+ "class": cssClass
328
+ }, contents);
329
+ };
330
+
255
331
  }).call(this);
256
332
  (function() {
257
333
  var DeferredBindingProxy, DefineProxy;
@@ -303,14 +379,21 @@
303
379
  };
304
380
 
305
381
  DefineProxy.prototype["with"] = function(properties) {
306
- var at;
382
+ var at, componentType;
307
383
  at = this.namespaced ? Luca.util.resolve(this.namespace, window || global) : window || global;
308
384
  if (this.namespaced && !(at != null)) {
309
385
  eval("(window||global)." + this.namespace + " = {}");
310
386
  at = Luca.util.resolve(this.namespace, window || global);
311
387
  }
312
388
  at[this.componentId] = Luca.extend(this.superClassName, this.componentName, properties);
313
- Luca.register(_.string.underscored(this.componentId), this.componentName);
389
+ if (Luca.autoRegister === true) {
390
+ if (Luca.isViewPrototype(at[this.componentId])) componentType = "view";
391
+ if (Luca.isCollectionPrototype(at[this.componentId])) {
392
+ componentType = "collection";
393
+ }
394
+ if (Luca.isModelPrototype(at[this.componentId])) componentType = "model";
395
+ Luca.register(_.string.underscored(this.componentId), this.componentName, componentType);
396
+ }
314
397
  return at[this.componentId];
315
398
  };
316
399
 
@@ -448,6 +531,8 @@
448
531
 
449
532
  registry = {
450
533
  classes: {},
534
+ model_classes: {},
535
+ collection_classes: {},
451
536
  namespaces: ['Luca.containers', 'Luca.components']
452
537
  };
453
538
 
@@ -458,9 +543,17 @@
458
543
 
459
544
  Luca.defaultComponentType = 'view';
460
545
 
461
- Luca.register = function(component, prototypeName) {
546
+ Luca.register = function(component, prototypeName, componentType) {
547
+ if (componentType == null) componentType = "view";
462
548
  Luca.trigger("component:registered", component, prototypeName);
463
- return registry.classes[component] = prototypeName;
549
+ switch (componentType) {
550
+ case "model":
551
+ return registry.model_classes[component] = prototypeName;
552
+ case "collection":
553
+ return registry.model_classes[component] = prototypeName;
554
+ default:
555
+ return registry.classes[component] = prototypeName;
556
+ }
464
557
  };
465
558
 
466
559
  Luca.development_mode_register = function(component, prototypeName) {
@@ -599,7 +692,7 @@
599
692
  return this.delegateEvents();
600
693
  },
601
694
  $wrap: function(wrapper) {
602
- if (!wrapper.match(/[<>]/)) {
695
+ if (_.isString(wrapper) && !wrapper.match(/[<>]/)) {
603
696
  wrapper = this.make("div", {
604
697
  "class": wrapper
605
698
  });
@@ -639,8 +732,8 @@
639
732
  });
640
733
  },
641
734
  getCollectionManager: function() {
642
- var _ref;
643
- return this.collectionManager || ((_ref = Luca.CollectionManager.get) != null ? _ref.call() : void 0);
735
+ var _base;
736
+ return this.collectionManager || (typeof (_base = Luca.CollectionManager).get === "function" ? _base.get() : void 0);
644
737
  },
645
738
  registerCollectionEvents: function() {
646
739
  var manager,
@@ -722,7 +815,7 @@
722
815
  _base = definition.render;
723
816
  _base || (_base = Luca.View.prototype.$attach);
724
817
  definition.render = function() {
725
- var autoTrigger, fn, target, trigger, view,
818
+ var autoTrigger, deferred, fn, target, trigger, view,
726
819
  _this = this;
727
820
  view = this;
728
821
  if (this.deferrable) {
@@ -732,10 +825,11 @@
732
825
  }
733
826
  target || (target = this.deferrable);
734
827
  trigger = this.deferrable_event ? this.deferrable_event : "reset";
735
- view.defer(function() {
828
+ deferred = function() {
736
829
  _base.call(view);
737
830
  return view.trigger("after:render", view);
738
- }).until(target, trigger);
831
+ };
832
+ view.defer(deferred).until(target, trigger);
739
833
  view.trigger("before:render", this);
740
834
  autoTrigger = this.deferrable_trigger || this.deferUntil;
741
835
  if (!(autoTrigger != null)) {
@@ -809,72 +903,7 @@
809
903
 
810
904
  _.def("Luca.Collection")["extends"](source)["with"]({
811
905
  cachedMethods: [],
812
- restoreMethodCache: function() {
813
- var config, name, _ref, _results;
814
- _ref = this._methodCache;
815
- _results = [];
816
- for (name in _ref) {
817
- config = _ref[name];
818
- if (config.original != null) {
819
- config.args = void 0;
820
- _results.push(this[name] = config.original);
821
- } else {
822
- _results.push(void 0);
823
- }
824
- }
825
- return _results;
826
- },
827
- clearMethodCache: function(method) {
828
- return this._methodCache[method].value = void 0;
829
- },
830
- clearAllMethodsCache: function() {
831
- var config, name, _ref, _results;
832
- _ref = this._methodCache;
833
- _results = [];
834
- for (name in _ref) {
835
- config = _ref[name];
836
- _results.push(this.clearMethodCache(name));
837
- }
838
- return _results;
839
- },
840
- setupMethodCaching: function() {
841
- var cache, collection, membershipEvents;
842
- collection = this;
843
- membershipEvents = ["reset", "add", "remove"];
844
- cache = this._methodCache = {};
845
- return _(this.cachedMethods).each(function(method) {
846
- var dependencies, dependency, membershipEvent, _i, _j, _len, _len2, _ref, _results;
847
- cache[method] = {
848
- name: method,
849
- original: collection[method],
850
- value: void 0
851
- };
852
- collection[method] = function() {
853
- var _base;
854
- return (_base = cache[method]).value || (_base.value = cache[method].original.apply(collection, arguments));
855
- };
856
- for (_i = 0, _len = membershipEvents.length; _i < _len; _i++) {
857
- membershipEvent = membershipEvents[_i];
858
- collection.bind(membershipEvent, function() {
859
- return collection.clearAllMethodsCache();
860
- });
861
- }
862
- dependencies = method.split(':')[1];
863
- if (dependencies) {
864
- _ref = dependencies.split(",");
865
- _results = [];
866
- for (_j = 0, _len2 = _ref.length; _j < _len2; _j++) {
867
- dependency = _ref[_j];
868
- _results.push(collection.bind("change:" + dependency, function() {
869
- return collection.clearMethodCache({
870
- method: method
871
- });
872
- }));
873
- }
874
- return _results;
875
- }
876
- });
877
- },
906
+ remoteFilter: false,
878
907
  initialize: function(models, options) {
879
908
  var table,
880
909
  _this = this;
@@ -894,6 +923,7 @@
894
923
  }
895
924
  this.name || (this.name = this.registerAs);
896
925
  this.manager || (this.manager = this.registerWith);
926
+ this.manager = _.isFunction(this.manager) ? this.manager() : this.manager;
897
927
  if (this.name && !this.manager) this.manager = Luca.CollectionManager.get();
898
928
  if (this.manager) {
899
929
  this.name || (this.name = this.cache_key());
@@ -957,14 +987,13 @@
957
987
  return _.uniq(parts).join("&");
958
988
  },
959
989
  resetFilter: function() {
960
- this.base_params = Luca.Collection.baseParams();
990
+ this.base_params = _(Luca.Collection.baseParams()).clone();
961
991
  return this;
962
992
  },
963
- remoteFilter: true,
964
993
  applyFilter: function(filter, options) {
965
994
  if (filter == null) filter = {};
966
995
  if (options == null) options = {};
967
- if ((options.remote != null) === true) {
996
+ if ((options.remote != null) === true || this.remoteFilter === true) {
968
997
  this.applyParams(filter);
969
998
  return this.fetch(_.extend(options, {
970
999
  refresh: true
@@ -974,8 +1003,9 @@
974
1003
  }
975
1004
  },
976
1005
  applyParams: function(params) {
977
- this.base_params || (this.base_params = _(Luca.Collection.baseParams()).clone());
978
- return _.extend(this.base_params, params);
1006
+ this.base_params = _(Luca.Collection.baseParams()).clone();
1007
+ _.extend(this.base_params, params);
1008
+ return this;
979
1009
  },
980
1010
  register: function(collectionManager, key, collection) {
981
1011
  if (collectionManager == null) {
@@ -1059,7 +1089,7 @@
1059
1089
  scope = options.scope || this;
1060
1090
  if (this.length > 0 && !this.fetching) fn.apply(scope, [this]);
1061
1091
  this.bind("reset", function(collection) {
1062
- return fn.apply(scope, [collection]);
1092
+ return fn.call(scope, collection);
1063
1093
  });
1064
1094
  if (!(this.fetching === true || !options.autoFetch || this.length > 0)) {
1065
1095
  return this.fetch();
@@ -1074,6 +1104,81 @@
1074
1104
  Luca.Collection.cache(this.bootstrap_cache_key, models);
1075
1105
  }
1076
1106
  return models;
1107
+ },
1108
+ restoreMethodCache: function() {
1109
+ var config, name, _ref, _results;
1110
+ _ref = this._methodCache;
1111
+ _results = [];
1112
+ for (name in _ref) {
1113
+ config = _ref[name];
1114
+ if (config.original != null) {
1115
+ config.args = void 0;
1116
+ _results.push(this[name] = config.original);
1117
+ } else {
1118
+ _results.push(void 0);
1119
+ }
1120
+ }
1121
+ return _results;
1122
+ },
1123
+ clearMethodCache: function(method) {
1124
+ return this._methodCache[method].value = void 0;
1125
+ },
1126
+ clearAllMethodsCache: function() {
1127
+ var config, name, _ref, _results;
1128
+ _ref = this._methodCache;
1129
+ _results = [];
1130
+ for (name in _ref) {
1131
+ config = _ref[name];
1132
+ _results.push(this.clearMethodCache(name));
1133
+ }
1134
+ return _results;
1135
+ },
1136
+ setupMethodCaching: function() {
1137
+ var cache, collection, membershipEvents;
1138
+ collection = this;
1139
+ membershipEvents = ["reset", "add", "remove"];
1140
+ cache = this._methodCache = {};
1141
+ return _(this.cachedMethods).each(function(method) {
1142
+ var dependencies, dependency, membershipEvent, _i, _j, _len, _len2, _ref, _results;
1143
+ cache[method] = {
1144
+ name: method,
1145
+ original: collection[method],
1146
+ value: void 0
1147
+ };
1148
+ collection[method] = function() {
1149
+ var _base;
1150
+ return (_base = cache[method]).value || (_base.value = cache[method].original.apply(collection, arguments));
1151
+ };
1152
+ for (_i = 0, _len = membershipEvents.length; _i < _len; _i++) {
1153
+ membershipEvent = membershipEvents[_i];
1154
+ collection.bind(membershipEvent, function() {
1155
+ return collection.clearAllMethodsCache();
1156
+ });
1157
+ }
1158
+ dependencies = method.split(':')[1];
1159
+ if (dependencies) {
1160
+ _ref = dependencies.split(",");
1161
+ _results = [];
1162
+ for (_j = 0, _len2 = _ref.length; _j < _len2; _j++) {
1163
+ dependency = _ref[_j];
1164
+ _results.push(collection.bind("change:" + dependency, function() {
1165
+ return collection.clearMethodCache({
1166
+ method: method
1167
+ });
1168
+ }));
1169
+ }
1170
+ return _results;
1171
+ }
1172
+ });
1173
+ },
1174
+ query: function(filter, options) {
1175
+ if (filter == null) filter = {};
1176
+ if (options == null) options = {};
1177
+ if (Backbone.QueryCollection != null) {
1178
+ return Backbone.QueryCollection.prototype.query.apply(this, arguments);
1179
+ } else {
1180
+ return this.models;
1181
+ }
1077
1182
  }
1078
1183
  });
1079
1184
 
@@ -1092,7 +1197,7 @@
1092
1197
  Luca.Collection.baseParams = function(obj) {
1093
1198
  if (obj) return Luca.Collection._baseParams = obj;
1094
1199
  if (_.isFunction(Luca.Collection._baseParams)) {
1095
- return Luca.Collection._baseParams.call();
1200
+ return Luca.Collection._baseParams();
1096
1201
  }
1097
1202
  if (_.isObject(Luca.Collection._baseParams)) {
1098
1203
  return Luca.Collection._baseParams;
@@ -1114,7 +1219,7 @@
1114
1219
  (function() {
1115
1220
  var attachToolbar;
1116
1221
 
1117
- attachToolbar = function(config) {
1222
+ attachToolbar = function(config, targetEl) {
1118
1223
  var action, container, hasBody, id, toolbar;
1119
1224
  if (config == null) config = {};
1120
1225
  config.orientation || (config.orientation = "top");
@@ -1145,7 +1250,7 @@
1145
1250
  }
1146
1251
  }
1147
1252
  })();
1148
- return this.$bodyEl()[action](container);
1253
+ return (targetEl || this.$bodyEl())[action](container);
1149
1254
  };
1150
1255
 
1151
1256
  _.def("Luca.components.Panel")["extends"]("Luca.View")["with"]({
@@ -1153,10 +1258,12 @@
1153
1258
  bottomToolbar: void 0,
1154
1259
  loadMask: false,
1155
1260
  loadMaskTemplate: ["components/load_mask"],
1261
+ loadMaskTimeout: 3000,
1156
1262
  initialize: function(options) {
1157
1263
  var _this = this;
1158
1264
  this.options = options != null ? options : {};
1159
1265
  Luca.View.prototype.initialize.apply(this, arguments);
1266
+ _.bindAll(this, "applyLoadMask", "disableLoadMask");
1160
1267
  if (this.loadMask === true) {
1161
1268
  this.defer(function() {
1162
1269
  _this.$el.addClass('with-mask');
@@ -1176,25 +1283,35 @@
1176
1283
  return this.$bodyEl();
1177
1284
  }
1178
1285
  },
1179
- applyLoadMask: function() {
1286
+ disableLoadMask: function() {
1287
+ this.$('.load-mask .bar').css("width", "100%");
1288
+ this.$('.load-mask').hide();
1289
+ return clearInterval(this.loadMaskInterval);
1290
+ },
1291
+ enableLoadMask: function() {
1180
1292
  var maxWidth,
1181
1293
  _this = this;
1294
+ this.$('.load-mask').show().find('.bar').css("width", "0%");
1295
+ maxWidth = this.$('.load-mask .progress').width();
1296
+ if (maxWidth < 20 && (maxWidth = this.$el.width()) < 20) {
1297
+ maxWidth = this.$el.parent().width();
1298
+ }
1299
+ this.loadMaskInterval = setInterval(function() {
1300
+ var currentWidth, newWidth;
1301
+ currentWidth = _this.$('.load-mask .bar').width();
1302
+ newWidth = currentWidth + 12;
1303
+ return _this.$('.load-mask .bar').css('width', newWidth);
1304
+ }, 200);
1305
+ if (this.loadMaskTimeout == null) return;
1306
+ return _.delay(function() {
1307
+ return _this.disableLoadMask();
1308
+ }, this.loadMaskTimeout);
1309
+ },
1310
+ applyLoadMask: function() {
1182
1311
  if (this.$('.load-mask').is(":visible")) {
1183
- this.$('.load-mask .bar').css("width", "100%");
1184
- this.$('.load-mask').hide();
1185
- return clearInterval(this.loadMaskInterval);
1312
+ return this.disableLoadMask();
1186
1313
  } else {
1187
- this.$('.load-mask').show().find('.bar').css("width", "0%");
1188
- maxWidth = this.$('.load-mask .progress').width();
1189
- if (maxWidth < 20 && (maxWidth = this.$el.width()) < 20) {
1190
- maxWidth = this.$el.parent().width();
1191
- }
1192
- return this.loadMaskInterval = setInterval(function() {
1193
- var currentWidth, newWidth;
1194
- currentWidth = _this.$('.load-mask .bar').width();
1195
- newWidth = currentWidth + 12;
1196
- return _this.$('.load-mask .bar').css('width', newWidth);
1197
- }, 200);
1314
+ return this.enableLoadMask();
1198
1315
  }
1199
1316
  },
1200
1317
  applyStyles: function(styles, body) {
@@ -1235,7 +1352,7 @@
1235
1352
  return $(this.el);
1236
1353
  },
1237
1354
  $wrap: function(wrapper) {
1238
- if (!wrapper.match(/[<>]/)) {
1355
+ if (_.isString(wrapper) && !wrapper.match(/[<>]/)) {
1239
1356
  wrapper = this.make("div", {
1240
1357
  "class": wrapper
1241
1358
  });
@@ -1266,7 +1383,7 @@
1266
1383
  if (config == null) config = {};
1267
1384
  config.parent = this;
1268
1385
  config.orientation = orientation;
1269
- return attachToolbar.call(this, config);
1386
+ return attachToolbar.call(this, config, config.targetEl);
1270
1387
  }
1271
1388
  });
1272
1389
 
@@ -1383,7 +1500,7 @@
1383
1500
  }).call(this);
1384
1501
  (function() {
1385
1502
  Luca.templates || (Luca.templates = {});
1386
- Luca.templates["components/form_view"] = function(obj){var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('<div class=\'form-view-panel\'>\n <ul class=\'form-view-flash-container\'></ul>\n <div class=\'form-view-body\'></div>\n</div>\n');}return __p.join('');};
1503
+ Luca.templates["components/form_alert"] = function(obj){var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('<div class=\'', className ,'\'>\n <a class=\'close\' data-dismiss=\'alert\' href=\'#\'>x</a>\n ', message ,'\n</div>\n');}return __p.join('');};
1387
1504
  }).call(this);
1388
1505
  (function() {
1389
1506
  Luca.templates || (Luca.templates = {});
@@ -1411,7 +1528,7 @@
1411
1528
  }).call(this);
1412
1529
  (function() {
1413
1530
  Luca.templates || (Luca.templates = {});
1414
- Luca.templates["containers/tab_view"] = function(obj){var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('<ul class=\'nav nav-tabs\' id=\'', cid ,'-tabs-selector\'></ul>\n<div class=\'tab-content\' id=\'', cid ,'-tab-view-content\'></div>\n');}return __p.join('');};
1531
+ Luca.templates["containers/tab_view"] = function(obj){var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('<ul class=\'nav ', navClass ,'\' id=\'', cid ,'-tabs-selector\'></ul>\n<div class=\'tab-content\' id=\'', cid ,'-tab-view-content\'></div>\n');}return __p.join('');};
1415
1532
  }).call(this);
1416
1533
  (function() {
1417
1534
  Luca.templates || (Luca.templates = {});
@@ -1816,20 +1933,30 @@
1816
1933
 
1817
1934
  }).call(this);
1818
1935
  (function() {
1819
- var instances;
1820
-
1821
- instances = [];
1822
1936
 
1823
1937
  Luca.CollectionManager = (function() {
1824
1938
 
1939
+ CollectionManager.prototype.name = "primary";
1940
+
1825
1941
  CollectionManager.prototype.__collections = {};
1826
1942
 
1827
1943
  function CollectionManager(options) {
1944
+ var existing, manager, _base, _base2;
1828
1945
  this.options = options != null ? options : {};
1829
1946
  _.extend(this, this.options);
1947
+ manager = this;
1948
+ if (existing = typeof (_base = Luca.CollectionManager).get === "function" ? _base.get(this.name) : void 0) {
1949
+ throw 'Attempt to create a collection manager with a name which already exists';
1950
+ }
1951
+ (_base2 = Luca.CollectionManager).instances || (_base2.instances = {});
1830
1952
  _.extend(this, Backbone.Events);
1831
- instances.push(this);
1832
- this.state = new Backbone.Model;
1953
+ _.extend(this, Luca.Events);
1954
+ Luca.CollectionManager.instances[this.name] = manager;
1955
+ Luca.CollectionManager.get = function(name) {
1956
+ if (name == null) return manager;
1957
+ return Luca.CollectionManager.instances[name];
1958
+ };
1959
+ this.state = new Luca.Model();
1833
1960
  if (this.initialCollections) {
1834
1961
  this.state.set({
1835
1962
  loaded_collections_count: 0,
@@ -1947,15 +2074,7 @@
1947
2074
  })();
1948
2075
 
1949
2076
  Luca.CollectionManager.destroyAll = function() {
1950
- return instances = [];
1951
- };
1952
-
1953
- Luca.CollectionManager.instances = function() {
1954
- return instances;
1955
- };
1956
-
1957
- Luca.CollectionManager.get = function() {
1958
- return _(instances).last();
2077
+ return Luca.CollectionManager.instances = {};
1959
2078
  };
1960
2079
 
1961
2080
  }).call(this);
@@ -2371,10 +2490,12 @@
2371
2490
  className: 'luca-ui-tab-view tabbable',
2372
2491
  tab_position: 'top',
2373
2492
  tabVerticalOffset: '50px',
2493
+ navClass: "nav-tabs",
2374
2494
  bodyTemplate: "containers/tab_view",
2375
2495
  bodyEl: "div.tab-content",
2376
2496
  initialize: function(options) {
2377
2497
  this.options = options != null ? options : {};
2498
+ if (this.navStyle === "list") this.navClass = "nav-list";
2378
2499
  Luca.containers.CardView.prototype.initialize.apply(this, arguments);
2379
2500
  _.bindAll(this, "select", "highlightSelectedTab");
2380
2501
  this.setupHooks(this.hooks);
@@ -2405,12 +2526,21 @@
2405
2526
  var tabView;
2406
2527
  tabView = this;
2407
2528
  return this.each(function(component, index) {
2408
- var selector;
2529
+ var icon, link, selector, _ref;
2530
+ if (component.tabIcon) icon = "<i class='icon-" + component.tabIcon;
2531
+ link = "<a href='#'>" + (icon || '') + " " + component.title + "</a>";
2409
2532
  selector = tabView.make("li", {
2410
2533
  "class": "tab-selector",
2411
2534
  "data-target": index
2412
- }, "<a>" + component.title + "</a>");
2413
- return tabView.tabContainer().append(selector);
2535
+ }, link);
2536
+ tabView.tabContainer().append(selector);
2537
+ if ((component.navHeading != null) && !((_ref = tabView.navHeadings) != null ? _ref[component.navHeading] : void 0)) {
2538
+ $(selector).before(tabView.make('li', {
2539
+ "class": "nav-header"
2540
+ }, component.navHeading));
2541
+ tabView.navHeadings || (tabView.navHeadings = {});
2542
+ return tabView.navHeadings[component.navHeading] = true;
2543
+ }
2414
2544
  });
2415
2545
  },
2416
2546
  highlightSelectedTab: function() {
@@ -2419,6 +2549,7 @@
2419
2549
  },
2420
2550
  select: function(e) {
2421
2551
  var me, my;
2552
+ e.preventDefault();
2422
2553
  me = my = $(e.target);
2423
2554
  this.trigger("before:select", this);
2424
2555
  this.activate(my.parent().data('target'));
@@ -2434,7 +2565,7 @@
2434
2565
  return $("#" + this.cid + "-tabs-selector");
2435
2566
  },
2436
2567
  tabContainer: function() {
2437
- return this.$('ul.nav-tabs', this.tabContainerWrapper());
2568
+ return this.$("ul." + this.navClass, this.tabContainerWrapper());
2438
2569
  },
2439
2570
  tabSelectors: function() {
2440
2571
  return this.$('li.tab-selector', this.tabContainer());
@@ -2452,11 +2583,12 @@
2452
2583
  wrapperClass: 'row',
2453
2584
  initialize: function(options) {
2454
2585
  this.options = options != null ? options : {};
2455
- Luca.core.Container.prototype.initialize.apply(this, arguments);
2586
+ _.extend(this, this.options);
2456
2587
  if (Luca.enableBootstrap === true) {
2457
2588
  if (this.fluid === true) this.wrapperClass = "row-fluid";
2458
- this.$el.wrap("<div class='" + this.wrapperClass + "' />").addClass('span12');
2589
+ this.$wrap(this.wrapperClass);
2459
2590
  }
2591
+ Luca.core.Container.prototype.initialize.apply(this, arguments);
2460
2592
  if (this.fullscreen) return $('html,body').addClass('luca-ui-fullscreen');
2461
2593
  },
2462
2594
  beforeRender: function() {
@@ -2464,12 +2596,18 @@
2464
2596
  if ((_ref = Luca.containers.CardView.prototype.beforeRender) != null) {
2465
2597
  _ref.apply(this, arguments);
2466
2598
  }
2467
- if (Luca.enableBootstrap && this.topNav && this.fullscreen) {
2468
- $('body').css('padding', '40px');
2469
- }
2470
2599
  if (this.topNav != null) this.renderTopNavigation();
2471
2600
  if (this.bottomNav != null) return this.renderBottomNavigation();
2472
2601
  },
2602
+ afterRender: function() {
2603
+ var _ref;
2604
+ if ((_ref = Luca.containers.CardView.prototype.after) != null) {
2605
+ _ref.apply(this, arguments);
2606
+ }
2607
+ if (Luca.enableBootstrap === true) {
2608
+ return this.$el.children().wrap('<div class="container" />');
2609
+ }
2610
+ },
2473
2611
  renderTopNavigation: function() {
2474
2612
  var _base;
2475
2613
  if (this.topNav == null) return;
@@ -2510,6 +2648,7 @@
2510
2648
  _.def('Luca.Application')["extends"]('Luca.containers.Viewport')["with"]({
2511
2649
  autoStartHistory: true,
2512
2650
  useCollectionManager: true,
2651
+ collectionManagerClass: "Luca.CollectionManager",
2513
2652
  plugin: false,
2514
2653
  useController: true,
2515
2654
  components: [
@@ -2534,13 +2673,16 @@
2534
2673
  }
2535
2674
  ];
2536
2675
  if (this.useCollectionManager === true) {
2676
+ if (_.isString(this.collectionManagerClass)) {
2677
+ this.collectionManagerClass = Luca.util.resolve(this.collectionManagerClass);
2678
+ }
2537
2679
  this.collectionManager || (this.collectionManager = typeof (_base = Luca.CollectionManager).get === "function" ? _base.get() : void 0);
2538
- this.collectionManager || (this.collectionManager = new Luca.CollectionManager(this.collectionManagerOptions || (this.collectionManagerOptions = {})));
2680
+ this.collectionManager || (this.collectionManager = new this.collectionManagerClass(this.collectionManagerOptions || (this.collectionManagerOptions = {})));
2539
2681
  }
2540
- this.state = new Backbone.Model(this.defaultState);
2541
- this.bind("ready", function() {
2682
+ this.state = new Luca.Model(this.defaultState);
2683
+ this.defer(function() {
2542
2684
  return _this.render();
2543
- });
2685
+ }).until("ready");
2544
2686
  if (this.useKeyRouter === true && (this.keyEvents != null)) {
2545
2687
  this.setupKeyRouter();
2546
2688
  }
@@ -2733,13 +2875,16 @@
2733
2875
  this.options = options != null ? options : {};
2734
2876
  _.extend(this, this.options);
2735
2877
  _.bindAll(this, "refresh");
2736
- if (this.collection == null) {
2878
+ if (!((this.collection != null) || this.options.collection)) {
2737
2879
  throw "Collection Views must specify a collection";
2738
2880
  }
2739
2881
  if (!((this.itemTemplate != null) || (this.itemRenderer != null) || (this.itemProperty != null))) {
2740
2882
  throw "Collection Views must specify an item template or item renderer function";
2741
2883
  }
2742
2884
  Luca.components.Panel.prototype.initialize.apply(this, arguments);
2885
+ if (_.isString(this.collection) && Luca.CollectionManager.get()) {
2886
+ this.collection = Luca.CollectionManager.get().get(this.collection);
2887
+ }
2743
2888
  if (Luca.isBackboneCollection(this.collection)) {
2744
2889
  this.collection.bind("reset", this.refresh);
2745
2890
  this.collection.bind("add", this.refresh);
@@ -2762,8 +2907,10 @@
2762
2907
  content = this.itemRenderer.call(this, item);
2763
2908
  }
2764
2909
  if (this.itemProperty) {
2765
- return content = _.isFunction(this.itemProperty) ? this.itemProperty() : item.model.get(this.itemProperty) || item.model[this.itemProperty];
2910
+ content = item.model.get(this.itemProperty) || item.model[this.itemProperty];
2911
+ if (_.isFunction(content)) content = content();
2766
2912
  }
2913
+ return content;
2767
2914
  },
2768
2915
  makeItem: function(model, index) {
2769
2916
  var item;
@@ -2896,6 +3043,7 @@
2896
3043
  _.def('Luca.fields.CheckboxArray')["extends"]('Luca.core.Field')["with"]({
2897
3044
  version: 2,
2898
3045
  template: "fields/checkbox_array",
3046
+ className: "luca-ui-checkbox-array",
2899
3047
  events: {
2900
3048
  "click input": "clickHandler"
2901
3049
  },
@@ -2952,6 +3100,7 @@
2952
3100
  input_id = _.uniqueId("" + _this.cid + "_checkbox");
2953
3101
  inputElement = make("input", {
2954
3102
  type: "checkbox",
3103
+ "class": "array-checkbox",
2955
3104
  name: _this.input_name,
2956
3105
  value: value,
2957
3106
  id: input_id
@@ -3333,6 +3482,27 @@
3333
3482
 
3334
3483
  }).call(this);
3335
3484
  (function() {
3485
+ var defaultToolbar;
3486
+
3487
+ defaultToolbar = {
3488
+ buttons: [
3489
+ {
3490
+ icon: "remove-sign",
3491
+ label: "Reset",
3492
+ eventId: "click:reset",
3493
+ className: "reset-button",
3494
+ align: 'right'
3495
+ }, {
3496
+ icon: "ok-sign",
3497
+ white: true,
3498
+ label: "Save Changes",
3499
+ eventId: "click:submit",
3500
+ color: "success",
3501
+ className: 'submit-button',
3502
+ align: 'right'
3503
+ }
3504
+ ]
3505
+ };
3336
3506
 
3337
3507
  _.def("Luca.components.FormView")["extends"]('Luca.core.Container')["with"]({
3338
3508
  tagName: 'form',
@@ -3345,7 +3515,6 @@
3345
3515
  toolbar: true,
3346
3516
  legend: "",
3347
3517
  bodyClassName: "form-view-body",
3348
- bodyTemplate: ["components/form_view"],
3349
3518
  initialize: function(options) {
3350
3519
  this.options = options != null ? options : {};
3351
3520
  if (this.loadMask == null) this.loadMask = Luca.enableBootstrap;
@@ -3354,28 +3523,18 @@
3354
3523
  this.state || (this.state = new Backbone.Model);
3355
3524
  this.setupHooks(this.hooks);
3356
3525
  this.applyStyleClasses();
3357
- if (this.toolbar === true && !((this.bottomToolbar != null) || (this.topToolbar != null))) {
3358
- return this.bottomToolbar = {
3359
- buttons: [
3360
- {
3361
- icon: "remove-sign",
3362
- label: "Reset",
3363
- eventId: "click:reset",
3364
- className: "reset-button",
3365
- align: 'right'
3366
- }, {
3367
- icon: "ok-sign",
3368
- white: true,
3369
- label: "Save Changes",
3370
- eventId: "click:submit",
3371
- color: "success",
3372
- className: 'submit-button',
3373
- align: 'right'
3374
- }
3375
- ]
3376
- };
3526
+ if (this.toolbar !== false && (!this.topToolbar && !this.bottomToolbar)) {
3527
+ if (this.toolbar === "both" || this.toolbar === "top") {
3528
+ this.topToolbar = this.getDefaultToolbar();
3529
+ }
3530
+ if (this.toolbar !== "top") {
3531
+ return this.bottomToolbar = this.getDefaultToolbar();
3532
+ }
3377
3533
  }
3378
3534
  },
3535
+ getDefaultToolbar: function() {
3536
+ return defaultToolbar;
3537
+ },
3379
3538
  applyStyleClasses: function() {
3380
3539
  if (Luca.enableBootstrap) this.applyBootstrapStyleClasses();
3381
3540
  if (this.labelAlign) this.$el.addClass("label-align-" + this.labelAlign);
@@ -3390,14 +3549,14 @@
3390
3549
  },
3391
3550
  resetHandler: function(e) {
3392
3551
  var me, my;
3393
- me = my = $(e.currentTarget);
3552
+ me = my = $(e != null ? e.target : void 0);
3394
3553
  this.trigger("before:reset", this);
3395
3554
  this.reset();
3396
3555
  return this.trigger("after:reset", this);
3397
3556
  },
3398
3557
  submitHandler: function(e) {
3399
3558
  var me, my;
3400
- me = my = $(e.currentTarget);
3559
+ me = my = $(e != null ? e.target : void 0);
3401
3560
  this.trigger("before:submit", this);
3402
3561
  if (this.loadMask === true) this.trigger("enable:loadmask", this);
3403
3562
  if (this.hasModel()) return this.submit();
@@ -3544,6 +3703,32 @@
3544
3703
  setLegend: function(legend) {
3545
3704
  this.legend = legend;
3546
3705
  return $('fieldset legend', this.el).first().html(this.legend);
3706
+ },
3707
+ flash: function(message) {
3708
+ if (this.$('.toolbar-container.top').length > 0) {
3709
+ return this.$('.toolbar-container.top').after(message);
3710
+ } else {
3711
+ return this.$bodyEl().prepend(message);
3712
+ }
3713
+ },
3714
+ successFlashDelay: 1500,
3715
+ successMessage: function(message) {
3716
+ var _this = this;
3717
+ this.$('.alert.alert-success').remove();
3718
+ this.flash(Luca.template("components/form_alert", {
3719
+ className: "alert alert-success",
3720
+ message: message
3721
+ }));
3722
+ return _.delay(function() {
3723
+ return _this.$('.alert.alert-success').fadeOut();
3724
+ }, this.successFlashDelay || 0);
3725
+ },
3726
+ errorMessage: function(message) {
3727
+ this.$('.alert.alert-error').remove();
3728
+ return this.flash(Luca.template("components/form_alert", {
3729
+ className: "alert alert-error",
3730
+ message: message
3731
+ }));
3547
3732
  }
3548
3733
  });
3549
3734
 
@@ -3581,12 +3766,10 @@
3581
3766
  Luca.components.Panel.prototype.initialize.apply(this, arguments);
3582
3767
  this.configure_collection(true);
3583
3768
  this.collection.bind("before:fetch", function() {
3584
- console.log("Triggering Enable Load Mask");
3585
3769
  if (_this.loadMask === true) return _this.trigger("enable:loadmask");
3586
3770
  });
3587
3771
  this.collection.bind("reset", function(collection) {
3588
3772
  _this.refresh();
3589
- console.log("Triggering Disable LoadMask");
3590
3773
  if (_this.loadMask === true) _this.trigger("disable:loadmask");
3591
3774
  return _this.trigger("after:collection:load", collection);
3592
3775
  });
@@ -3598,9 +3781,9 @@
3598
3781
  cells = _this.render_row(model, _this.collection.indexOf(model), {
3599
3782
  cellsOnly: true
3600
3783
  });
3601
- return $(rowEl).html(cells);
3784
+ return $(rowEl).html(cells.join(" "));
3602
3785
  } catch (error) {
3603
- return console.log("Error in change handler for GridView.collection", error, _this, model, rowEl, cells);
3786
+ return console.log("Error in change handler for GridView.collection", error, _this, model);
3604
3787
  }
3605
3788
  });
3606
3789
  },
@@ -3806,17 +3989,16 @@
3806
3989
  fixed: true,
3807
3990
  position: 'top',
3808
3991
  className: 'navbar',
3809
- initialize: function(options) {
3810
- this.options = options != null ? options : {};
3811
- return Luca.View.prototype.initialize.apply(this, arguments);
3812
- },
3813
3992
  brand: "Luca.js",
3814
3993
  bodyTemplate: 'nav_bar',
3815
3994
  bodyClassName: 'luca-ui-navbar-body',
3816
3995
  beforeRender: function() {
3817
3996
  if (this.fixed) this.$el.addClass("navbar-fixed-" + this.position);
3818
3997
  if (this.brand != null) {
3819
- return this.content().append("<a class='brand' href='#'>" + this.brand + "</a>");
3998
+ this.content().append("<a class='brand' href='#'>" + this.brand + "</a>");
3999
+ }
4000
+ if (this.template) {
4001
+ return this.content().append(Luca.template(this.template, this));
3820
4002
  }
3821
4003
  },
3822
4004
  render: function() {