stormfront-rails 0.10.6 → 0.11.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 454e22f09976d29d75b77b5769dd3c7282c01363
4
- data.tar.gz: 25f88483b8ea590832dd50decd5479fbba27519c
3
+ metadata.gz: e4fc59612c92509eb2ce9c7dec61d92793625739
4
+ data.tar.gz: a5fafb949f95680426b40dc6ef0c38918f1a25e5
5
5
  SHA512:
6
- metadata.gz: 39ab1223257b6f556b5b09adec9cef23ca0d908928002591949b8caf3c0ee208fa0f4ba0bacdcfa6b33fbd8810ae622d5963f5e5bac9a131fa72a12532d78ed5
7
- data.tar.gz: 740c33c95d0623cc5aa97be78af117eb6e1ba13236632268c8b94248e357339ce252a3ee28987562d7b9d2b4ef8cd32a0f9866a1a50d906afe27896d44deeff2
6
+ metadata.gz: 785a3d81a0da1d81c251b1984543e5556fc804b6d8dc1643805f5cddba28c061e0ca8d27792736b53e8ca2264a4c56a18bb77c0fe0b1316879583b9c569481e1
7
+ data.tar.gz: 07b2fd98c22bc81c28587ca176d1d13b7a28729e74f2321bd72034f3f3b81ec4bb65059d0eb7d3a39cf3e927e86a3d6c33892cbdaacfc34c39b7e4e467214398
@@ -1,5 +1,5 @@
1
1
  module Stormfront
2
2
  module Rails
3
- VERSION = '0.10.6'
3
+ VERSION = '0.11.0'
4
4
  end
5
5
  end
@@ -8,34 +8,28 @@ Stormfront.Class = function(options) {
8
8
  this.initialize.apply(this, arguments);
9
9
  };
10
10
 
11
- Stormfront.Class.extend = function(protoProps) {
12
- function copyConstructor(base){
13
- return function(){ return base.apply(this, arguments); };
14
- }
15
- function copyBaseProperties(child, parent){
16
- _.extend(child, parent);
17
- }
18
- function carryPrototypeChain(child, parent){
19
- var Surrogate = function(){ this.constructor = child; };
20
- Surrogate.prototype = parent.prototype;
21
- child.prototype = new Surrogate;
22
- }
23
- function copyNewProperties(protoProps){
24
- _.extend(child.prototype, protoProps);
25
- }
26
- function enableAccessToBaseClass(){
27
- child.__super__ = parent.prototype;
28
- }
11
+ stormfront.enableModules = function (child, modules) {
12
+ _.each(modules, function(module){
13
+ stormfront.enableModules(child, module(child).dependencies);
14
+ });
15
+ };
29
16
 
17
+ stormfront.extend = function(properties){
30
18
  var parent = this;
31
- var child = copyConstructor(parent);
32
- copyBaseProperties(child, parent);
33
- carryPrototypeChain(child, parent);
34
- copyNewProperties(protoProps);
35
- enableAccessToBaseClass(child, parent);
19
+ var child = function() {
20
+ parent.apply(this, arguments);
21
+ stormfront.enableModules(this, properties.include);
22
+ return this;
23
+ };
24
+ _.extend(child, parent);
25
+ child.prototype = _.create(parent.prototype, properties);
26
+ child.prototype.constructor = child;
27
+ child.__super__ = parent.prototype;
36
28
  return child;
37
29
  };
38
30
 
31
+ Stormfront.Class.extend = stormfront.extend;
32
+
39
33
  stormfront.arguments = function(args){
40
34
  return new Stormfront.Arguments(args);
41
35
  };
@@ -172,6 +166,10 @@ Stormfront.Number = Stormfront.Class.extend({
172
166
  return this.number < value ? -1 : this.number > value ? 1 : 0;
173
167
  }
174
168
  });
