Initial (v.rough) draft of ONOS UI.
Finally got something working, and need to check it in.
Showing
7 changed files
with
711 additions
and
2 deletions
web/gui/src/main/webapp/base.css
0 → 100644
1 | <!DOCTYPE html> | 1 | <!DOCTYPE html> |
2 | +<!-- | ||
3 | + ONOS UI - single page web app | ||
4 | + | ||
5 | + @author Simon Hunt | ||
6 | + --> | ||
2 | <html> | 7 | <html> |
3 | <head> | 8 | <head> |
4 | <title>ONOS GUI</title> | 9 | <title>ONOS GUI</title> |
5 | 10 | ||
6 | <script src="libs/d3.min.js"></script> | 11 | <script src="libs/d3.min.js"></script> |
7 | <script src="libs/jquery-2.1.1.min.js"></script> | 12 | <script src="libs/jquery-2.1.1.min.js"></script> |
13 | + | ||
14 | + <link rel="stylesheet" href="base.css"> | ||
15 | + <link rel="stylesheet" href="onos.css"> | ||
16 | + | ||
17 | + <script src="onosui.js"></script> | ||
18 | + | ||
8 | </head> | 19 | </head> |
9 | <body> | 20 | <body> |
10 | - <h1>ONOS GUI</h1> | 21 | + <div id="frame"> |
11 | - Sort of... | 22 | + <div id="mast"> |
23 | + <span class="title"> | ||
24 | + ONOS Web UI | ||
25 | + </span> | ||
26 | + <span class="right"> | ||
27 | + <span class="radio">[one]</span> | ||
28 | + <span class="radio">[two]</span> | ||
29 | + <span class="radio">[three]</span> | ||
30 | + </span> | ||
31 | + </div> | ||
32 | + <div id="view"></div> | ||
33 | + </div> | ||
34 | + | ||
35 | + // Initialize the UI... | ||
36 | + <script type="text/javascript"> | ||
37 | + var ONOS = $.onos({note: "config, if needed"}); | ||
38 | + </script> | ||
39 | + | ||
40 | + // include module files | ||
41 | + // + mast.js | ||
42 | + // + nav.js | ||
43 | + // + .... application views | ||
44 | + | ||
45 | + // for now, we are just bootstrapping the network visualization | ||
46 | + <script src="network.js" type="text/javascript"></script> | ||
47 | + | ||
48 | + // finally, build the UI | ||
49 | + <script type="text/javascript"> | ||
50 | + $(ONOS.buildUi); | ||
51 | + </script> | ||
52 | + | ||
12 | </body> | 53 | </body> |
13 | </html> | 54 | </html> | ... | ... |
web/gui/src/main/webapp/module-template.js
0 → 100644
1 | +/* | ||
2 | + Module template file. | ||
3 | + | ||
4 | + @author Simon Hunt | ||
5 | + */ | ||
6 | + | ||
7 | +(function (onos) { | ||
8 | + 'use strict'; | ||
9 | + | ||
10 | + var api = onos.api; | ||
11 | + | ||
12 | + // == define your functions here..... | ||
13 | + | ||
14 | + | ||
15 | + // == register views here, with links to lifecycle callbacks | ||
16 | + | ||
17 | +// api.addView('view-id', {/* callbacks */}); | ||
18 | + | ||
19 | + | ||
20 | +}(ONOS)); |
web/gui/src/main/webapp/network.js
0 → 100644
1 | +/* | ||
2 | + ONOS network topology viewer - PoC version 1.0 | ||
3 | + | ||
4 | + @author Simon Hunt | ||
5 | + */ | ||
6 | + | ||
7 | +(function (onos) { | ||
8 | + 'use strict'; | ||
9 | + | ||
10 | + var api = onos.api; | ||
11 | + | ||
12 | + var config = { | ||
13 | + jsonUrl: 'network.json', | ||
14 | + mastHeight: 32, | ||
15 | + force: { | ||
16 | + linkDistance: 150, | ||
17 | + linkStrength: 0.9, | ||
18 | + charge: -400, | ||
19 | + ticksWithoutCollisions: 50, | ||
20 | + marginLR: 20, | ||
21 | + marginTB: 20, | ||
22 | + translate: function() { | ||
23 | + return 'translate(' + | ||
24 | + config.force.marginLR + ',' + | ||
25 | + config.force.marginTB + ')'; | ||
26 | + } | ||
27 | + }, | ||
28 | + labels: { | ||
29 | + padLR: 3, | ||
30 | + padTB: 2, | ||
31 | + marginLR: 3, | ||
32 | + marginTB: 2 | ||
33 | + }, | ||
34 | + constraints: { | ||
35 | + ypos: { | ||
36 | + pkt: 0.3, | ||
37 | + opt: 0.7 | ||
38 | + } | ||
39 | + } | ||
40 | + }, | ||
41 | + view = {}, | ||
42 | + network = {}, | ||
43 | + selected = {}, | ||
44 | + highlighted = null; | ||
45 | + | ||
46 | + | ||
47 | + function loadNetworkView() { | ||
48 | + // Hey, here I am, calling something on the ONOS api: | ||
49 | + api.printTime(); | ||
50 | + | ||
51 | + resize(); | ||
52 | + | ||
53 | + d3.json(config.jsonUrl, function (err, data) { | ||
54 | + if (err) { | ||
55 | + alert('Oops! Error reading JSON...\n\n' + | ||
56 | + 'URL: ' + jsonUrl + '\n\n' + | ||
57 | + 'Error: ' + err.message); | ||
58 | + return; | ||
59 | + } | ||
60 | + console.log("here is the JSON data..."); | ||
61 | + console.log(data); | ||
62 | + | ||
63 | + network.data = data; | ||
64 | + drawNetwork(); | ||
65 | + }); | ||
66 | + | ||
67 | + $(document).on('click', '.select-object', function() { | ||
68 | + // when any object of class "select-object" is clicked... | ||
69 | + // TODO: get a reference to the object via lookup... | ||
70 | + var obj = network.lookup[$(this).data('id')]; | ||
71 | + if (obj) { | ||
72 | + selectObject(obj); | ||
73 | + } | ||
74 | + // stop propagation of event (I think) ... | ||
75 | + return false; | ||
76 | + }); | ||
77 | + | ||
78 | + $(window).on('resize', resize); | ||
79 | + } | ||
80 | + | ||
81 | + | ||
82 | + // ======================================================== | ||
83 | + | ||
84 | + function drawNetwork() { | ||
85 | + $('#view').empty(); | ||
86 | + | ||
87 | + prepareNodesAndLinks(); | ||
88 | + createLayout(); | ||
89 | + console.log("\n\nHere is the augmented network object..."); | ||
90 | + console.warn(network); | ||
91 | + } | ||
92 | + | ||
93 | + function prepareNodesAndLinks() { | ||
94 | + network.lookup = {}; | ||
95 | + network.nodes = []; | ||
96 | + network.links = []; | ||
97 | + | ||
98 | + var nw = network.forceWidth, | ||
99 | + nh = network.forceHeight; | ||
100 | + | ||
101 | + network.data.nodes.forEach(function(n) { | ||
102 | + var ypc = yPosConstraintForNode(n), | ||
103 | + ix = Math.random() * 0.8 * nw + 0.1 * nw, | ||
104 | + iy = ypc * nh, | ||
105 | + node = { | ||
106 | + id: n.id, | ||
107 | + type: n.type, | ||
108 | + status: n.status, | ||
109 | + x: ix, | ||
110 | + y: iy, | ||
111 | + constraint: { | ||
112 | + weight: 0.7, | ||
113 | + y: iy | ||
114 | + } | ||
115 | + }; | ||
116 | + network.lookup[n.id] = node; | ||
117 | + network.nodes.push(node); | ||
118 | + }); | ||
119 | + | ||
120 | + function yPosConstraintForNode(n) { | ||
121 | + return config.constraints.ypos[n.type] || 0.5; | ||
122 | + } | ||
123 | + | ||
124 | + | ||
125 | + network.data.links.forEach(function(n) { | ||
126 | + var src = network.lookup[n.src], | ||
127 | + dst = network.lookup[n.dst], | ||
128 | + id = src.id + "~" + dst.id; | ||
129 | + | ||
130 | + var link = { | ||
131 | + id: id, | ||
132 | + source: src, | ||
133 | + target: dst, | ||
134 | + strength: config.force.linkStrength | ||
135 | + }; | ||
136 | + network.links.push(link); | ||
137 | + }); | ||
138 | + } | ||
139 | + | ||
140 | + function createLayout() { | ||
141 | + | ||
142 | + network.force = d3.layout.force() | ||
143 | + .nodes(network.nodes) | ||
144 | + .links(network.links) | ||
145 | + .linkStrength(function(d) { return d.strength; }) | ||
146 | + .size([network.forceWidth, network.forceHeight]) | ||
147 | + .linkDistance(config.force.linkDistance) | ||
148 | + .charge(config.force.charge) | ||
149 | + .on('tick', tick); | ||
150 | + | ||
151 | + network.svg = d3.select('#view').append('svg') | ||
152 | + .attr('width', view.width) | ||
153 | + .attr('height', view.height) | ||
154 | + .append('g') | ||
155 | + .attr('transform', config.force.translate()); | ||
156 | + | ||
157 | + // TODO: svg.append('defs') | ||
158 | + // TODO: glow/blur stuff | ||
159 | + // TODO: legend (and auto adjust on scroll) | ||
160 | + | ||
161 | + network.link = network.svg.append('g').selectAll('.link') | ||
162 | + .data(network.force.links(), function(d) {return d.id}) | ||
163 | + .enter().append('line') | ||
164 | + .attr('class', 'link'); | ||
165 | + | ||
166 | + // TODO: drag behavior | ||
167 | + // TODO: closest node deselect | ||
168 | + | ||
169 | + // TODO: add drag, mouseover, mouseout behaviors | ||
170 | + network.node = network.svg.selectAll('.node') | ||
171 | + .data(network.force.nodes(), function(d) {return d.id}) | ||
172 | + .enter().append('g') | ||
173 | + .attr('class', 'node') | ||
174 | + .attr('transform', function(d) { | ||
175 | + return translate(d.x, d.y); | ||
176 | + }) | ||
177 | + // .call(network.drag) | ||
178 | + .on('mouseover', function(d) {}) | ||
179 | + .on('mouseout', function(d) {}); | ||
180 | + | ||
181 | + // TODO: augment stroke and fill functions | ||
182 | + network.nodeRect = network.node.append('rect') | ||
183 | + // TODO: css for node rects | ||
184 | + .attr('rx', 5) | ||
185 | + .attr('ry', 5) | ||
186 | + .attr('stroke', function(d) { return '#000'}) | ||
187 | + .attr('fill', function(d) { return '#ddf'}) | ||
188 | + .attr('width', 60) | ||
189 | + .attr('height', 24); | ||
190 | + | ||
191 | + network.node.each(function(d) { | ||
192 | + var node = d3.select(this), | ||
193 | + rect = node.select('rect'); | ||
194 | + var text = node.append('text') | ||
195 | + .text(d.id) | ||
196 | + .attr('dx', '1em') | ||
197 | + .attr('dy', '2.1em'); | ||
198 | + }); | ||
199 | + | ||
200 | + // this function is scheduled to happen soon after the given thread ends | ||
201 | + setTimeout(function() { | ||
202 | + network.node.each(function(d) { | ||
203 | + // for every node, recompute size, padding, etc. so text fits | ||
204 | + var node = d3.select(this), | ||
205 | + text = node.selectAll('text'), | ||
206 | + bounds = {}, | ||
207 | + first = true; | ||
208 | + | ||
209 | + // NOTE: probably unnecessary code if we only have one line. | ||
210 | + }); | ||
211 | + | ||
212 | + network.numTicks = 0; | ||
213 | + network.preventCollisions = false; | ||
214 | + network.force.start(); | ||
215 | + for (var i = 0; i < config.ticksWithoutCollisions; i++) { | ||
216 | + network.force.tick(); | ||
217 | + } | ||
218 | + network.preventCollisions = true; | ||
219 | + $('#view').css('visibility', 'visible'); | ||
220 | + }); | ||
221 | + | ||
222 | + } | ||
223 | + | ||
224 | + function translate(x, y) { | ||
225 | + return 'translate(' + x + ',' + y + ')'; | ||
226 | + } | ||
227 | + | ||
228 | + | ||
229 | + function tick(e) { | ||
230 | + network.numTicks++; | ||
231 | + | ||
232 | + // adjust the y-coord of each node, based on y-pos constraints | ||
233 | +// network.nodes.forEach(function (n) { | ||
234 | +// var z = e.alpha * n.constraint.weight; | ||
235 | +// if (!isNaN(n.constraint.y)) { | ||
236 | +// n.y = (n.constraint.y * z + n.y * (1 - z)); | ||
237 | +// } | ||
238 | +// }); | ||
239 | + | ||
240 | + network.link | ||
241 | + .attr('x1', function(d) { | ||
242 | + return d.source.x; | ||
243 | + }) | ||
244 | + .attr('y1', function(d) { | ||
245 | + return d.source.y; | ||
246 | + }) | ||
247 | + .attr('x2', function(d) { | ||
248 | + return d.target.x; | ||
249 | + }) | ||
250 | + .attr('y2', function(d) { | ||
251 | + return d.target.y; | ||
252 | + }); | ||
253 | + | ||
254 | + network.node | ||
255 | + .attr('transform', function(d) { | ||
256 | + return translate(d.x, d.y); | ||
257 | + }); | ||
258 | + | ||
259 | + } | ||
260 | + | ||
261 | + // $('#docs-close').on('click', function() { | ||
262 | + // deselectObject(); | ||
263 | + // return false; | ||
264 | + // }); | ||
265 | + | ||
266 | + // $(document).on('click', '.select-object', function() { | ||
267 | + // var obj = graph.data[$(this).data('name')]; | ||
268 | + // if (obj) { | ||
269 | + // selectObject(obj); | ||
270 | + // } | ||
271 | + // return false; | ||
272 | + // }); | ||
273 | + | ||
274 | + function selectObject(obj, el) { | ||
275 | + var node; | ||
276 | + if (el) { | ||
277 | + node = d3.select(el); | ||
278 | + } else { | ||
279 | + network.node.each(function(d) { | ||
280 | + if (d == obj) { | ||
281 | + node = d3.select(el = this); | ||
282 | + } | ||
283 | + }); | ||
284 | + } | ||
285 | + if (!node) return; | ||
286 | + | ||
287 | + if (node.classed('selected')) { | ||
288 | + deselectObject(); | ||
289 | + return; | ||
290 | + } | ||
291 | + deselectObject(false); | ||
292 | + | ||
293 | + selected = { | ||
294 | + obj : obj, | ||
295 | + el : el | ||
296 | + }; | ||
297 | + | ||
298 | + highlightObject(obj); | ||
299 | + | ||
300 | + node.classed('selected', true); | ||
301 | + | ||
302 | + // TODO animate incoming info pane | ||
303 | + // resize(true); | ||
304 | + // TODO: check bounds of selected node and scroll into view if needed | ||
305 | + } | ||
306 | + | ||
307 | + function deselectObject(doResize) { | ||
308 | + // Review: logic of 'resize(...)' function. | ||
309 | + if (doResize || typeof doResize == 'undefined') { | ||
310 | + resize(false); | ||
311 | + } | ||
312 | + // deselect all nodes in the network... | ||
313 | + network.node.classed('selected', false); | ||
314 | + selected = {}; | ||
315 | + highlightObject(null); | ||
316 | + } | ||
317 | + | ||
318 | + function highlightObject(obj) { | ||
319 | + if (obj) { | ||
320 | + if (obj != highlighted) { | ||
321 | + // TODO set or clear "inactive" class on nodes, based on criteria | ||
322 | + network.node.classed('inactive', function(d) { | ||
323 | + // return (obj !== d && | ||
324 | + // d.relation(obj.id)); | ||
325 | + return (obj !== d); | ||
326 | + }); | ||
327 | + // TODO: same with links | ||
328 | + network.link.classed('inactive', function(d) { | ||
329 | + return (obj !== d.source && obj !== d.target); | ||
330 | + }); | ||
331 | + } | ||
332 | + highlighted = obj; | ||
333 | + } else { | ||
334 | + if (highlighted) { | ||
335 | + // clear the inactive flag (no longer suppressed visually) | ||
336 | + network.node.classed('inactive', false); | ||
337 | + network.link.classed('inactive', false); | ||
338 | + } | ||
339 | + highlighted = null; | ||
340 | + | ||
341 | + } | ||
342 | + } | ||
343 | + | ||
344 | + function resize(showDetails) { | ||
345 | + console.log("resize() called..."); | ||
346 | + | ||
347 | + var $details = $('#details'); | ||
348 | + | ||
349 | + if (typeof showDetails == 'boolean') { | ||
350 | + var showingDetails = showDetails; | ||
351 | + // TODO: invoke $details.show() or $details.hide()... | ||
352 | + // $details[showingDetails ? 'show' : 'hide'](); | ||
353 | + } | ||
354 | + | ||
355 | + view.height = window.innerHeight - config.mastHeight; | ||
356 | + view.width = window.innerWidth; | ||
357 | + $('#view') | ||
358 | + .css('height', view.height + 'px') | ||
359 | + .css('width', view.width + 'px'); | ||
360 | + | ||
361 | + network.forceWidth = view.width - config.force.marginLR; | ||
362 | + network.forceHeight = view.height - config.force.marginTB; | ||
363 | + } | ||
364 | + | ||
365 | + // ====================================================================== | ||
366 | + // register with the UI framework | ||
367 | + | ||
368 | + api.addView('network', { | ||
369 | + load: loadNetworkView | ||
370 | + }); | ||
371 | + | ||
372 | + | ||
373 | +}(ONOS)); | ||
374 | + |
web/gui/src/main/webapp/network.json
0 → 100644
1 | +{ | ||
2 | + "id": "network-v1", | ||
3 | + "meta": { | ||
4 | + "__comment_1__": "This is sample data for developing the ONOS UI", | ||
5 | + "foo": "bar", | ||
6 | + "zoo": "goo" | ||
7 | + }, | ||
8 | + "nodes": [ | ||
9 | + { | ||
10 | + "id": "switch-1", | ||
11 | + "type": "opt", | ||
12 | + "status": "good" | ||
13 | + }, | ||
14 | + { | ||
15 | + "id": "switch-2", | ||
16 | + "type": "opt", | ||
17 | + "status": "good" | ||
18 | + }, | ||
19 | + { | ||
20 | + "id": "switch-3", | ||
21 | + "type": "opt", | ||
22 | + "status": "good" | ||
23 | + }, | ||
24 | + { | ||
25 | + "id": "switch-4", | ||
26 | + "type": "opt", | ||
27 | + "status": "good" | ||
28 | + }, | ||
29 | + { | ||
30 | + "id": "switch-11", | ||
31 | + "type": "pkt", | ||
32 | + "status": "good" | ||
33 | + }, | ||
34 | + { | ||
35 | + "id": "switch-12", | ||
36 | + "type": "pkt", | ||
37 | + "status": "good" | ||
38 | + }, | ||
39 | + { | ||
40 | + "id": "switch-13", | ||
41 | + "type": "pkt", | ||
42 | + "status": "good" | ||
43 | + } | ||
44 | + ], | ||
45 | + "links": [ | ||
46 | + { "src": "switch-1", "dst": "switch-2" }, | ||
47 | + { "src": "switch-1", "dst": "switch-3" }, | ||
48 | + { "src": "switch-1", "dst": "switch-4" }, | ||
49 | + { "src": "switch-2", "dst": "switch-3" }, | ||
50 | + { "src": "switch-2", "dst": "switch-4" }, | ||
51 | + { "src": "switch-3", "dst": "switch-4" }, | ||
52 | + { "src": "switch-13", "dst": "switch-3" }, | ||
53 | + { "src": "switch-12", "dst": "switch-2" }, | ||
54 | + { "src": "switch-11", "dst": "switch-1" } | ||
55 | + ] | ||
56 | +} |
web/gui/src/main/webapp/onos.css
0 → 100644
1 | +/* | ||
2 | + ONOS CSS file | ||
3 | + | ||
4 | + @author Simon Hunt | ||
5 | + */ | ||
6 | + | ||
7 | +body, html { | ||
8 | + height: 100%; | ||
9 | +} | ||
10 | + | ||
11 | +/* | ||
12 | + * Classes | ||
13 | + */ | ||
14 | + | ||
15 | +span.title { | ||
16 | + color: red; | ||
17 | + font-size: 16pt; | ||
18 | + font-style: italic; | ||
19 | +} | ||
20 | + | ||
21 | +span.radio { | ||
22 | + color: darkslateblue; | ||
23 | +} | ||
24 | + | ||
25 | +span.right { | ||
26 | + float: right; | ||
27 | +} | ||
28 | + | ||
29 | +/* | ||
30 | + * === DEBUGGING ====== | ||
31 | + */ | ||
32 | +svg { | ||
33 | + border: 1px dashed red; | ||
34 | +} | ||
35 | + | ||
36 | + | ||
37 | +/* | ||
38 | + * Network Graph elements ====================================== | ||
39 | + */ | ||
40 | + | ||
41 | +.link { | ||
42 | + fill: none; | ||
43 | + stroke: #666; | ||
44 | + stroke-width: 1.5px; | ||
45 | + opacity: .7; | ||
46 | + /*marker-end: url(#end);*/ | ||
47 | + | ||
48 | + transition: opacity 250ms; | ||
49 | + -webkit-transition: opacity 250ms; | ||
50 | + -moz-transition: opacity 250ms; | ||
51 | +} | ||
52 | + | ||
53 | +marker#end { | ||
54 | + fill: #666; | ||
55 | + stroke: #666; | ||
56 | + stroke-width: 1.5px; | ||
57 | +} | ||
58 | + | ||
59 | +.node rect { | ||
60 | + stroke-width: 1.5px; | ||
61 | + | ||
62 | + transition: opacity 250ms; | ||
63 | + -webkit-transition: opacity 250ms; | ||
64 | + -moz-transition: opacity 250ms; | ||
65 | +} | ||
66 | + | ||
67 | +.node text { | ||
68 | + fill: #000; | ||
69 | + font: 10px sans-serif; | ||
70 | + pointer-events: none; | ||
71 | +} | ||
72 | + | ||
73 | +.node.selected rect { | ||
74 | + filter: url(#blue-glow); | ||
75 | +} | ||
76 | + | ||
77 | +.link.inactive, | ||
78 | +.node.inactive rect, | ||
79 | +.node.inactive text { | ||
80 | + opacity: .2; | ||
81 | +} | ||
82 | + | ||
83 | +.node.inactive.selected rect, | ||
84 | +.node.inactive.selected text { | ||
85 | + opacity: .6; | ||
86 | +} | ||
87 | + | ||
88 | +.legend { | ||
89 | + position: fixed; | ||
90 | +} | ||
91 | + | ||
92 | +.legend .category rect { | ||
93 | + stroke-width: 1px; | ||
94 | +} | ||
95 | + | ||
96 | +.legend .category text { | ||
97 | + fill: #000; | ||
98 | + font: 10px sans-serif; | ||
99 | + pointer-events: none; | ||
100 | +} | ||
101 | + | ||
102 | +/* | ||
103 | + * ============================================================= | ||
104 | + */ | ||
105 | + | ||
106 | +/* | ||
107 | + * Specific structural elements | ||
108 | + */ | ||
109 | + | ||
110 | +#frame { | ||
111 | + width: 100%; | ||
112 | + height: 100%; | ||
113 | + background-color: #ffd; | ||
114 | +} | ||
115 | + | ||
116 | +#mast { | ||
117 | + height: 32px; | ||
118 | + background-color: #dda; | ||
119 | + vertical-align: baseline; | ||
120 | +} | ||
121 | + | ||
122 | +#main { | ||
123 | + background-color: #99b; | ||
124 | +} |
web/gui/src/main/webapp/onosui.js
0 → 100644
1 | +/* | ||
2 | + ONOS UI Framework. | ||
3 | + | ||
4 | + @author Simon Hunt | ||
5 | + */ | ||
6 | + | ||
7 | +(function ($) { | ||
8 | + 'use strict'; | ||
9 | + var tsI = new Date().getTime(), // initialize time stamp | ||
10 | + tsB; // build time stamp | ||
11 | + | ||
12 | + // attach our main function to the jQuery object | ||
13 | + $.onos = function (options) { | ||
14 | + // private namespaces | ||
15 | + var publicApi; // public api | ||
16 | + | ||
17 | + // internal state | ||
18 | + var views = {}, | ||
19 | + currentView = null, | ||
20 | + built = false; | ||
21 | + | ||
22 | + // DOM elements etc. | ||
23 | + var $mast; | ||
24 | + | ||
25 | + | ||
26 | + // various functions.................. | ||
27 | + | ||
28 | + // throw an error | ||
29 | + function throwError(msg) { | ||
30 | + // todo: maybe add tracing later | ||
31 | + throw new Error(msg); | ||
32 | + } | ||
33 | + | ||
34 | + // define all the public api functions... | ||
35 | + publicApi = { | ||
36 | + printTime: function () { | ||
37 | + console.log("the time is " + new Date()); | ||
38 | + }, | ||
39 | + | ||
40 | + addView: function (vid, cb) { | ||
41 | + views[vid] = { | ||
42 | + vid: vid, | ||
43 | + cb: cb | ||
44 | + }; | ||
45 | + // TODO: proper registration of views | ||
46 | + // for now, make the one (and only) view current.. | ||
47 | + currentView = views[vid]; | ||
48 | + } | ||
49 | + }; | ||
50 | + | ||
51 | + // function to be called from index.html to build the ONOS UI | ||
52 | + function buildOnosUi() { | ||
53 | + tsB = new Date().getTime(); | ||
54 | + tsI = tsB - tsI; // initialization duration | ||
55 | + | ||
56 | + console.log('ONOS UI initialized in ' + tsI + 'ms'); | ||
57 | + | ||
58 | + if (built) { | ||
59 | + throwError("ONOS UI already built!"); | ||
60 | + } | ||
61 | + built = true; | ||
62 | + | ||
63 | + // TODO: invoke hash navigation | ||
64 | + // --- report build errors --- | ||
65 | + | ||
66 | + // for now, invoke the one and only load function: | ||
67 | + | ||
68 | + currentView.cb.load(); | ||
69 | + } | ||
70 | + | ||
71 | + | ||
72 | + // export the api and build-UI function | ||
73 | + return { | ||
74 | + api: publicApi, | ||
75 | + buildUi: buildOnosUi | ||
76 | + }; | ||
77 | + }; | ||
78 | + | ||
79 | +}(jQuery)); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or login to post a comment