storkCore

Check-in [da040a306b]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Cleaner implementation for the empty sublist check for listoflists
Timelines: family | ancestors | descendants | both | emptySublist
Files: files | file ages | folders
SHA1:da040a306b07ae5ebf838541c206bf397b021770
User & Date: setok 2018-02-13 15:22:33
Context
2018-05-07
09:00
Added method for emptying a list Leaf check-in: d4aa32cbfb user: setok tags: emptySublist
2018-02-13
15:22
Cleaner implementation for the empty sublist check for listoflists check-in: da040a306b user: setok tags: emptySublist
2018-02-12
19:55
This version works for not displaying empty sublists However there is two calls to refresh() along the path to make that happen (due to the model not being ready on the first call). Need to figure out a way to avoid that. check-in: 9b5bcb6207 user: setok tags: emptySublist
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to list.js.

1
2
3
4
5
6
7




8
9
10
11
12
13
14
..
40
41
42
43
44
45
46

47
48
49
50
51
52
53
..
65
66
67
68
69
70
71

72
73
74
75
76
77
78
..
84
85
86
87
88
89
90

91
92
93
94
95
96
97

98
99
100
101
102
103
104
105
106
107








108
109
110
111
112
113
114
...
128
129
130
131
132
133
134
135
136


137
138
139
140
141
142
143
...
193
194
195
196
197
198
199







200
201
202
203
204
205
206
...
220
221
222
223
224
225
226



227
228
229
230
231
232
233
...
821
822
823
824
825
826
827

828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853




























854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873

874
875
876
877
878
879

880
881
882
883
884
885
886
/**
 * Controller for list widgets with items
 *
 * @class StorkUtil.ListController
 * @extends StorkCore.StorkController
 * @singleton
 */




var ListController = clone(StorkController);

/**
 * @property {Array} itemControllers
 */
ListController.copiedProperty("itemControllers", []);

................................................................................
 * Set the element which will contain the items of the list.
 */
ListController.setListContainer = function(element) {
    if(isString(element)) {
        element = elementByID(element);
    }
    this.containerElement = element;

};


/**
 * Set the HTML element to be shown if the list has no items. This can be
 * useful for informational purposes. If this is not set, or is 'undefined',
 * just show an empty list.
................................................................................

/**
 * 'itemController' is the StorkCore object which will be cloned as a
 * controller for each item in the list.
 */
ListController.setItemControllerPrototype = function(itemController) {
    this.itemControllerProto = itemController;

};

ListController.unsetModel = function(){
    for (var i=0; i<this.itemControllers.length;i++){
        this.itemControllers[i].unsetModel();
        this.itemControllers[i].deleted();
    }
................................................................................
 * set with setItemControllerPrototype() - which must be called before
 * calling this.
 *
 * Each item controller will get a StorkModel based on the content of the
 * element of 'listModel'.
 */
ListController.setModel = function(listModel) {

    if(!this.itemControllerProto) {
        throw "You need to set the item controller prototype (setItemControllerPrototype) before calling setModel!";
    }
    if(!this.containerElement) {
        throw "You need to set the list container element (setListContainer) before calling setModel!";
    }


    //remove the listeners to the current model if it exists, it can lead to
    //infinite recursion if resetEvent method is not overriden
    if (this.model){
        this.model.removeListener(this);
        // process the model unsetting
        this.unsetModel();
    }

    this.model = listModel;
    listModel.removeListener(this);








    emptyElement(this.containerElement);
    var itemAmount = listModel.getLength();

    if (this.listID === undefined){
        this.listID=ListController.nextListID;
        ListController.nextListID++;
    }
................................................................................
        itemController.createElement(this.containerElement);
        itemController.drawed();
        this.itemControllers[i] = itemController;
        this.informListeners('listItemControllerAdded',[this,
                                                        itemController,
                                                        i]);
    }

    listModel.addListener(this);


};


/**
 * Check to see if the zero length element should be shown or not.
 * Show it if it is set, and the length of the list is 0.
 */
................................................................................
            this.containerElement.appendChild(sortedControllers[i].getElement());
        }
    }

};