169
+ Stormfront.Errors = {
170
+ FEEDBACK: 'An unexpected error was encountered'
171
+ };
172
+
175
173
  Stormfront.Response = Stormfront.Class.extend({
176
174
  initialize: function(xhr){
177
175
  this.xhr = xhr;
@@ -189,7 +187,6 @@ Stormfront.Response = Stormfront.Class.extend({
189
187
  return this.xhr.status === 401;
190
188
  },
191
189
  hasBeenAborted: function(){
192
- //TODO: consider xhr.status === 'abort'?
193
190
  return this.xhr.readyState != 4;
194
191
  },
195
192
  getError: function(){
@@ -284,15 +281,26 @@ Stormfront.Type = Stormfront.Class.extend({
284
281
  });
285
282
 
286
283
  Stormfront.Patterns = {
284
+ When: function (subject, methods) {
285
+ subject.when = subject.when || {};
286
+ _.each(methods, function (method) {
287
+ var actualMethod = subject[method];
288
+ subject[method] = function () {
289
+ var when = subject.when[method];
290
+ var value = actualMethod.apply(subject, arguments);
291
+ when && when.apply(subject, arguments);
292
+ return value;
293
+ }
294
+ });
295
+ subject.when.initialize && subject.when.initialize.apply(subject);
296
+ },
287
297
  Dispatcher: function (subject, dispatcher) {
288
- if (dispatcher) {
289
- subject.dispatch = function (event) {
290
- dispatcher.dispatch(event);
291
- };
292
- subject.getDispatcher = function(){
293
- return dispatcher;
294
- };
295
- }
298
+ subject.dispatch = function (event) {
299
+ dispatcher.dispatch(event);
300
+ };
301
+ subject.getDispatcher = function () {
302
+ return dispatcher;
303
+ };
296
304
  },
297
305
  Events: function (subject) {
298
306
  if (!subject.listenTo)
@@ -300,17 +308,12 @@ Stormfront.Patterns = {
300
308
 
301
309
  $.extend(subject, {
302
310
  forward: function (other, type) {
303
- function propagate(){
304
- subject.trigger.apply(subject, arguments);
305
- }
306
- subject.listenTo(other, type || 'all', propagate);
311
+ subject.listenTo(other, type || 'all', subject.trigger);
307
312
  }
308
313
  })
309
314
  }
310
315
  };
311
- Stormfront.Errors = {
312
- FEEDBACK: 'An unexpected error was encountered'
313
- };
316
+
314
317
 
315
318
  Stormfront.Dispatches = {
316
319
  RECEIVED: 'Dispatcher:Action:Received',
@@ -329,10 +332,10 @@ Stormfront.NO_CHANGE = 'Store:Nothing_Changed';
329
332
  Stormfront.Reducer = Stormfront.Class.extend({
330
333
  type: 'NOT:IMPLEMENTED',
331
334
  dependencies: [],
332
- initialize: function(dispatcher){
335
+ initialize: function (dispatcher) {
333
336
  Stormfront.Patterns.Dispatcher(this, dispatcher);
334
337
  },
335
- execute: function(store, event){
338
+ execute: function (store, event) {
336
339
  throw 'The reducer does not implement a function body'
337
340
  }
338
341
  });
@@ -577,7 +580,6 @@ Stormfront.Dispatcher = Stormfront.Class.extend({
577
580
  root.trigger(Stormfront.Dispatches.QUEUED, event);
578
581
  }
579
582
 
580
-
581
583
  function processQueue() {
582
584
  if (_.isEmpty(queue))
583
585
  return;
@@ -592,67 +594,37 @@ Stormfront.Dispatcher = Stormfront.Class.extend({
592
594
  }
593
595
  });
594
596
  Stormfront.Container = Stormfront.Class.extend({
595
- page: null,
596
- initial: null,
597
- reducers: [],
598
- initialize: function(location) {
597
+ initialize: function (reducers) {
599
598
  Stormfront.Patterns.Events(this);
600
- var dispatcher = new Stormfront.Dispatcher();
601
- var page = new this.page(dispatcher);
599
+ Stormfront.Patterns.Dispatcher(this, new Stormfront.Dispatcher());
600
+ var ursula = this.getDispatcher();
602
601
  var store = new Stormfront.Store({
603
- reducers: this.reducers,
604
- dispatcher: dispatcher
602
+ reducers: reducers,
603
+ dispatcher: ursula
605
604
  });
606
605
 
607
- function executeAction(action){
608
- store.executeReducer(action);
609
- }
610
- function updateView(action, reducer, newProperties, oldProperties){
611
- page.updateProperties(newProperties, oldProperties, action, reducer);
606
+ function execute (store) {
607
+ return function (action) {
608
+ store.executeReducer(action);
609
+ }
612
610
  }
613
- this.listenTo(dispatcher, Stormfront.Dispatches.READY, executeAction);
614
- this.listenTo(store, Stormfront.Dispatches.CHANGE, updateView);
615
611
 
616
- Stormfront.Patterns.Dispatcher(this, dispatcher);
617
- Stormfront.Patterns.Events(this);
618
-
619
- this.forward(dispatcher);
612
+ this.listenTo(ursula, Stormfront.Dispatches.READY, execute(store));
613
+ this.forward(ursula);
620
614
  this.forward(store);
621
-
622
- dispatcher.dispatch(SetStateAction(this.initial));
623
-
624
- location.html(page.render().$el);
625
-
626
- page.transition('attached');
627
- }
628
- });
629
-
630
- var homefront = { };
631
- var Homefront = {
632
- Patterns: {}
633
- };
634
-
635
- Homefront.Template = Stormfront.Class.extend({
636
- initialize: function (selector) {
637
- this.selector = selector;
638
615
  },
639
- render: function (vm) {
640
- function getTemplate(selector) {
641
- return $('#' + selector + '_template');
642
- }
643
- function compileTemplate(selection) {
644
- return Handlebars.compile(selection.html());
645
- }
646
- function expandTemplate(template, vm) {
647
- return template(vm);
648
- }
649
-
650
- var template = getTemplate(this.selector);
651
- var compiled = compileTemplate(template);
652
- return expandTemplate(compiled, vm)
616
+ start: function (initial) {
617
+ this.dispatch(SetStateAction(initial));
653
618
  }
654
619
  });
655
620
 
621
+ Homefront = {};
622
+ Homefront.Virtualize = require('virtual-html');
623
+ Homefront.Virtual = require('virtual-dom');
624
+ Homefront.Diff = Homefront.Virtual.diff;
625
+ Homefront.Patch = Homefront.Virtual.patch;
626
+ Homefront.Create = Homefront.Virtual.create;
627
+
656
628
  Homefront.Entity = Stormfront.Class.extend({
657
629
  defaults: null,
658
630
  initialize: function (properties) {
@@ -728,567 +700,73 @@ Homefront.Request = Stormfront.Ajax.Request.extend({
728
700
  }
729
701
  });
730
702
 
731
- Keys = {
732
- Enter: 13,
733
- LeftArrow: 37,
734
- DownArrow: 40,
735
- RightArrow: 39,
736
- UpArrow: 38,
737
- C: 67,
738
- R: 82,
739
- M: 77,
740
- Tab: 9,
741
- Override: 1000,
742
- Shift: 2000
703
+ Homefront.Templating = function (template, viewModel) {
704
+ return Handlebars.compile(template)(viewModel);
743
705
  };
744
-
745
- KeyboardEvents = Stormfront.Class.extend({
746
- initialize: function(){
747
- _.bindAll(this, 'onKeyDown');
748
- _.extend(this, Backbone.Events);
749
- $(window).on('keydown', this.onKeyDown);
750
- },
751
- onKeyDown: function(event){
752
- function isInput(node){
753
- switch(node){
754
- case 'SELECT':
755
- return true;
756
- case 'TEXTAREA':
757
- return true;
758
- case 'INPUT':
759
- return true;
760
- case 'BUTTON':
761
- return true;
762
- default:
763
- return false;
764
- }
765
- }
766
- var shift = event.shiftKey ? Keys.Shift : 0;
767
- var override = isInput(document.activeElement.nodeName) ? Keys.Override : 0;
768
- this.trigger(shift + override + event.which, event);
769
- },
770
- enterState: function(bindings){
771
- var self = this;
772
- this.off();
773
- function addBinding(value, key) {
774
- self.on(key, value);
706
+ Homefront.Rendering = function (html, events, context) {
707
+ return Homefront.Eventing(Homefront.Virtualize(html), events, context);
708
+ };
709
+ Homefront.Eventing = function (view, events, context) {
710
+ function delegate (handler) {
711
+ return function () {
712
+ handler.apply(context, arguments);
775
713
  }
776
- _.each(bindings, addBinding);
777
- },
778
- close: function(){
779
- $(window).off('keydown', this.onKeyDown);
780
- this.off('all');
781
714
  }
782
- });
783
- MouseEvents = Stormfront.Class.extend({
784
- initialize: function(options){
785
- options = _.extend({delay: 175}, options);
786
- this.delay = options.delay ? options.delay : 175;
787
- this.public = _.clone(Backbone.Events);
788
- this.internal = _.clone(Backbone.Events);
789
- },
790
- listen: function(target){
791
- this.$el = target;
792
- this.$el.global = $(document);
793
- this.el = this.$el[0];
794
-
795
- var self = this;
796
- function enterStandardEventMode() {
797
- self.$el.on('wheel.me', handleMouseWheel);
798
- self.$el.on('mousewheel.me', handleMouseWheel);
799
- self.$el.one('mousedown.me', handleFirstMouseDown);
800
-
801
- function handleFirstMouseDown(eventArgs) {
802
- self.$el.one('mousemove.me', enterDraggingMode);
803
-
804
- self.$el.one('mousedown.me', handleSubsequentMouseDown);
805
- self.internal.once("special:single-click:down", function() { handleSpecialMouseDown(eventArgs)});
806
- self.$el.global.one('mouseup.me', handleFirstMouseUp);
807
- delay("special:single-click:down", eventArgs);
808
- }
809
-
810
- function handleFirstMouseUp(eventArgs) {
811
- self.$el.off('mousemove.me');
812
- self.internal.once("special:single-click:up", function() { handleSpecialMouseUp(eventArgs); });
813
- delay("special:single-click:up", eventArgs);
814
- }
815
715
 
816
- function delay(event, eventArgs){
817
- setTimeout(function() { publishInternalEvent(event, eventArgs);}, self.delay);
818
- }
819
-
820
- function handleSpecialMouseDown(eventArgs) {
821
- self.$el.off('mousedown.me');
822
- self.$el.one('mousedown.me', handleFirstMouseDown);
823
- publishExternalEvent("single-click:down", eventArgs);
824
- }
825
-
826
- function handleSpecialMouseUp(eventArgs) {
827
- publishExternalEvent("single-click:up", eventArgs);
828
- }
829
-
830
- function handleSubsequentMouseDown(eventArgs) {
831
- self.internal.off("special:single-click:down");
832
- self.$el.one('mousedown.me', handleFirstMouseDown);
833
- self.$el.global.one('mouseup.me', handleSubsequentMouseUp);
834
- publishExternalEvent("double-click:down", eventArgs);
835
- }
836
-
837
- function handleSubsequentMouseUp(eventArgs) {
838
- self.internal.off("special:single-click:up");
839
- publishExternalEvent("double-click:up", eventArgs);
840
- }
841
-
842
- function handleMouseWheel(eventArgs) {
843
- publishExternalEvent("mousewheel", eventArgs);
844
- }
845
- }
846
-
847
- function exitStandardEventMode() {
848
- self.$el.off('mousedown.me');
849
- self.$el.global.off('mouseup.me');
850
- self.$el.off('mousemove.me');
851
- self.$el.off('wheel.me');
852
- self.$el.off('mousewheel.me');
853
- self.internal.off("special:single-click:down");
854
- self.internal.off("special:single-click:up");
855
- }
856
-
857
- function enterDraggingMode(eventArgs) {
858
- function handleMouseMove(eventArgs) {
859
- publishExternalEvent("dragging:move", eventArgs);
860
- }
861
-
862
- function handleMouseUp(eventArgs) {
863
- publishExternalEvent("dragging:end", eventArgs);
864
- exitDraggingMode();
865
- enterStandardEventMode();
866
- }
867
-
868
- exitStandardEventMode();
869
- publishExternalEvent("dragging:start", eventArgs);
870
- self.$el.global.on('mousemove.me', handleMouseMove);
871
- self.$el.global.one('mouseup.me', handleMouseUp);
872
- }
873
-
874
- function exitDraggingMode() {
875
- self.$el.off('mouseup.me');
876
- self.$el.global.off('mousemove.me');
877
- self.$el.global.off('mousedown.me');
878
- }
879
-
880
- function disableUnsupportedEvents() {
881
- self.$el.global.on('selectstart.me', function(eventArgs) {
882
- eventArgs.preventDefault();
883
- eventArgs.stopPropagation();
884
- return false; });
885
- self.$el.on("contextmenu.me", function(eventArgs) {
886
- eventArgs.preventDefault();
887
- eventArgs.stopPropagation();
888
- return false; });
889
- }
890
-
891
- function publishInternalEvent(event, eventArgs){
892
- publishEvent(self.internal, event, eventArgs);
893
- }
894
- function publishExternalEvent(event, eventArgs){
895
- publishEvent(self.public, event, eventArgs);
896
- }
897
- function publishEvent(publisher, event, eventArgs){
898
- function getMousePosition(eventArgs) {
899
- var offset = self.$el.offset();
900
- var relativeX = eventArgs.originalEvent.pageX - offset.left;
901
- var relativeY = eventArgs.originalEvent.pageY - offset.top;
902
- eventArgs.preventDefault();
903
- eventArgs.stopPropagation();
904
- return {
905
- x: relativeX,
906
- y: relativeY
907
- };
908
- }
909
- var position = getMousePosition(eventArgs);
910
- publisher.trigger(event, position, eventArgs.originalEvent);
911
- }
912
-
913
- enterStandardEventMode();
914
- disableUnsupportedEvents();
915
- },
916
- on: function(event, callback){
917
- this.public.on(event, callback);
918
- return this;
919
- },
920
- off: function(event ,callback){
921
- this.public.off(event, callback);
922
- return this;
923
- },
924
- stopListening: function(){
925
- this.$el && this.$el.off('.me');
926
- this.$el.global && this.$el.global.off('.me');
927
- }
928
- });
929
- Homefront.Errors = {
930
- FEEDBACK: 'An unexpected error was encountered',
931
- /** @return {string} */
932
- NO_SELECTOR: function() { return 'A template selector was not provided for your view' },
933
- /** @return {string} */
934
- NO_TEMPLATE: function(name) { return name +'\'s template was not found'; },
935
- /** @return {string} */
936
- INCOMPATIBLE_TEMPLATE: function(name) { return name +'\'s template and view model for your view are not compatible'; },
937
- /** @return {string} */
938
- VIEW_MODEL: function(name) { return name + '\'s context generated an error'; },
939
- /** @return {string} */
940
- NO_LOCATION: function(name) { return name + ' has no locations available to render'; },
941
- /** @return {string} */
942
- MULTIPLE_LOCATIONS: function(name) { return name + ' has multiple locations available to render'; },
943
- /** @return {string} */
944
- INITIALIZING: function(name) { return name + ' failed to initialize'; },
945
- /** @return {string} */
946
- RENDERING: function(name) { return name + ' failed to render'; },
947
- /** @return {string} */
948
- ATTACHING: function(name) { return name + ' failed to attach'; },
949
- /** @return {string} */
950
- CLOSING: function(name) { return name + ' failed to close'; },
951
- /** @return {string} */
952
- ADDING: function(name) { return name + ' failed to add'; }
716
+ _.each(events, function (handler, key) {
717
+ view.properties['on' + key] = delegate(handler);
718
+ });
719
+ return view;
953
720
  };
954
721
 
955
- Homefront.ViewBase = Backbone.View.extend({
956
- location: null,
957
- template: null,
958
- render: function () {
959
- try {
960
- var context = this.getContext();
961
- if (this.template)
962
- this.$el.html(new Homefront.Template(this.template).render(context));
963
- } catch (e) {
964
- this.$el.html('An error was encountered');
965
- console.error('Failed to render view');
966
- console.error(e);
967
- }
968
- return this;
969
- },
970
- getContext: function(){
971
- return this.properties ? this.properties : { };
972
- },
973
- close: function () {
974
- this.remove();
975
- }
976
- });
977
- Homefront.View = Homefront.ViewBase.extend({
978
- when: {},
722
+ Homefront.Base = Stormfront.Class.extend({
979
723
  initialize: function (dispatcher) {
980
- _.each(this.when, this.addSubscriber, this);
981
- this.addPublisher(this);
982
- this.transition('before:initializing');
983
724
  Stormfront.Patterns.Dispatcher(this, dispatcher);
984
- this.transition('initializing');
985
- },
986
- render: function () {
987
- this.transition('before:rendering');
988
- Homefront.ViewBase.prototype.render.call(this);
989
- this.transition('rendering');
990
- return this;
725
+ Stormfront.Patterns.When(this, ['initialize', 'render', 'attached']);
991
726
  },
992
- renderAgain: function(){
993
- this.render();
994
- this.transition('attached');
995
- },
996
- addPublisher: function (publisher, identity) {
997
- function notify(event) {
998
- var args = stormfront.arguments(arguments).skip(1).get();
999
- function executeHandler(subscriber) {
1000
- var handler = stormfront.hash(subscriber).findNestedValue(event.split(':'));
1001
- try {
1002
- if (_.isFunction(handler))
1003
- handler.apply(this, args);
1004
- } catch (e) {
1005
- console.error('Error encountered within the When block: ('+event+')');
1006
- console.error(e);
1007
- }
1008
- }
1009
-
1010
- _.each(this._subscribers, executeHandler, this);
1011
- }
1012
-
1013
- function prepend(identity) {
1014
- return function (event) {
1015
- var newEvent = identity + ':' + event;
1016
- var args = stormfront.arguments(arguments).skip(1).prepend(newEvent).get();
1017
- notify.apply(this, args);
1018
- }
1019
- }
1020
-
1021
- if (publisher === this)
1022
- this.listenTo(publisher, 'transition', notify);
1023
- else
1024
- this.listenTo(publisher, 'transition', prepend(identity));
1025
- },
1026
- addSubscriber: function (whenBlock) {
1027
- this._subscribers = this._subscribers || [];
1028
- if (whenBlock && !_.isEmpty(whenBlock))
1029
- this._subscribers.push(whenBlock);
1030
- },
1031
- transition: function () {
1032
- this.trigger.apply(this, stormfront.arguments(arguments).prepend('transition').get());
1033
- },
1034
- updateProperties: function (properties) {
1035
- var previous = this.properties;
1036
- this.properties = this.selectProperties(properties);
1037
- this.transition('updating', this.properties, previous);
1038
- },
1039
- selectProperties: function (properties) {
727
+ render: function(properties){
728
+ // return a v-tree to have
729
+ // it rendered to the screen
730
+ this.properties = properties;
1040
731
  return properties;
1041
732
  },
1042
- close: function () {
1043
- this.transition('before:closing');
1044
- this.transition('closing');
1045
- Homefront.ViewBase.prototype.close.call(this);
733
+ attached: function (dom) {
734
+ this.dom = dom;
1046
735
  }
1047
736
  });
1048
-
1049
- Homefront.View.extend = function(protoProps){
1050
- function copyConstructor(base){
1051
- return function(){ return base.apply(this, arguments); };
1052
- }
1053
- function copyBaseProperties(child, parent){
1054
- _.extend(child, parent);
1055
- }
1056
- function carryPrototypeChain(child, parent){
1057
- var Surrogate = function(){ this.constructor = child; };
1058
- Surrogate.prototype = parent.prototype;
1059
- child.prototype = new Surrogate;
1060
- }
1061
- function copyNewProperties(child, protoProps){
1062
- var newWhen = protoProps['when'];
1063
- var oldWhen = child.prototype['when'];
1064
-
1065
- _.extend(child.prototype, protoProps);
1066
-
1067
- var when = [];
1068
- oldWhen && when.push(oldWhen);
1069
- newWhen && when.push(newWhen);
1070
- child.prototype['when'] = _.flatten(when);
1071
- }
1072
- function enableAccessToBaseClass(){
1073
- child.__super__ = parent.prototype;
1074
- }
1075
-
1076
- var parent = this;
1077
- var child = copyConstructor(parent);
1078
- copyBaseProperties(child, parent);
1079
- carryPrototypeChain(child, parent);
1080
- copyNewProperties(child, protoProps);
1081
- enableAccessToBaseClass(child, parent);
1082
- return child;
1083
- };
1084
-
1085
- Homefront.Alert = Homefront.View.extend({
1086
- className: 'alert',
1087
- events: {
1088
- 'click .close': 'dismiss'
1089
- },
1090
- render: function(){
1091
- var errors = this.properties.errors || [];
1092
- var content = $('<div>');
1093
- var summary = $('<p>').addClass('summary').text(Stormfront.Errors.FEEDBACK);
1094
- var details = $('<p>').addClass('errors').text(errors.join(', '));
1095
- var close = $('<div>').addClass('close').attr('title', 'click to close');
1096
- content.append(summary).append(details).append(close);
1097
- this.$el.html(content);
1098
- this.transitionAs('rendering', arguments);
1099
- return this;
1100
- },
1101
- dismiss: function(){
1102
- this.trigger('dismissed');
1103
- this.close();
1104
- }
1105
- });
1106
- Homefront.Overlay = Stormfront.Class.extend({
1107
- initialize: function(options){
1108
- var selector = options.selector;
1109
-
1110
- if (!selector)
1111
- this.overlay = new Homefront.FullScreenOverlay({model: options});
1112
- else if (options.saveRequest)
1113
- this.overlay = new Homefront.InlineOverlay();
1114
- else
1115
- this.overlay = new Homefront.AnonymousOverlay();
1116
-
1117
- selector = selector ? selector : document.body;
1118
- this.location = selector.size ? selector : $(selector);
1119
- this.render();
1120
- },
1121
- render: function(){
1122
- this.location.append(this.overlay.render().$el);
1123
- this.overlay.transition('attached');
1124
- return this;
1125
- },
1126
- close: function(){
1127
- this.overlay.close();
1128
- this.location = null;
1129
- },
1130
- error: function(){
1131
- this.overlay.error.apply(this.overlay, arguments);
1132
- }
1133
- });
1134
-
1135
- Homefront.OverlayBase = Homefront.View.extend({
1136
- className: 'overlay',
1137
- activated: false,
1138
- PAUSE_DURATION: 0,
1139
- MINIMUM_DURATION: 0,
1140
- base_css: {
1141
- overlay_background: {
1142
- top: '0px', left: '0px',
1143
- width: '100%', height: '100%'
1144
- },
1145
- overlay_panel: {
1146
- position: 'absolute',
1147
- top: '50%', left: '50%'
1148
- }
1149
- },
1150
- base: {
1151
- rendering: function(){
1152
- function applyCss(value, key){
1153
- var selector = '.' + key;
1154
- this.$(selector).css(value);
1155
- }
1156
- this.startTime = stormfront.time().now();
1157
- _.each(this.base_css, applyCss, this);
1158
- _.each(this.css, applyCss, this);
1159
- this.$el.css({opacity: '0', 'pointer-events': 'none'});
1160
- },
1161
- attached: function(){
1162
- var self = this;
1163
- function activate(){
1164
- self.$el.css({opacity: '1', 'pointer-events': 'auto'});
1165
- self.activated = true;
1166
- }
1167
- function setDimensions(panel){
1168
- var content = self.$('.content');
1169
- var position = {
1170
- 'margin-left': - content.outerWidth() / 2,
1171
- 'margin-top': - content.outerHeight() / 2
1172
- };
1173
- panel.css(position);
1174
- }
1175
- setDimensions(this.$('.overlay_panel'));
1176
- if (this.PAUSE_DURATION)
1177
- setTimeout(activate, this.PAUSE_DURATION);
1178
- else
1179
- activate();
1180
- },
1181
- closing: function(){
1182
- var self = this;
1183
- function remove(){
1184
- self.remove();
1185
- }
1186
- if (!this.activated)
1187
- this.remove();
1188
-
1189
- var currentDuration = stormfront.time().now() - this.startTime;
1190
- var remainingDuration = this.MINIMUM_DURATION - currentDuration;
1191
- if (remainingDuration > 0)
1192
- setTimeout(remove, remainingDuration);
1193
- else
1194
- this.remove();
1195
- }
737
+ Homefront.View = Homefront.Base.extend({
738
+ template: '<div></div>',
739
+ templating: Homefront.Templating,
740
+ rendering: Homefront.Rendering,
741
+
742
+ render: function (properties) {
743
+ this.properties = properties;
744
+ this.context = this.getContext(properties);
745
+ this.html = this.templating(this.template, this.context);
746
+ this.setNode(this.rendering(this.html, this.events, this));
747
+ return this.getNode();
748
+ },
749
+ getContext: function (properties) {
750
+ return properties;
1196
751
  },
1197
- initialize: function(){
1198
- this.addSubscriber(this.base);
1199
- Stormfront.View.prototype.initialize.apply(this, arguments);
752
+ getNode: function(){
753
+ return this.node;
1200
754
  },
1201
- error: function(){
1202
- this.remove();
755
+ setNode: function(node){
756
+ this.node = node;
1203
757
  },
1204
- close: function(){
1205
- this.transition.apply(this, stormfront.arguments(arguments).prepend('closing').get());
1206
- }
1207
- });
1208
758
 
1209
- Homefront.FullScreenOverlay = Homefront.OverlayBase.extend({
1210
- MINIMUM_DURATION: 900,
1211
- css: {
1212
- overlay_background: {
1213
- position: 'fixed',
1214
- 'z-index': '100000'
1215
- },
1216
- overlay_panel: {
1217
- 'z-index': '100001'
1218
- }
1219
- },
1220
- when: {
1221
- rendering: function(){
1222
- this.$el.addClass('blocking');
1223
- }
1224
- }
1225
- });
1226
-
1227
- Homefront.AnonymousOverlay = Homefront.OverlayBase.extend({
1228
- PAUSE_DURATION: 200,
1229
- MINIMUM_DURATION: 450,
1230
- css: {
1231
- overlay_background: {
1232
- position: 'absolute',
1233
- 'z-index': 'auto'
1234
- },
1235
- overlay_panel: {
1236
- 'z-index': 'auto'
1237
- }
1238
- },
1239
- when: {
1240
- rendering: function(){
1241
- this.$el.addClass('anonymous');
1242
- }
759
+ attached: function (dom) {
760
+ this.dom = dom;
1243
761
  }
1244
762
  });
1245
763
 
1246
- Homefront.InlineOverlay = Homefront.OverlayBase.extend({
1247
- className: 'input_overlay',
1248
- MINIMUM_DURATION: 1500,
1249
- MAXIMUM_WIDTH: 1200,
1250
- base_css: {
1251
- input: {
1252
- position: 'absolute',
1253
- top: '2px',
1254
- right: '10px',
1255
- width:'16px',
1256
- 'z-index':'10000'
1257
- }
1258
- },
1259
- when: {
1260
- rendering: function () {
1261
- this.$el.find('.error').hide();
1262
- this.$el.find('.confirm').hide();
1263
- },
1264
- closing: function(){
1265
- this.$el.find('.spinner').hide();
1266
- this.$el.find('.confirm').show();
1267
- }
1268
- },
1269
- error: function (xhr) {
1270
- //TODO: Elevate this code up a level to the Request
1271
- try {
1272
- var response = JSON.parse(xhr.responseText);
1273
- var error = response.error || response.message;
1274
- this.$el.find('.spinner').hide();
1275
- this.$el.find('.error').show().attr('title', error);
1276
- xhr.handled = true;
1277
- }
1278
- catch (e) {
1279
- console.warn('Could not parse error', arguments);
1280
- this.remove();
1281
- }
1282
- }
1283
- });
1284
764
  Homefront.Guidance = {
1285
765
  Generic: function (type, text) {
1286
- return Homefront.Text.extend({
1287
- tagName: type,
1288
- className: 'guidance',
1289
- text: text,
1290
- selectProperties: function () {
1291
- return {value: this.text}
766
+ return Homefront.View.extend({
767
+ template: '<{{type}} class="guidance">{{text}}</{{type}}>',
768
+ getContext: function () {
769
+ return {type: type, text: text}
1292
770
  }
1293
771
  });
1294
772
  },
@@ -1304,526 +782,274 @@ Homefront.Guidance = {
1304
782
  }
1305
783
  };
1306
784
 
1307
- Homefront.Chaperone = Homefront.View.extend({
1308
- method: 'append',
1309
- when: {
1310
- initializing: function () {
1311
- this._children = [];
785
+ Homefront.Empty = { tagName: '', children: [] };
786
+
787
+ Homefront.VirtualGateway = function(view) {
788
+ function getProperties(node){
789
+ return node ? node.properties || {} : {};
790
+ }
791
+ function getClass(node){
792
+ return getProperties(node).class || '';
793
+ }
794
+ function hasClass(node, className){
795
+ return (_.contains(getClass(node).split(' '), className));
796
+ }
797
+ function find(node, className){
798
+ if (hasClass(node, className))
799
+ return node;
800
+ var candidate = Homefront.Empty;
801
+ _.find(node.children, function(child){
802
+ candidate = find(child, className);
803
+ return candidate !== Homefront.Empty;
804
+ });
805
+ return candidate;
806
+ }
807
+ function findParent(node, className){
808
+ var candidate = Homefront.Empty;
809
+ _.find(node.children, function(child){
810
+ if (hasClass(child, className))
811
+ candidate = node;
812
+ else
813
+ candidate = findParent(child, className);
814
+ return candidate !== Homefront.Empty;
815
+ });
816
+ return candidate;
817
+ }
818
+ return _.extend(view, {
819
+ hasClass: function(className){
820
+ return hasClass(view.getNode(), className);
1312
821
  },
1313
- updating: function (properties) {
1314
- this.updateChildren(this._children, properties);
822
+ find: function (location) {
823
+ return find(view.getNode(), location);
1315
824
  },
1316
- attached: function () {
1317
- var previous = this._children;
1318
- this._children = [];
1319
- this.createChildren();
1320
- this.renderChildren(this._children);
1321
- this.attachChildren(this._children);
1322
- this.closeChildren(previous);
825
+ parent: function(location) {
826
+ return findParent(view.getNode(), location);
1323
827
  },
1324
- closing: function () {
1325
- this.closeChildren(this._children);
1326
- this._children = [];
828
+ replace: function (location, node) {
829
+ var child = find(view.getNode(), location);
830
+ var parent = findParent(view.getNode(), location);
831
+ var index = _.indexOf(parent.children, child);
832
+ parent.children[index] = node;
1327
833
  },
1328
- chaperone: {
1329
- create: function (child, properties) {
1330
- var type = stormfront.type(child);
1331
- properties = _.isObject(properties) ? properties : this.properties;
1332
-
1333
- if (type)
1334
- this.transition('chaperone:add', new type(this.getDispatcher()), properties);
1335
- else
1336
- console.error('Child type does not exist: ', child);
1337
- },
1338
- add: function (child, properties) {
1339
- this._children.push(child);
1340
- child.transition && this.addPublisher(child, 'child');
1341
- child.updateProperties(properties);
1342
- },
1343
- attach: function (child, location, method) {
1344
- child.transition('attaching', child);
1345
- location[method](child.$el);
1346
- child.transition('attached', child);
1347
- }
1348
- },
1349
- child: {
1350
- closing: function (child) {
1351
- this._children.splice(this._children.indexOf(child), 1);
1352
- this.stopListening(child);
1353
- }
1354
- }
1355
- },
1356
- createChild: function (type, properties) {
1357
- this.transition('chaperone:create', type, properties);
1358
- },
1359
- attachChild: function (child, location, method) {
1360
- this.transition('chaperone:attach', child, location, method || this.method);
1361
- },
1362
- createChildren: function () {
1363
-
1364
- },
1365
- renderChildren: function (children) {
1366
- _.invoke(children, 'render');
1367
- },
1368
- attachChildren: function (children) {
1369
- function attachChild(child) {
1370
- if (child.location)
1371
- this.attachChild(child, this.$('.' + child.location));
834
+ append: function(node, location){
835
+ if (location)
836
+ find(view.getNode(), location).children.push(node);
1372
837
  else
1373
- this.attachChild(child, this.$el, 'append');
1374
- }
1375
-
1376
- _.each(children, attachChild, this);
1377
- },
1378
- updateChildren: function (children, properties) {
1379
- _.invoke(children, 'updateProperties', properties);
1380
- },
1381
- closeChildren: function (children) {
1382
- function stop(child) {
1383
- this.stopListening(child);
838
+ view.getNode().children.push(node);
1384
839
  }
840
+ });
841
+ };
1385
842
 
1386
- //TODO: This bit is odd...
1387
- _.each(children, stop, this);
1388
- _.invoke(children, 'close');
1389
- },
1390
- at: function (index) {
1391
- return this._children[index];
1392
- }
1393
- });
1394
- Homefront.Layout = Homefront.Chaperone.extend({
1395
- method: 'replaceWith',
1396
- createChildren: function () {
1397
- _.each(this.children, this.createChild, this);
1398
- }
1399
- });
1400
- Homefront.Switch = Homefront.Chaperone.extend({
1401
- when: {
1402
- updating: function () {
1403
- if (this._state !== undefined && this.stateChanged())
1404
- this.renderAgain();
1405
- }
1406
- },
1407
- getCases: function () {
1408
- var feedback = '"getState" and "getCases" are not implemented';
1409
- var guidance = Homefront.Guidance.Paragraph(feedback);
1410
- return {
1411
- not_implemented: guidance
1412
- };
1413
- },
1414
- getState: function () {
1415
- return 'not_implemented'
1416
- },
1417
- stateChanged: function(){
1418
- return this._state !== this.getState(this.properties);
1419
- },
1420
- updateState: function () {
1421
- var oldState = this._state;
1422
- var newState = this.getState(this.properties);
1423
- this._state = newState;
843
+ Homefront.Chaperone = function(child){
844
+ _.extend(child, {
845
+ default: Homefront.Guidance.Paragraph,
846
+ createChild: function (name) {
847
+ var type = stormfront.type(name);
848
+ return (type) ?
849
+ new type(this.getDispatcher()) :
850
+ this.guidance('View was not found: ' + name);
851
+ },
852
+ renderChild: function (child, properties) {
853
+ return child.render(properties || this.properties);
854
+ },
855
+ appendChild: function (child, location) {
856
+ this.append(child, location);
857
+ },
858
+ attachChild: function (child, location) {
859
+ this.replace(location, child);
860
+ },
861
+ //todo: when a view wants to render two children
1424
862
 
1425
- if (oldState !== newState) {
1426
- oldState && this.transition('exiting:' + oldState, oldState);
1427
- this.transition('entering:' + newState, newState);
1428
- } else {
1429
- oldState && this.transition('staying:' + oldState, oldState);
1430
- }
1431
- return newState;
1432
- },
1433
- createChildren: function () {
1434
- var cases = this.getCases();
1435
- var state = this.updateState();
1436
- var candidate = cases[state];
1437
- candidate && this.createChild(candidate);
1438
- },
1439
- attachChildren: function (children) {
1440
- if (children.length === 1) {
1441
- var candidate = children[0];
1442
- candidate.$el.addClass(this.className);
1443
- candidate.$el.addClass(this._state);
1444
- this.attachChild(candidate, this.$el, 'replaceWith');
1445
- this.setElement(candidate.el);
863
+ guidance: function (text) {
864
+ return new (this.default(text))();
1446
865
  }
1447
- }
1448
- });
866
+ });
1449
867
 
1450
- Homefront.Expandable = Homefront.Switch.extend({
1451
- summary: null,
1452
- details: null,
1453
- expanded: false,
1454
- getCases: function () {
1455
- return {
1456
- summary: this.summary,
1457
- details: this.details
1458
- };
1459
- },
1460
- getState: function () {
1461
- return this.expanded ? 'details' : 'summary';
1462
- },
1463
- expand: function () {
1464
- this.expanded = true;
1465
- this.renderAgain();
1466
- },
1467
- collapse: function () {
1468
- this.expanded = false;
1469
- this.renderAgain();
868
+ return {
869
+ dependencies: [Homefront.VirtualGateway]
1470
870
  }
1471
- });
1472
- Homefront.Enumerator = Homefront.Chaperone.extend({
1473
- item: null,
871
+ };
872
+ Homefront.Layout = Homefront.View.extend({
873
+ include: [Homefront.Chaperone],
874
+ children: [],
1474
875
  when: {
1475
- chaperone: {
1476
- add: function (child) {
1477
- child.location = this.item.location;
1478
- }
876
+ render: function () {
877
+ this.appendChildren(this.children);
1479
878
  }
1480
879
  },
1481
- createChildren: function () {
1482
- function createChild(item) {
1483
- this.createChild(this.item.view, item);
1484
- }
1485
-
1486
- _.each(this.selectItems(this.properties), createChild, this);
1487
- },
1488
- updateChildren: function (children, properties) {
1489
- function updateWith(items) {
1490
- return function(child, index) {
1491
- var item = items[index];
1492
- child.updateProperties(item);
1493
- }
1494
- }
1495
-
1496
- _.each(children, updateWith(this.selectItems(properties)));
1497
- },
1498
- composeChild: function (item) {
1499
- return this.createChild(this.item, item);
1500
- },
1501
- selectItems: function (properties) {
1502
- return properties;
1503
- },
1504
- at: function (index) {
1505
- return this._children[index];
880
+ appendChildren: function(types){
881
+ _.each(types, function(type){
882
+ var child = this.createChild(type);
883
+ var view = this.renderChild(child);
884
+ this.appendChild(view);
885
+ }, this);
1506
886
  }
1507
887
  });
1508
- Homefront.List = Homefront.Switch.extend({
1509
- item: null,
888
+
889
+ Homefront.Template = Homefront.View.extend({
890
+ include: [Homefront.Chaperone],
891
+ children: {},
1510
892
  when: {
1511
- initializing: function () {
1512
- this.enumerator = Homefront.Enumerator.extend({
1513
- tagName: this.tagName,
1514
- template: this.template,
1515
- className: this.className + ' stormfront.enumerator',
1516
- item: this.item,
1517
- getContext: this.getContext,
1518
- selectItems: this.selectItems
1519
- });
893
+ render: function () {
894
+ this.attachChildren(this.children);
1520
895
  }
1521
896
  },
1522
- getCases: function () {
1523
- return {
1524
- empty: this.empty,
1525
- populated: this.enumerator
1526
- }
1527
- },
1528
- getState: function (properties) {
1529
- var items = this.selectItems(properties);
1530
- return items && items.length > 0 ? 'populated' : 'empty';
1531
- },
1532
- selectItems: function (properties) {
1533
- return properties.list ? properties.list() : properties;
897
+ attachChildren: function(types){
898
+ _.each(types, function(type, location){
899
+ var child = this.createChild(type);
900
+ var view = this.renderChild(child);
901
+ this.attachChild(view, location);
902
+ }, this);
1534
903
  }
1535
904
  });
1536
- //TODO: This should have a better name I suppose
1537
- Homefront.ActiveList = Homefront.List.extend({
1538
- getCases: function () {
1539
- //lazy shortcut
1540
- this.populated = this.enumerator;
1541
- return this;
905
+ Homefront.Switch = Homefront.Base.extend({
906
+ cases: {},
907
+ include: [Homefront.Chaperone],
908
+ render: function (properties) {
909
+ this.properties = properties;
910
+ return this.createCase(this.getState(properties)).render(properties);
1542
911
  },
1543
912
  getState: function (properties) {
1544
- var state = properties.state;
1545
- if (state === Stormfront.Ajax.SUCCESS)
1546
- //TODO: Fetching inventory can return an error in the data
1547
- return this.selectItems(properties).length === 0 ? 'empty' : properties.data.error ? 'error' : 'populated';
1548
- else if (state === Stormfront.Ajax.START)
1549
- return 'requesting';
1550
- else if (state === Stormfront.Ajax.ERROR)
1551
- return 'error';
1552
- return state;
1553
- },
1554
- selectItems: function(properties) {
1555
- return properties.data
1556
- }
1557
- });
1558
-
1559
- //TODO: Got two of them now?
1560
- Homefront.Series = Homefront.List.extend({
1561
- getState: function (properties) {
1562
- var state = properties.state();
1563
- if (state === Stormfront.Ajax.SUCCESS) {
1564
- var items = this.selectItems(properties);
1565
- return items && items.length > 0 ? 'populated' : 'empty';
1566
- }
1567
- return state;
913
+ return properties;
1568
914
  },
1569
- selectItems: function (properties) {
1570
- return properties.list();
915
+ createCase: function(state){
916
+ var candidate = this.cases[state];
917
+ return (candidate) ?
918
+ this.createChild(candidate) :
919
+ this.guidance('Case was not found for state: ' + state);
1571
920
  }
1572
921
  });
1573
- Homefront.Patterns.Selectable = function(method, action){
1574
- var events = {};
1575
- events[method] = 'select';
1576
- return {
1577
- events: events,
1578
- action: action,
1579
- select: function(){
1580
- var action = stormfront.type(this.action);
1581
- this.dispatch(new action(this.properties));
1582
- }
1583
- };
1584
- };
1585
-
1586
- Homefront.SelectableList = Homefront.Enumerator.extend({
1587
- className: 'options',
922
+ Homefront.Collection = Homefront.Switch.extend({
923
+ loading: null,
1588
924
  item: null,
1589
- select: null,
1590
- method: 'click',
925
+ empty: null,
926
+ error: null,
1591
927
  when: {
1592
- initializing: function(){
1593
- var item = stormfront.type(this.item);
1594
- this.item = {
1595
- view: item.extend(Homefront.Patterns.Selectable(this.method, this.select))
1596
- };
1597
- }
1598
- },
1599
- selectItems: function (properties) {
1600
- return properties.list();
1601
- }
1602
- });
1603
-
1604
- Homefront.SelectableDisplay = Homefront.Switch.extend({
1605
- className: 'selected',
1606
- select: null,
1607
- guidance: '',
1608
- display: null,
1609
- getCases: function() {
1610
- return {
1611
- none: Homefront.Guidance.Paragraph(this.guidance),
1612
- selected: this.display
1613
- };
1614
- },
1615
- when: {
1616
- entering: {
1617
- none: function(){
1618
- var entity = this.properties;
1619
- if (entity.onlyOne()) {
1620
- var action = stormfront.type(this.select);
1621
- this.dispatch(new action(entity.first()));
1622
- }
928
+ initialize: function(){
929
+ this.cases = {
930
+ loading: this.loading,
931
+ error: this.error,
932
+ populated: Homefront.List.extend({
933
+ template: this.template,
934
+ empty: this.empty,
935
+ item: this.item,
936
+ selectList: this.selectList
937
+ })
1623
938
  }
1624
- },
1625
- updating: function(){
1626
- this.render();
1627
939
  }
1628
940
  },
1629
- getState: function(properties){
1630
- return properties.selected() ? 'selected' : 'none';
941
+ getState: function (properties) {
942
+ switch(properties.state) {
943
+ case Stormfront.Ajax.START:
944
+ return 'loading';
945
+ case Stormfront.Ajax.PENDING:
946
+ return 'loading';
947
+ case Stormfront.Ajax.SUCCESS:
948
+ return 'populated';
949
+ case Stormfront.Ajax.ERROR:
950
+ return 'error';
951
+ case Stormfront.Ajax.ABORTED:
952
+ return 'error';
953
+ default:
954
+ return properties.state;
955
+ }
956
+ },
957
+ selectList: function (properties) {
958
+ return properties.list;
1631
959
  }
1632
960
  });
1633
-
1634
- //TODO: Could be a list or a series.
1635
- Homefront.Selection = Homefront.Switch.extend({
1636
- className: 'selection',
961
+ Homefront.List = Homefront.View.extend({
962
+ include: [Homefront.Chaperone],
1637
963
  item: null,
1638
- select: null,
1639
- method: 'click',
1640
- display: null,
1641
- none: '',
1642
- initial: '',
1643
- empty: '',
1644
- list: null,
1645
- adapter: null,
964
+ empty: null,
1646
965
  when: {
1647
- initializing: function(){
1648
- this.selectList = Homefront.SelectableList.extend({
1649
- item: this.item,
1650
- select: this.select,
1651
- method: this.method || 'click'
1652
- });
1653
- this.selectDisplay = Homefront.SelectableDisplay.extend({
1654
- select: this.select,
1655
- display: this.display,
1656
- guidance: this.none
1657
- });
966
+ render: function () {
967
+ this.renderList(this.selectList(this.properties));
1658
968
  }
1659
969
  },
1660
- getCases: function(){
1661
- return {
1662
- initial: Homefront.Guidance.Paragraph(this.initial),
1663
- empty: Homefront.Guidance.Paragraph(this.empty),
1664
- populated: Homefront.Layout.extend({
1665
- children: [this.selectList, this.selectDisplay]
1666
- })
1667
- }
970
+ selectList: function (properties) {
971
+ return properties;
1668
972
  },
1669
- getState: function (properties) {
1670
- var state = properties.state();
1671
- if (state === Stormfront.Ajax.SUCCESS)
1672
- return properties.isEmpty() ? 'empty' : 'populated';
1673
- return state;
1674
- },
1675
- selectProperties: function(properties){
1676
- var adapter = stormfront.type(this.adapter);
1677
- return new adapter(properties);
1678
- }
1679
- });
1680
- Homefront.Search = Homefront.Layout.extend({
1681
- className: 'search',
1682
- adapter: null,
1683
- when: {
1684
- initializing: function () {
1685
- var results = Homefront.Selection.extend({
1686
- select: this.select,
1687
- display: this.details,
1688
- none: this.none,
1689
- empty: this.empty,
1690
- initial: this.initial,
1691
- item: this.item,
1692
- method: this.method || 'click'
1693
- });
1694
- this.children = [this.search, results]
1695
- }
973
+ renderList: function (list) {
974
+ (_.isEmpty(list)) ?
975
+ this.appendChild(this.renderChild(this.createChild(this.empty))) :
976
+ _.each(list, this.renderEntry, this);
1696
977
  },
1697
- selectProperties: function (properties) {
1698
- var adapter = stormfront.type(this.adapter);
1699
- return new adapter(properties);
978
+ renderEntry: function (entry) {
979
+ this.appendChild(this.renderChild(this.createChild(this.item), entry));
1700
980
  }
1701
981
  });
1702
982
 
1703
983
  Homefront.Text = Homefront.View.extend({
1704
- when: {
1705
- updating: function(){
1706
- this.updateValue();
1707
- },
1708
- rendering: function(){
1709
- this.updateValue();
1710
- }
1711
- },
1712
- updateValue: function(){
1713
- this.$el.text(this.getValue(this.properties));
1714
- },
1715
- getValue: function(properties){
1716
- return this.value || properties.value;
1717
- }
984
+
1718
985
  });
1719
986
 
1720
987
  Homefront.Label = Homefront.Text.extend({
1721
- tagName: 'label',
1722
- when: {
1723
- rendering: function() {
1724
- this.$el.attr('for', this.properties.for);
1725
- }
1726
- }
988
+
1727
989
  });
1728
990
 
1729
991
  Homefront.Paragraph = Homefront.Text.extend({
1730
- tagName: 'p'
992
+
1731
993
  });
1732
994
 
1733
995
  Homefront.Input = Homefront.Text.extend({
1734
- tagName: 'input',
1735
- enable: function(){
1736
- this.$el.prop('disabled', false);
1737
- },
1738
- disable: function(){
1739
- this.$el.prop('disabled', true);
1740
- },
1741
- updateValue: function(){
1742
- this.$el.val(this.getValue(this.properties));
1743
- },
1744
- readValue: function(){
1745
- return this.$el.val();
1746
- }
996
+
1747
997
  });
1748
998
 
1749
999
  Homefront.Select = Homefront.Input.extend({
1750
- tagName: 'select',
1751
- events: {
1752
- 'change': 'select'
1753
- },
1754
- when: {
1755
- rendering: function(){
1756
- this.updateSelect();
1757
- },
1758
- updating: function(){
1759
- this.updateSelect();
1760
- }
1761
- },
1762
- updateSelect: function(){
1763
- this.updateOptions();
1764
- this.updateValue();
1765
- },
1766
- updateOptions: function(){
1767
- var options = this.getOptions(this.properties);
1768
- function createOption(value){
1769
- return $('<option>').val(value).text(value);
1770
- }
1771
- this.$el.append(_.map(options, createOption));
1772
- },
1773
- getOptions: function(properties){
1774
- return properties.options;
1775
- },
1776
- getValue: function(properties) {
1777
- return this.selected || properties.selected;
1778
- },
1779
- select: function(){
1780
- this.transition('change', this.readValue());
1781
- }
1000
+
1782
1001
  });
1783
1002
 
1784
1003
  Homefront.TextBox = Homefront.Input.extend({
1785
- events: {
1786
- 'change': 'change',
1787
- 'blur': 'blur',
1788
- 'keyup': 'special'
1789
- },
1790
- when: {
1791
- rendering: function(){
1792
- this.$el.attr('type', 'text');
1793
- }
1794
- },
1795
- change: function(){
1796
- this.transition('change', this.readValue());
1797
- },
1798
- blur: function(){
1799
- this.transition('blur', this.readValue());
1800
- },
1801
- special: function(event){
1802
- if (event.which === Keys.Enter)
1803
- this.transition('enter', this.readValue());
1804
- }
1004
+
1805
1005
  });
1806
1006
 
1807
1007
  Homefront.Clicker = Homefront.Input.extend({
1808
- events: {
1809
- 'click': 'click'
1810
- },
1811
- click: function(){
1812
- this.transition('click');
1813
- }
1008
+
1814
1009
  });
1815
1010
 
1816
1011
  Homefront.Button = Homefront.Clicker.extend({
1817
- when: {
1818
- rendering: function(){
1819
- this.$el.attr('type', 'button');
1820
- }
1821
- }
1012
+
1822
1013
  });
1823
- Homefront.Leaf = Homefront.View.extend({
1824
- when: {
1825
- initializing: function() {
1826
- this.template = stormfront.string(this.className).firstWord() || null;
1827
- }
1014
+ Homefront.Page = Stormfront.Class.extend({
1015
+ initial: {},
1016
+ reducers: null,
1017
+ view: null,
1018
+ initialize: function(location){
1019
+ Stormfront.Patterns.Events(this);
1020
+ this.start(this.reducers, location, this.view, this.initial);
1021
+ },
1022
+ start: function(reducers, location, view, initial){
1023
+ var container = new Stormfront.Container(reducers);
1024
+ var options = {
1025
+ location: location,
1026
+ dispatcher: container.getDispatcher(),
1027
+ view: this.view
1028
+ };
1029
+ this.listenTo(container, Stormfront.Dispatches.CHANGE, this.renderView(options));
1030
+ container.start(initial);
1031
+ },
1032
+ renderView: function(options){
1033
+ return function(action, reducer, newProperties, oldProperties) {
1034
+ var view = new this.view(options.dispatcher);
1035
+ var newTree = view.render(newProperties, oldProperties, action, reducer);
1036
+ this.attachView(newTree, options.location);
1037
+ }
1038
+ },
1039
+ attachView: function(newTree, location){
1040
+ this.tree = this.tree ?
1041
+ this.updateView(newTree) :
1042
+ this.createView(location, newTree);
1043
+ view.transition('attached');
1044
+ },
1045
+ createView: function(location, newTree){
1046
+ this.root = Homefront.Create(newTree);
1047
+ location.appendChild(this.root);
1048
+ return newTree;
1049
+ },
1050
+ updateView: function(newTree){
1051
+ var patches = Homefront.Diff(this.tree, newTree);
1052
+ this.root = Homefront.Patch(this.root, patches);
1053
+ return newTree;
1828
1054
  }
1829
- });
1055
+ });