Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/webroot/rsrc/externals/javelin/ext/view/View.js
12242 views
1
/**
2
* A View is a composable wrapper on JX.$N, allowing abstraction of higher-order
3
* views and a consistent pattern of parameterization. It is intended
4
* to be used either directly or as a building block for a syntactic sugar layer
5
* for concise expression of markup patterns.
6
*
7
* @provides javelin-view
8
* @requires javelin-install
9
* javelin-util
10
*/
11
JX.install('View', {
12
construct : function(attrs, children) {
13
this._attributes = JX.copy({}, this.getDefaultAttributeValues());
14
JX.copy(this._attributes, attrs);
15
16
this._rawChildren = {};
17
this._childKeys = [];
18
19
if (children) {
20
this.addChildren(JX.$AX(children));
21
}
22
23
this.setName(this.__class__.__readable__);
24
},
25
events: [
26
'change'
27
],
28
29
properties: {
30
'name': null
31
},
32
33
members : {
34
_attributes : null,
35
_rawChildren : null,
36
_childKeys: null, // keys of rawChildren, kept ordered.
37
_nextChildKey: 0, // next key to use for a new child
38
39
/*
40
* Don't override.
41
* TODO: Strongly typed attribute access (getIntAttr, getStringAttr...)?
42
*/
43
getAttr : function(attrName) {
44
return this._attributes[attrName];
45
},
46
47
/*
48
* Don't override.
49
*/
50
multisetAttr : function(attrs) {
51
JX.copy(this._attributes, attrs);
52
this.invoke('change');
53
return this;
54
},
55
56
/*
57
* Don't override.
58
*/
59
setAttr : function(attrName, value) {
60
this._attributes[attrName] = value;
61
this.invoke('change');
62
return this;
63
},
64
/*
65
* Child views can override to specify default values for attributes.
66
*/
67
getDefaultAttributeValues : function() {
68
return {};
69
},
70
71
/**
72
* Don't override.
73
*/
74
getAllAttributes: function() {
75
return JX.copy({}, this._attributes);
76
},
77
78
/**
79
* Get the children. Don't override.
80
*/
81
getChildren : function() {
82
var result = [];
83
var should_repack = false;
84
85
var ii;
86
var key;
87
88
for (ii = 0; ii < this._childKeys.length; ii++) {
89
key = this._childKeys[ii];
90
if (this._rawChildren[key] === undefined) {
91
should_repack = true;
92
} else {
93
result.push(this._rawChildren[key]);
94
}
95
}
96
97
if (should_repack) {
98
var new_child_keys = [];
99
for (ii = 0; ii < this._childKeys.length; ii++) {
100
key = this._childKeys[ii];
101
if (this._rawChildren[key] !== undefined) {
102
new_child_keys.push(key);
103
}
104
}
105
106
this._childKeys = new_child_keys;
107
}
108
109
return result;
110
},
111
112
/**
113
* Add children to the view. Returns array of removal handles.
114
* Don't override.
115
*/
116
addChildren : function(children) {
117
var result = [];
118
for (var ii = 0; ii < children.length; ii++) {
119
result.push(this._addChild(children[ii]));
120
}
121
this.invoke('change');
122
return result;
123
},
124
125
/**
126
* Add a single child view to the view.
127
* Returns a removal handle, i.e. an object that has a method remove(),
128
* that removes the added child from the view.
129
*
130
* Don't override.
131
*/
132
addChild: function(child) {
133
var result = this._addChild(child);
134
this.invoke('change');
135
return result;
136
},
137
138
_addChild: function(child) {
139
var key = this._nextChildKey++;
140
this._rawChildren[key] = child;
141
this._childKeys.push(key);
142
143
return {
144
remove: JX.bind(this, this._removeChild, key)
145
};
146
},
147
148
_removeChild: function(child_key) {
149
delete this._rawChildren[child_key];
150
this.invoke('change');
151
},
152
153
/**
154
* Accept visitors. This allows adding new behaviors to Views without
155
* having to change View classes themselves.
156
*
157
* This implements a post-order traversal over the tree of views. Children
158
* are processed before parents, and for convenience the results of the
159
* visitor on the children are passed to it when processing the parent.
160
*
161
* The visitor parameter is a callable which receives two parameters.
162
* The first parameter is the view to visit. The second parameter is an
163
* array of the results of visiting the view's children.
164
*
165
* Don't override.
166
*/
167
accept: function(visitor) {
168
var results = [];
169
var children = this.getChildren();
170
for(var ii = 0; ii < children.length; ii++) {
171
var result;
172
if (children[ii].accept) {
173
result = children[ii].accept(visitor);
174
} else {
175
result = children[ii];
176
}
177
results.push(result);
178
}
179
return visitor(this, results);
180
},
181
182
/**
183
* Given the already-rendered children, return the rendered result of
184
* this view.
185
* By default, just pass the children through.
186
*/
187
render: function(rendered_children) {
188
return rendered_children;
189
}
190
}
191
});
192
193