ListController.deleteItemEvent = function(source, item, index) {







    var itemController = this.itemControllers[index];
    if(itemController) {
        this.itemControllers.splice(index, 1);
        itemController.deleted();
        this.informListeners('listItemControllerDeleted',
                             [this, itemController]);
        this.showOrHideZeroLengthElement();
................................................................................
 * 'index' is the index at which it appeared.
 */
ListController.insertBeforeEvent = function(source, modelItem, index) {
     /*console.log("ListController.insertBeforeEvent:", source, modelItem, index);
     console.log(this.itemControllerProto);
     console.log("modelItem: ");
     console.log(modelItem);*/



    var itemController = clone(this.itemControllerProto);
    //itemController.init();
    itemController.setModel(modelItem);
    itemController.setListID(this.listID);
    itemController.setListItemID(this.nextItemID);
    this.nextItemID++;
    var nextController = this.itemControllers[index];
................................................................................
/**
 * The name of the StorkModel property for this item which contains a
 * ListModel object as its value, and which will be used to populate the
 * sub-list
 */
ListOfListsItem.setSubListModelProperty = function(propertyName) {
    this.subListModelProperty = propertyName;

};


/**
 * Override ListItemController refresh() to implement functionality of
 * renderIfEmpty().
 */

ListOfListsItem.refresh = function() { 
    console.log("refresh");
    var r = this.superMethod(ListOfListsItem.refresh, "refresh");

    if (! this.renderIfEmpty) {
        var sublistModel = this.getSubListController().getModel();
        console.log(this.getSubListController());
        console.log(sublistModel);            
        console.log(this.myElement);

        if (!sublistModel || (sublistModel.getLength() == 0)) {
            hideElement(this.myElement);
        } else {
            showElement(this.myElement);
        }                
    }        

    console.log("ListOfListsItem.refresh - return");




























    return r;
};


/**
 * Override the normal ListItemController createElement() with one that
 * builds the sub-list.
 */
ListOfListsItem.createElement = function(containerElement,
                                         beforeElement) {
    var subListModel;
    var listContainer;

    console.debug("ListOfListsItem - createElement");
    this.superMethod(ListOfListsItem.createElement, "createElement", 
                     containerElement, beforeElement);

    listContainer = this.getContainedElement(this.subListContainer);
    this.subListController.setListContainer(listContainer);


    subListModel = this.model.getProperty(this.subListModelProperty);
    console.log("createElement setModel");
    this.subListController.setModel(subListModel);
    console.log("createElement addListener");
    subListModel.addListener(this);
    console.log("createElement return");

    this.refresh();
};


ListOfListsItem.renderIfEmpty = function(render) {
    this.renderIfEmpty = render;
    return;







>
>
>
>







 







>







 







>







 







>





|

>
|
|
<

<





>
>
>
>
>
>
>
>







 







|
<
>
>







 







>
>
>
>
>
>
>







 







>
>
>







 







>









<




<
<
<








|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>













|






>






>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
..
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
..
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
..
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

108

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
142
143
144
145
146
147
148
149

150
151
152
153
154
155
156
157
158
...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
...
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
...
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862

863
864
865
866



867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
/**
 * Controller for list widgets with items
 *
 * @class StorkUtil.ListController
 * @extends StorkCore.StorkController
 * @singleton
 */

// :NOTE: Should look at utilising StorkHtmlView here and away from the
// controller creating HTML

var ListController = clone(StorkController);

/**
 * @property {Array} itemControllers
 */
ListController.copiedProperty("itemControllers", []);

................................................................................
 * Set the element which will contain the items of the list.
 */
ListController.setListContainer = function(element) {
    if(isString(element)) {
        element = elementByID(element);
    }
    this.containerElement = element;
    this.refresh();
};


/**
 * Set the HTML element to be shown if the list has no items. This can be
 * useful for informational purposes. If this is not set, or is 'undefined',
 * just show an empty list.
................................................................................

/**
 * 'itemController' is the StorkCore object which will be cloned as a
 * controller for each item in the list.
 */
ListController.setItemControllerPrototype = function(itemController) {
    this.itemControllerProto = itemController;
    this.refresh();
};

ListController.unsetModel = function(){
    for (var i=0; i<this.itemControllers.length;i++){
        this.itemControllers[i].unsetModel();
        this.itemControllers[i].deleted();
    }
................................................................................
 * set with setItemControllerPrototype() - which must be called before
 * calling this.
 *
 * Each item controller will get a StorkModel based on the content of the
 * element of 'listModel'.
 */
ListController.setModel = function(listModel) {
    /*
    if(!this.itemControllerProto) {
        throw "You need to set the item controller prototype (setItemControllerPrototype) before calling setModel!";
    }
    if(!this.containerElement) {
        throw "You need to set the list container element (setListContainer) before calling setModel!";
    }*/

    if (this.model){
        //remove the listeners to the current model if it exists, it can lead to
        //infinite recursion if resetEvent method is not overriden

        this.model.removeListener(this);

        this.unsetModel();
    }

    this.model = listModel;
    listModel.removeListener(this);
    this.refresh();
    listModel.addListener(this);
};


ListController.refresh = function() {
    if (this.model && this.containerElement && this.itemControllerProto) {
        var listModel = this.model;
    emptyElement(this.containerElement);
    var itemAmount = listModel.getLength();

    if (this.listID === undefined){
        this.listID=ListController.nextListID;
        ListController.nextListID++;
    }
................................................................................
        itemController.createElement(this.containerElement);
        itemController.drawed();
        this.itemControllers[i] = itemController;
        this.informListeners('listItemControllerAdded',[this,
                                                        itemController,
                                                        i]);
    }
}


    //return this.superMethod(ListController.refresh, "refresh");
};


/**
 * Check to see if the zero length element should be shown or not.
 * Show it if it is set, and the length of the list is 0.
 */
................................................................................
            this.containerElement.appendChild(sortedControllers[i].getElement());
        }
    }

};

ListController.deleteItemEvent = function(source, item, index) {
    if (! (this.model && this.containerElement && this.itemControllerProto) ) {
        // We only care for these events after the model, container element 
        // and item controller prototype
        // are set. Ie. after HTML has been created for the list items.
        return;
    }

    var itemController = this.itemControllers[index];
    if(itemController) {
        this.itemControllers.splice(index, 1);
        itemController.deleted();
        this.informListeners('listItemControllerDeleted',
                             [this, itemController]);
        this.showOrHideZeroLengthElement();
................................................................................
 * 'index' is the index at which it appeared.
 */
ListController.insertBeforeEvent = function(source, modelItem, index) {
     /*console.log("ListController.insertBeforeEvent:", source, modelItem, index);
     console.log(this.itemControllerProto);
     console.log("modelItem: ");
     console.log(modelItem);*/
    if (! (this.model && this.containerElement && this.itemControllerProto) ) {
        return;
    }
    var itemController = clone(this.itemControllerProto);
    //itemController.init();
    itemController.setModel(modelItem);
    itemController.setListID(this.listID);
    itemController.setListItemID(this.nextItemID);
    this.nextItemID++;
    var nextController = this.itemControllers[index];
................................................................................
/**
 * The name of the StorkModel property for this item which contains a
 * ListModel object as its value, and which will be used to populate the
 * sub-list
 */
ListOfListsItem.setSubListModelProperty = function(propertyName) {
    this.subListModelProperty = propertyName;
    ListOfListsItem.setupSubListModel();
};


/**
 * Override ListItemController refresh() to implement functionality of
 * renderIfEmpty().
 */

ListOfListsItem.refresh = function() { 

    var r = this.superMethod(ListOfListsItem.refresh, "refresh");

    if (! this.renderIfEmpty) {
        var sublistModel = this.getSubListController().getModel();




        if (!sublistModel || (sublistModel.getLength() == 0)) {
            hideElement(this.myElement);
        } else {
            showElement(this.myElement);
        }                
    }        

    return r;
};


/* Setup the model of the sublist, and set ourselves as a listener of it.
   This only does something if a model has been set for this item, and
   the subListModelProperty has been set. 

   Intended for internal use.
*/

ListOfListsItem.setupSubListModel = function() {
    if (this.subListModelProperty && this.model) {
        var sublistModel = this.model.getProperty(this.subListModelProperty);
        var oldModel = this.subListController.getModel();
        if (oldModel) {
            oldModel.removeListener(this);
        }
        this.subListController.setModel(sublistModel);
        sublistModel.addListener(this);
    }
};


ListOfListsItem.setModel = function(listModel) {
    var r = this.superMethod(ListOfListsItem.setModel, "setModel", listModel);

    this.setupSubListModel();

    return r;
};


/**
 * Override the normal ListItemController createElement() with one that
 * builds the sub-list.
 */
ListOfListsItem.createElement = function(containerElement,
                                         beforeElement) {
    var subListModel;
    var listContainer;

    //console.debug("ListOfListsItem - createElement");
    this.superMethod(ListOfListsItem.createElement, "createElement", 
                     containerElement, beforeElement);

    listContainer = this.getContainedElement(this.subListContainer);
    this.subListController.setListContainer(listContainer);

    /*
    subListModel = this.model.getProperty(this.subListModelProperty);
    console.log("createElement setModel");
    this.subListController.setModel(subListModel);
    console.log("createElement addListener");
    subListModel.addListener(this);
    console.log("createElement return");
*/
    this.refresh();
};


ListOfListsItem.renderIfEmpty = function(render) {
    this.renderIfEmpty = render;
    return;

Changes to storkCore.js.

877
878
879
880
881
882
883
884


885
886
887
888
889
890
891
        throw new Error("Empty object passed to StorkModel.addListener");
    }
    this.listeners.push(listener);
};


/**
 * Remove an object listening for changes in the attributes of this model


 *
 * @param {Object} listener
 *    the object registered as listener to be deleted
 */
StorkModel.removeListener = function(listener) {
    this.listeners = removeFromArray(this.listeners, listener);
};







|
>
>







877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
        throw new Error("Empty object passed to StorkModel.addListener");
    }
    this.listeners.push(listener);
};


/**
 * Remove an object listening for changes in the attributes of this 
 * model. It is not an error to try to remove an object which is not a
 * listener.
 *
 * @param {Object} listener
 *    the object registered as listener to be deleted
 */
StorkModel.removeListener = function(listener) {
    this.listeners = removeFromArray(this.listeners, listener);
};