GUI -- Implemented Instance Panel.
- handling addInstance event. Change-Id: Ic98a3291bd37ecf1155dbe1696167d0635a31972
Showing
13 changed files
with
482 additions
and
59 deletions
... | @@ -75,7 +75,8 @@ | ... | @@ -75,7 +75,8 @@ |
75 | append: appendPanel, | 75 | append: appendPanel, |
76 | width: panelWidth, | 76 | width: panelWidth, |
77 | height: panelHeight, | 77 | height: panelHeight, |
78 | - isVisible: panelIsVisible | 78 | + isVisible: panelIsVisible, |
79 | + el: panelEl | ||
79 | }; | 80 | }; |
80 | 81 | ||
81 | p.el = panelLayer.append('div') | 82 | p.el = panelLayer.append('div') |
... | @@ -136,6 +137,10 @@ | ... | @@ -136,6 +137,10 @@ |
136 | return p.on; | 137 | return p.on; |
137 | } | 138 | } |
138 | 139 | ||
140 | + function panelEl() { | ||
141 | + return p.el; | ||
142 | + } | ||
143 | + | ||
139 | return api; | 144 | return api; |
140 | } | 145 | } |
141 | 146 | ... | ... |
... | @@ -218,8 +218,7 @@ | ... | @@ -218,8 +218,7 @@ |
218 | if (xns) { | 218 | if (xns) { |
219 | atr.transform = sus.translate(trans); | 219 | atr.transform = sus.translate(trans); |
220 | } | 220 | } |
221 | - elem.append('use').attr(atr).classed('overlay', ovr); | 221 | + return elem.append('use').attr(atr).classed('overlay', ovr); |
222 | - | ||
223 | } | 222 | } |
224 | 223 | ||
225 | // ---------------------------------------------------------------------- | 224 | // ---------------------------------------------------------------------- | ... | ... |
... | @@ -143,11 +143,16 @@ | ... | @@ -143,11 +143,16 @@ |
143 | return 'translate(' + x + ',' + y + ')'; | 143 | return 'translate(' + x + ',' + y + ')'; |
144 | } | 144 | } |
145 | 145 | ||
146 | + function stripPx(s) { | ||
147 | + return s.replace(/px$/,''); | ||
148 | + } | ||
149 | + | ||
146 | return { | 150 | return { |
147 | createDragBehavior: createDragBehavior, | 151 | createDragBehavior: createDragBehavior, |
148 | loadGlow: loadGlow, | 152 | loadGlow: loadGlow, |
149 | cat7: cat7, | 153 | cat7: cat7, |
150 | - translate: translate | 154 | + translate: translate, |
155 | + stripPx: stripPx | ||
151 | }; | 156 | }; |
152 | }]); | 157 | }]); |
153 | }()); | 158 | }()); | ... | ... |
... | @@ -78,6 +78,7 @@ | ... | @@ -78,6 +78,7 @@ |
78 | <script src="view/topo/topoEvent.js"></script> | 78 | <script src="view/topo/topoEvent.js"></script> |
79 | <script src="view/topo/topoForce.js"></script> | 79 | <script src="view/topo/topoForce.js"></script> |
80 | <script src="view/topo/topoPanel.js"></script> | 80 | <script src="view/topo/topoPanel.js"></script> |
81 | + <script src="view/topo/topoInst.js"></script> | ||
81 | <script src="view/device/device.js"></script> | 82 | <script src="view/device/device.js"></script> |
82 | <!-- TODO: inject javascript refs server-side --> | 83 | <!-- TODO: inject javascript refs server-side --> |
83 | 84 | ... | ... |
... | @@ -43,7 +43,7 @@ | ... | @@ -43,7 +43,7 @@ |
43 | } | 43 | } |
44 | 44 | ||
45 | 45 | ||
46 | -/* --- Topo Panels --- */ | 46 | +/* --- Topo Summary Panel --- */ |
47 | 47 | ||
48 | #topo-p-summary { | 48 | #topo-p-summary { |
49 | /* Base css from panel.css */ | 49 | /* Base css from panel.css */ |
... | @@ -107,3 +107,78 @@ | ... | @@ -107,3 +107,78 @@ |
107 | background-color: #888; | 107 | background-color: #888; |
108 | color: #888; | 108 | color: #888; |
109 | } | 109 | } |
110 | + | ||
111 | + | ||
112 | +/* --- Topo Detail Panel --- */ | ||
113 | + | ||
114 | +/* TODO: add CSS rules */ | ||
115 | + | ||
116 | + | ||
117 | +/* --- Topo Instance Panel --- */ | ||
118 | + | ||
119 | +#topo-p-instance { | ||
120 | + height: 100px; | ||
121 | +} | ||
122 | + | ||
123 | +#topo-p-instance div.onosInst { | ||
124 | + display: inline-block; | ||
125 | + width: 170px; | ||
126 | + height: 85px; | ||
127 | + cursor: pointer; | ||
128 | +} | ||
129 | + | ||
130 | +#topo-p-instance svg rect { | ||
131 | + fill: #ccc; | ||
132 | + stroke: #aaa; | ||
133 | + stroke-width: 3.5; | ||
134 | +} | ||
135 | +#topo-p-instance .online svg rect { | ||
136 | + opacity: 1; | ||
137 | + fill: #9cf; | ||
138 | + stroke: #555; | ||
139 | +} | ||
140 | + | ||
141 | +#topo-p-instance svg .glyph { | ||
142 | + fill: #888; | ||
143 | + fill-rule: evenodd; | ||
144 | +} | ||
145 | +#topo-p-instance .online svg .glyph { | ||
146 | + fill: #000; | ||
147 | +} | ||
148 | + | ||
149 | +#topo-p-instance svg .badgeIcon { | ||
150 | + fill: #777; | ||
151 | + fill-rule: evenodd; | ||
152 | +} | ||
153 | + | ||
154 | +#topo-p-instance .online svg .badgeIcon { | ||
155 | + fill: #fff; | ||
156 | +} | ||
157 | + | ||
158 | +#topo-p-instance svg text { | ||
159 | + text-anchor: middle; | ||
160 | + fill: #777; | ||
161 | +} | ||
162 | +#topo-p-instance .online svg text { | ||
163 | + fill: #eee; | ||
164 | +} | ||
165 | + | ||
166 | +#topo-p-instance svg text.instTitle { | ||
167 | + font-size: 11pt; | ||
168 | + font-weight: bold; | ||
169 | +} | ||
170 | +#topo-p-instance svg text.instLabel { | ||
171 | + font-size: 9pt; | ||
172 | + font-style: italic; | ||
173 | +} | ||
174 | + | ||
175 | +#topo-p-instance .onosInst.mastership { | ||
176 | + opacity: 0.3; | ||
177 | +} | ||
178 | +#topo-p-instance .onosInst.mastership.affinity { | ||
179 | + opacity: 1.0; | ||
180 | +} | ||
181 | +#topo-p-instance .onosInst.mastership.affinity svg rect { | ||
182 | + /* TODO: add blue glow */ | ||
183 | + /*filter: url(#blue-glow);*/ | ||
184 | +} | ... | ... |
... | @@ -143,12 +143,13 @@ | ... | @@ -143,12 +143,13 @@ |
143 | 143 | ||
144 | .controller('OvTopoCtrl', [ | 144 | .controller('OvTopoCtrl', [ |
145 | '$scope', '$log', '$location', '$timeout', | 145 | '$scope', '$log', '$location', '$timeout', |
146 | - 'FnService', 'MastService', | 146 | + 'FnService', 'MastService', 'KeyService', 'ZoomService', |
147 | - 'KeyService', 'ZoomService', 'GlyphService', 'MapService', | 147 | + 'GlyphService', 'MapService', |
148 | 'TopoEventService', 'TopoForceService', 'TopoPanelService', | 148 | 'TopoEventService', 'TopoForceService', 'TopoPanelService', |
149 | + 'TopoInstService', | ||
149 | 150 | ||
150 | function ($scope, _$log_, $loc, $timeout, _fs_, mast, | 151 | function ($scope, _$log_, $loc, $timeout, _fs_, mast, |
151 | - _ks_, _zs_, _gs_, _ms_, tes, _tfs_, tps) { | 152 | + _ks_, _zs_, _gs_, _ms_, tes, _tfs_, tps, tis) { |
152 | var self = this; | 153 | var self = this; |
153 | $log = _$log_; | 154 | $log = _$log_; |
154 | fs = _fs_; | 155 | fs = _fs_; |
... | @@ -167,6 +168,7 @@ | ... | @@ -167,6 +168,7 @@ |
167 | $log.log('OvTopoCtrl is saying Buh-Bye!'); | 168 | $log.log('OvTopoCtrl is saying Buh-Bye!'); |
168 | tes.closeSock(); | 169 | tes.closeSock(); |
169 | tps.destroyPanels(); | 170 | tps.destroyPanels(); |
171 | + tis.destroyInst(); | ||
170 | }); | 172 | }); |
171 | 173 | ||
172 | // svg layer and initialization of components | 174 | // svg layer and initialization of components |
... | @@ -181,6 +183,7 @@ | ... | @@ -181,6 +183,7 @@ |
181 | setUpMap(); | 183 | setUpMap(); |
182 | setUpForce(); | 184 | setUpForce(); |
183 | 185 | ||
186 | + tis.initInst(); | ||
184 | tps.initPanels(); | 187 | tps.initPanels(); |
185 | tes.openSock(); | 188 | tes.openSock(); |
186 | 189 | ... | ... |
... | @@ -23,7 +23,7 @@ | ... | @@ -23,7 +23,7 @@ |
23 | 'use strict'; | 23 | 'use strict'; |
24 | 24 | ||
25 | // injected refs | 25 | // injected refs |
26 | - var $log, wss, wes, tps; | 26 | + var $log, wss, wes, tps, tis; |
27 | 27 | ||
28 | // internal state | 28 | // internal state |
29 | var wsock; | 29 | var wsock; |
... | @@ -47,7 +47,8 @@ | ... | @@ -47,7 +47,8 @@ |
47 | } | 47 | } |
48 | 48 | ||
49 | function addInstance(ev) { | 49 | function addInstance(ev) { |
50 | - $log.debug(' *** We got an ADD INSTANCE event: ', ev); | 50 | + $log.debug(' **** Add Instance **** ', ev.payload); |
51 | + tis.addInstance(ev.payload); | ||
51 | } | 52 | } |
52 | 53 | ||
53 | // ========================== | 54 | // ========================== |
... | @@ -87,13 +88,14 @@ | ... | @@ -87,13 +88,14 @@ |
87 | angular.module('ovTopo') | 88 | angular.module('ovTopo') |
88 | .factory('TopoEventService', | 89 | .factory('TopoEventService', |
89 | ['$log', '$location', 'WebSocketService', 'WsEventService', | 90 | ['$log', '$location', 'WebSocketService', 'WsEventService', |
90 | - 'TopoPanelService', | 91 | + 'TopoPanelService', 'TopoInstService', |
91 | 92 | ||
92 | - function (_$log_, $loc, _wss_, _wes_, _tps_) { | 93 | + function (_$log_, $loc, _wss_, _wes_, _tps_, _tis_) { |
93 | $log = _$log_; | 94 | $log = _$log_; |
94 | wss = _wss_; | 95 | wss = _wss_; |
95 | wes = _wes_; | 96 | wes = _wes_; |
96 | tps = _tps_; | 97 | tps = _tps_; |
98 | + tis = _tis_; | ||
97 | 99 | ||
98 | function bindDispatcher(TopoDomElementsPassedHere) { | 100 | function bindDispatcher(TopoDomElementsPassedHere) { |
99 | // TODO: store refs to topo DOM elements... | 101 | // TODO: store refs to topo DOM elements... | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +/* | ||
18 | + ONOS GUI -- Topology Instances Module. | ||
19 | + Defines modeling of ONOS instances. | ||
20 | + */ | ||
21 | + | ||
22 | +(function () { | ||
23 | + 'use strict'; | ||
24 | + | ||
25 | + // injected refs | ||
26 | + var $log, ps, sus, gs; | ||
27 | + | ||
28 | + // configuration | ||
29 | + var instCfg = { | ||
30 | + rectPad: 8, | ||
31 | + nodeOx: 9, | ||
32 | + nodeOy: 9, | ||
33 | + nodeDim: 40, | ||
34 | + birdOx: 19, | ||
35 | + birdOy: 21, | ||
36 | + birdDim: 21, | ||
37 | + uiDy: 45, | ||
38 | + titleDy: 30, | ||
39 | + textYOff: 20, | ||
40 | + textYSpc: 15 | ||
41 | + }, | ||
42 | + showLogicErrors = true, | ||
43 | + idIns = 'topo-p-instance', | ||
44 | + instOpts = { | ||
45 | + edge: 'left', | ||
46 | + width: 20 | ||
47 | + }; | ||
48 | + | ||
49 | + // internal state | ||
50 | + var onosInstances, | ||
51 | + onosOrder, | ||
52 | + oiShowMaster, | ||
53 | + oiBox; | ||
54 | + | ||
55 | + | ||
56 | + // ========================== | ||
57 | + // *** ADD INSTANCE *** | ||
58 | + | ||
59 | + function addInstance(data) { | ||
60 | + var id = data.id; | ||
61 | + | ||
62 | + if (onosInstances[id]) { | ||
63 | + updateInstance(data); | ||
64 | + return; | ||
65 | + } | ||
66 | + onosInstances[id] = data; | ||
67 | + onosOrder.push(data); | ||
68 | + updateInstances(); | ||
69 | + } | ||
70 | + | ||
71 | + function updateInstance(data) { | ||
72 | + var id = data.id, | ||
73 | + d = onosInstances[id]; | ||
74 | + if (d) { | ||
75 | + angular.extend(d, data); | ||
76 | + updateInstances(); | ||
77 | + } else { | ||
78 | + logicError('updateInstance: lookup fail: ID = "' + id + '"'); | ||
79 | + } | ||
80 | + } | ||
81 | + | ||
82 | + function computeDim(self) { | ||
83 | + var css = window.getComputedStyle(self); | ||
84 | + return { | ||
85 | + w: sus.stripPx(css.width), | ||
86 | + h: sus.stripPx(css.height) | ||
87 | + }; | ||
88 | + } | ||
89 | + | ||
90 | + function clickInst(d) { | ||
91 | + var el = d3.select(this), | ||
92 | + aff = el.classed('affinity'); | ||
93 | + if (!aff) { | ||
94 | + setAffinity(el, d); | ||
95 | + } else { | ||
96 | + cancelAffinity(); | ||
97 | + } | ||
98 | + } | ||
99 | + | ||
100 | + function setAffinity(el, d) { | ||
101 | + d3.selectAll('.onosInst') | ||
102 | + .classed('mastership', true) | ||
103 | + .classed('affinity', false); | ||
104 | + el.classed('affinity', true); | ||
105 | + | ||
106 | + // TODO: suppress the layers and highlight only specific nodes... | ||
107 | + //suppressLayers(true); | ||
108 | + //node.each(function (n) { | ||
109 | + // if (n.master === d.id) { | ||
110 | + // n.el.classed('suppressed', false); | ||
111 | + // } | ||
112 | + //}); | ||
113 | + oiShowMaster = true; | ||
114 | + } | ||
115 | + | ||
116 | + function cancelAffinity() { | ||
117 | + d3.selectAll('.onosInst') | ||
118 | + .classed('mastership affinity', false); | ||
119 | + | ||
120 | + // TODO: restore layer state | ||
121 | + //restoreLayerState(); | ||
122 | + oiShowMaster = false; | ||
123 | + } | ||
124 | + | ||
125 | + function instRectAttr(dim) { | ||
126 | + var pad = instCfg.rectPad; | ||
127 | + return { | ||
128 | + x: pad, | ||
129 | + y: pad, | ||
130 | + width: dim.w - pad*2, | ||
131 | + height: dim.h - pad*2, | ||
132 | + rx: 6 | ||
133 | + }; | ||
134 | + } | ||
135 | + | ||
136 | + function viewBox(dim) { | ||
137 | + return '0 0 ' + dim.w + ' ' + dim.h; | ||
138 | + } | ||
139 | + | ||
140 | + function attachUiBadge(svg) { | ||
141 | + gs.addGlyph(svg, 'uiAttached', 30, true, [12, instCfg.uiDy]) | ||
142 | + .classed('badgeIcon uiBadge', true); | ||
143 | + } | ||
144 | + | ||
145 | + function instColor(id, online) { | ||
146 | + // TODO: fix this.. | ||
147 | + //return cat7.get(id, !online, network.view.getTheme()); | ||
148 | + return 'blue'; | ||
149 | + } | ||
150 | + | ||
151 | + // ============================== | ||
152 | + | ||
153 | + function updateInstances() { | ||
154 | + var onoses = oiBox.el().selectAll('.onosInst') | ||
155 | + .data(onosOrder, function (d) { return d.id; }), | ||
156 | + instDim = {w:0,h:0}, | ||
157 | + c = instCfg; | ||
158 | + | ||
159 | + function nSw(n) { | ||
160 | + return '# Switches: ' + n; | ||
161 | + } | ||
162 | + | ||
163 | + // operate on existing onos instances if necessary | ||
164 | + onoses.each(function (d) { | ||
165 | + var el = d3.select(this), | ||
166 | + svg = el.select('svg'); | ||
167 | + instDim = computeDim(this); | ||
168 | + | ||
169 | + // update online state | ||
170 | + el.classed('online', d.online); | ||
171 | + | ||
172 | + // update ui-attached state | ||
173 | + svg.select('use.uiBadge').remove(); | ||
174 | + if (d.uiAttached) { | ||
175 | + attachUiBadge(svg); | ||
176 | + } | ||
177 | + | ||
178 | + function updAttr(id, value) { | ||
179 | + svg.select('text.instLabel.'+id).text(value); | ||
180 | + } | ||
181 | + | ||
182 | + updAttr('ip', d.ip); | ||
183 | + updAttr('ns', nSw(d.switches)); | ||
184 | + }); | ||
185 | + | ||
186 | + | ||
187 | + // operate on new onos instances | ||
188 | + var entering = onoses.enter() | ||
189 | + .append('div') | ||
190 | + .attr('class', 'onosInst') | ||
191 | + .classed('online', function (d) { return d.online; }) | ||
192 | + .on('click', clickInst); | ||
193 | + | ||
194 | + entering.each(function (d) { | ||
195 | + var el = d3.select(this), | ||
196 | + rectAttr, | ||
197 | + svg; | ||
198 | + instDim = computeDim(this); | ||
199 | + rectAttr = instRectAttr(instDim); | ||
200 | + | ||
201 | + svg = el.append('svg').attr({ | ||
202 | + width: instDim.w, | ||
203 | + height: instDim.h, | ||
204 | + viewBox: viewBox(instDim) | ||
205 | + }); | ||
206 | + | ||
207 | + svg.append('rect').attr(rectAttr); | ||
208 | + | ||
209 | + gs.addGlyph(svg, 'bird', 28, true, [14, 14]) | ||
210 | + .classed('badgeIcon', true); | ||
211 | + | ||
212 | + if (d.uiAttached) { | ||
213 | + attachUiBadge(svg); | ||
214 | + } | ||
215 | + | ||
216 | + var left = c.nodeOx + c.nodeDim, | ||
217 | + len = rectAttr.width - left, | ||
218 | + hlen = len / 2, | ||
219 | + midline = hlen + left; | ||
220 | + | ||
221 | + // title | ||
222 | + svg.append('text') | ||
223 | + .attr({ | ||
224 | + class: 'instTitle', | ||
225 | + x: midline, | ||
226 | + y: c.titleDy | ||
227 | + }) | ||
228 | + .text(d.id); | ||
229 | + | ||
230 | + // a couple of attributes | ||
231 | + var ty = c.titleDy + c.textYOff; | ||
232 | + | ||
233 | + function addAttr(id, label) { | ||
234 | + svg.append('text').attr({ | ||
235 | + class: 'instLabel ' + id, | ||
236 | + x: midline, | ||
237 | + y: ty | ||
238 | + }).text(label); | ||
239 | + ty += c.textYSpc; | ||
240 | + } | ||
241 | + | ||
242 | + addAttr('ip', d.ip); | ||
243 | + addAttr('ns', nSw(d.switches)); | ||
244 | + }); | ||
245 | + | ||
246 | + // operate on existing + new onoses here | ||
247 | + // set the affinity colors... | ||
248 | + onoses.each(function (d) { | ||
249 | + var el = d3.select(this), | ||
250 | + rect = el.select('svg').select('rect'), | ||
251 | + col = instColor(d.id, d.online); | ||
252 | + rect.style('fill', col); | ||
253 | + }); | ||
254 | + | ||
255 | + // adjust the panel size appropriately... | ||
256 | + oiBox.width(instDim.w * onosOrder.length); | ||
257 | + oiBox.height(instDim.h); | ||
258 | + | ||
259 | + // remove any outgoing instances | ||
260 | + onoses.exit().remove(); | ||
261 | + } | ||
262 | + | ||
263 | + | ||
264 | + // ========================== | ||
265 | + | ||
266 | + function logicError(msg) { | ||
267 | + if (showLogicErrors) { | ||
268 | + $log.warn('TopoInstService: ' + msg); | ||
269 | + } | ||
270 | + } | ||
271 | + | ||
272 | + function initInst() { | ||
273 | + oiBox = ps.createPanel(idIns, instOpts); | ||
274 | + oiBox.show(); | ||
275 | + | ||
276 | + onosInstances = {}; | ||
277 | + onosOrder = []; | ||
278 | + oiShowMaster = false; | ||
279 | + } | ||
280 | + | ||
281 | + function destroyInst() { | ||
282 | + ps.destroyPanel(idIns); | ||
283 | + oiBox = null; | ||
284 | + } | ||
285 | + | ||
286 | + // ========================== | ||
287 | + | ||
288 | + angular.module('ovTopo') | ||
289 | + .factory('TopoInstService', | ||
290 | + ['$log', 'PanelService', 'SvgUtilService', 'GlyphService', | ||
291 | + | ||
292 | + function (_$log_, _ps_, _sus_, _gs_) { | ||
293 | + $log = _$log_; | ||
294 | + ps = _ps_; | ||
295 | + sus = _sus_; | ||
296 | + gs = _gs_; | ||
297 | + | ||
298 | + return { | ||
299 | + initInst: initInst, | ||
300 | + destroyInst: destroyInst, | ||
301 | + addInstance: addInstance | ||
302 | + }; | ||
303 | + }]); | ||
304 | +}()); |
... | @@ -28,43 +28,20 @@ | ... | @@ -28,43 +28,20 @@ |
28 | // constants | 28 | // constants |
29 | var idSum = 'topo-p-summary', | 29 | var idSum = 'topo-p-summary', |
30 | idDet = 'topo-p-detail', | 30 | idDet = 'topo-p-detail', |
31 | - idIns = 'topo-p-instance', | ||
32 | panelOpts = { | 31 | panelOpts = { |
33 | width: 260 | 32 | width: 260 |
34 | }; | 33 | }; |
35 | 34 | ||
36 | - // internal state | 35 | + // panels |
37 | - var settings; | ||
38 | - | ||
39 | - | ||
40 | - // SVG elements; | ||
41 | - var fooPane; | ||
42 | - | ||
43 | - // D3 selections; | ||
44 | var summaryPanel, | 36 | var summaryPanel, |
45 | - detailPanel, | 37 | + detailPanel; |
46 | - instancePanel; | ||
47 | - | ||
48 | - // default settings for force layout | ||
49 | - var defaultSettings = { | ||
50 | - foo: 2 | ||
51 | - }; | ||
52 | - | ||
53 | 38 | ||
54 | // ========================== | 39 | // ========================== |
40 | + // *** SHOW SUMMARY *** | ||
55 | 41 | ||
56 | - function addSep(tbody) { | 42 | + function showSummary(data) { |
57 | - tbody.append('tr').append('td').attr('colspan', 2).append('hr'); | 43 | + populateSummary(data); |
58 | - } | 44 | + showSummaryPanel(); |
59 | - | ||
60 | - function addProp(tbody, label, value) { | ||
61 | - var tr = tbody.append('tr'); | ||
62 | - | ||
63 | - function addCell(cls, txt) { | ||
64 | - tr.append('td').attr('class', cls).text(txt); | ||
65 | - } | ||
66 | - addCell('label', label + ' :'); | ||
67 | - addCell('value', value); | ||
68 | } | 45 | } |
69 | 46 | ||
70 | function populateSummary(data) { | 47 | function populateSummary(data) { |
... | @@ -89,9 +66,36 @@ | ... | @@ -89,9 +66,36 @@ |
89 | }); | 66 | }); |
90 | } | 67 | } |
91 | 68 | ||
69 | + function addSep(tbody) { | ||
70 | + tbody.append('tr').append('td').attr('colspan', 2).append('hr'); | ||
71 | + } | ||
72 | + | ||
73 | + function addProp(tbody, label, value) { | ||
74 | + var tr = tbody.append('tr'); | ||
75 | + | ||
76 | + function addCell(cls, txt) { | ||
77 | + tr.append('td').attr('class', cls).text(txt); | ||
78 | + } | ||
79 | + addCell('label', label + ' :'); | ||
80 | + addCell('value', value); | ||
81 | + } | ||
82 | + | ||
92 | function showSummaryPanel() { | 83 | function showSummaryPanel() { |
93 | summaryPanel.show(); | 84 | summaryPanel.show(); |
85 | + // TODO: augment, once we have the details pane also | ||
86 | + } | ||
94 | 87 | ||
88 | + // ========================== | ||
89 | + | ||
90 | + function initPanels() { | ||
91 | + summaryPanel = ps.createPanel(idSum, panelOpts); | ||
92 | + detailPanel = ps.createPanel(idDet, panelOpts); | ||
93 | + } | ||
94 | + | ||
95 | + function destroyPanels() { | ||
96 | + ps.destroyPanel(idSum); | ||
97 | + ps.destroyPanel(idDet); | ||
98 | + summaryPanel = detailPanel = null; | ||
95 | } | 99 | } |
96 | 100 | ||
97 | // ========================== | 101 | // ========================== |
... | @@ -105,22 +109,6 @@ | ... | @@ -105,22 +109,6 @@ |
105 | ps = _ps_; | 109 | ps = _ps_; |
106 | gs = _gs_; | 110 | gs = _gs_; |
107 | 111 | ||
108 | - function initPanels() { | ||
109 | - summaryPanel = ps.createPanel(idSum, panelOpts); | ||
110 | - // TODO: set up detail and instance panels.. | ||
111 | - } | ||
112 | - | ||
113 | - function destroyPanels() { | ||
114 | - ps.destroyPanel(idSum); | ||
115 | - summaryPanel = null; | ||
116 | - // TODO: destroy detail and instance panels.. | ||
117 | - } | ||
118 | - | ||
119 | - function showSummary(payload) { | ||
120 | - populateSummary(payload); | ||
121 | - showSummaryPanel(); | ||
122 | - } | ||
123 | - | ||
124 | return { | 112 | return { |
125 | initPanels: initPanels, | 113 | initPanels: initPanels, |
126 | destroyPanels: destroyPanels, | 114 | destroyPanels: destroyPanels, | ... | ... |
... | @@ -84,6 +84,13 @@ describe('factory: fw/layer/panel.js', function () { | ... | @@ -84,6 +84,13 @@ describe('factory: fw/layer/panel.js', function () { |
84 | expect(el.style('width')).toEqual('200px'); | 84 | expect(el.style('width')).toEqual('200px'); |
85 | }); | 85 | }); |
86 | 86 | ||
87 | + it('should provide an api of panel functions', function () { | ||
88 | + var p = ps.createPanel('foo'); | ||
89 | + expect(fs.areFunctions(p, [ | ||
90 | + 'show', 'hide', 'empty', 'append', 'width', 'height', 'isVisible', 'el' | ||
91 | + ])).toBeTruthy(); | ||
92 | + }); | ||
93 | + | ||
87 | it('should complain when a duplicate ID is used', function () { | 94 | it('should complain when a duplicate ID is used', function () { |
88 | spyOn($log, 'warn'); | 95 | spyOn($log, 'warn'); |
89 | var p = ps.createPanel('foo'); | 96 | var p = ps.createPanel('foo'); | ... | ... |
... | @@ -252,7 +252,7 @@ describe('factory: fw/svg/glyph.js', function() { | ... | @@ -252,7 +252,7 @@ describe('factory: fw/svg/glyph.js', function() { |
252 | 252 | ||
253 | it('should add a glyph with default size', function () { | 253 | it('should add a glyph with default size', function () { |
254 | gs.init(); | 254 | gs.init(); |
255 | - gs.addGlyph(svg, 'crown'); | 255 | + var retval = gs.addGlyph(svg, 'crown'); |
256 | var what = svg.selectAll('use'); | 256 | var what = svg.selectAll('use'); |
257 | expect(what.size()).toEqual(1); | 257 | expect(what.size()).toEqual(1); |
258 | expect(what.attr('width')).toEqual('40'); | 258 | expect(what.attr('width')).toEqual('40'); |
... | @@ -260,6 +260,10 @@ describe('factory: fw/svg/glyph.js', function() { | ... | @@ -260,6 +260,10 @@ describe('factory: fw/svg/glyph.js', function() { |
260 | expect(what.attr('xlink:href')).toEqual('#crown'); | 260 | expect(what.attr('xlink:href')).toEqual('#crown'); |
261 | expect(what.classed('glyph')).toBeTruthy(); | 261 | expect(what.classed('glyph')).toBeTruthy(); |
262 | expect(what.classed('overlay')).toBeFalsy(); | 262 | expect(what.classed('overlay')).toBeFalsy(); |
263 | + | ||
264 | + // check a couple on retval, which should be the same thing.. | ||
265 | + expect(retval.attr('xlink:href')).toEqual('#crown'); | ||
266 | + expect(retval.classed('glyph')).toBeTruthy(); | ||
263 | }); | 267 | }); |
264 | 268 | ||
265 | it('should add a glyph with given size', function () { | 269 | it('should add a glyph with given size', function () { | ... | ... |
... | @@ -43,7 +43,13 @@ describe('factory: fw/svg/svgUtil.js', function() { | ... | @@ -43,7 +43,13 @@ describe('factory: fw/svg/svgUtil.js', function() { |
43 | ])).toBeTruthy(); | 43 | ])).toBeTruthy(); |
44 | }); | 44 | }); |
45 | 45 | ||
46 | - // TODO: add unit tests for drag behavior etc. | 46 | + |
47 | + // TODO: add unit tests for drag behavior | ||
48 | + // TODO: add unit tests for loadGlow | ||
49 | + // TODO: add unit tests for cat7 | ||
50 | + | ||
51 | + | ||
52 | + // === translate() | ||
47 | 53 | ||
48 | it('should translate from two args', function () { | 54 | it('should translate from two args', function () { |
49 | expect(sus.translate(1,2)).toEqual('translate(1,2)'); | 55 | expect(sus.translate(1,2)).toEqual('translate(1,2)'); |
... | @@ -53,4 +59,14 @@ describe('factory: fw/svg/svgUtil.js', function() { | ... | @@ -53,4 +59,14 @@ describe('factory: fw/svg/svgUtil.js', function() { |
53 | expect(sus.translate([3,4])).toEqual('translate(3,4)'); | 59 | expect(sus.translate([3,4])).toEqual('translate(3,4)'); |
54 | }); | 60 | }); |
55 | 61 | ||
62 | + | ||
63 | + // === stripPx() | ||
64 | + | ||
65 | + it('should not affect a number', function () { | ||
66 | + expect(sus.stripPx('4')).toEqual('4'); | ||
67 | + }); | ||
68 | + | ||
69 | + it('should remove trailing px', function () { | ||
70 | + expect(sus.stripPx('4px')).toEqual('4'); | ||
71 | + }); | ||
56 | }); | 72 | }); | ... | ... |
-
Please register or login to post a comment