UNPKG

4.11 kBJavaScriptView Raw
1var _ = require("underscore");
2var Trackr = require("trackr");
3var utils = require("./utils");
4var Model = require("./model");
5var View = require("./view");
6
7var Section =
8module.exports = View.extend({
9 constructor: function() {
10 this.rows = {};
11 this._row_deps = {};
12 View.apply(this, arguments);
13 },
14
15 invert: function(val) {
16 if (!_.isBoolean(val)) val = !this._inverted;
17 this._inverted = val;
18 return this;
19 },
20
21 isInverted: function() {
22 return !!this._inverted;
23 },
24
25 setPath: function(path) {
26 this._path = path;
27 return this;
28 },
29
30 onRow: function(fn) {
31 if (!_.isFunction(fn))
32 throw new Error("Expecting function for row handler.");
33
34 this._onRow = fn;
35 return this;
36 },
37
38 addRow: function(key, data) {
39 // remove existing
40 this.removeRow(key);
41
42 // convert data to model
43 if (!Model.isModel(data)) {
44 data = new Model(data, this.model);
45 }
46
47 // create a new row
48 var row = new View(data);
49
50 // set up render and mount it
51 row.render = this._onRow;
52 this.rows[key] = row;
53 this.addMember(row);
54 row.mount();
55
56 return row;
57 },
58
59 hasRow: function(key) {
60 return this.getRow(key) != null;
61 },
62
63 getRow: function(key) {
64 return this.rows[key];
65 },
66
67 removeRow: function(key) {
68 if (this.rows[key] == null) return this;
69
70 var row = this.rows[key];
71 this.removeMember(row);
72 delete this.rows[key];
73
74 return this;
75 },
76
77 removeAllRows: function() {
78 Object.keys(this.rows).forEach(this.removeRow, this);
79 return this;
80 },
81
82 render: function() {
83 if (this._path == null) throw new Error("Missing path.");
84
85 var self = this,
86 val, isEmpty, inverted, isList,
87 rowSort, model, proxy, keys;
88
89 val = this.get(this._path);
90 model = new Model(val, this.model);
91 proxy = model.getProxyByValue(val);
92 inverted = this.isInverted();
93 isList = model.callProxyMethod(proxy, val, "isList");
94
95 function getEmptiness() {
96 return model.callProxyMethod(proxy, val, "isEmpty");
97 }
98
99 Trackr.nonreactive(function() {
100 isEmpty = !val || (isList && !getEmptiness())
101 });
102
103 if (isEmpty && inverted) {
104 if (isList) getEmptiness();
105 this.addRow(0, model);
106 } else if (!isEmpty && !inverted) {
107 if (isList) {
108 keys = [];
109
110 this.autorun(function(comp) {
111 var nkeys = model.callProxyMethod(proxy, val, "keys");
112
113 // trick Trackr so autoruns aren't controlled by this one
114 Trackr.currentComputation = comp._parent;
115
116 // remove removed rows
117 _.difference(keys, nkeys).forEach(function(key) {
118 if (this._row_deps[key]) {
119 this._row_deps[key].stop();
120 delete this._row_deps[key];
121 }
122
123 this.removeRow(key);
124 }, this);
125
126 // add added rows
127 _.difference(nkeys, keys).forEach(function(key) {
128 var row, rmodel;
129
130 row = this.getRow(key);
131 rmodel = row != null ? row.model :
132 new Model(null, new Model({ $key: key }, this.model));
133
134 this._row_deps[key] = this.autorun(function(c) {
135 rmodel.set(model.callProxyMethod(proxy, val, "get", key));
136 // if (rowSort != null) rowSort.invalidate();
137 });
138
139 // add the row after we set the data
140 if (row == null) this.addRow(key, rmodel);
141 }, this);
142
143 // pretend like nothing happened
144 Trackr.currentComputation = comp;
145
146 // the new set of keys
147 keys = nkeys;
148 });
149
150 // a reactive context that continuously sorts rows
151 // rowSort = this.autorun(function() {
152 // console.log(keys);
153 // var before = null, i, row;
154
155 // for (i = keys.length - 1; i >= 0; i--) {
156 // row = this.getRow(keys[i]);
157 // if (row == null) continue;
158 // this.insertBefore(row, before);
159 // before = row;
160 // }
161 // });
162 } else {
163 this.addRow(0, model);
164 }
165 } else if (isList) {
166 getEmptiness();
167 }
168
169 // auto clean
170 this.once("invalidate", function() {
171 this._row_deps = {};
172 this.removeAllRows();
173 });
174 }
175
176}, {
177
178 isEmpty: function(model, proxy) {
179 if (!model.data) return true;
180 if (proxy == null) proxy = model.getProxyByValue(model.data);
181 return model.callProxyMethod(proxy, model.data, "isList") &&
182 model.callProxyMethod(proxy, model.data, "isEmpty");
183 }
184
185});