stormfront-rails 0.10.6 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ });