blob: 31d89fa9a951049ae71ef2251a6c977193f5d684 [file] [log] [blame]
Simon Hunt195cb382014-11-03 17:50:51 -08001/*
2 * Copyright 2014 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 -- Base Framework
19
20 @author Simon Hunt
21 */
22
23(function ($) {
24 'use strict';
25 var tsI = new Date().getTime(), // initialize time stamp
26 tsB, // build time stamp
Simon Hunt25248912014-11-04 11:25:48 -080027 mastHeight = 36, // see mast2.css
Simon Hunt142d0032014-11-04 20:13:09 -080028 defaultVid = 'sample';
Simon Hunt195cb382014-11-03 17:50:51 -080029
30
31 // attach our main function to the jQuery object
32 $.onos = function (options) {
Simon Hunt25248912014-11-04 11:25:48 -080033 var uiApi,
34 viewApi,
Simon Hunt1a9eff92014-11-07 11:06:34 -080035 navApi,
36 libApi;
Simon Hunt25248912014-11-04 11:25:48 -080037
38 var defaultOptions = {
Simon Hunt142d0032014-11-04 20:13:09 -080039 trace: false,
40 startVid: defaultVid
Simon Hunt25248912014-11-04 11:25:48 -080041 };
42
43 // compute runtime settings
44 var settings = $.extend({}, defaultOptions, options);
Simon Hunt195cb382014-11-03 17:50:51 -080045
46 // internal state
47 var views = {},
48 current = {
49 view: null,
50 ctx: ''
51 },
52 built = false,
Simon Hunt0df1b1d2014-11-04 22:58:29 -080053 errorCount = 0,
Simon Hunt934c3ce2014-11-05 11:45:07 -080054 keyHandler = {
55 fn: null,
56 map: {}
57 };
Simon Hunt195cb382014-11-03 17:50:51 -080058
59 // DOM elements etc.
Simon Huntdb9eb072014-11-04 19:12:46 -080060 var $view,
61 $mastRadio;
Simon Hunt195cb382014-11-03 17:50:51 -080062
63
Simon Hunt0df1b1d2014-11-04 22:58:29 -080064 function whatKey(code) {
65 switch (code) {
66 case 13: return 'enter';
67 case 16: return 'shift';
68 case 17: return 'ctrl';
69 case 18: return 'alt';
70 case 27: return 'esc';
71 case 32: return 'space';
72 case 37: return 'leftArrow';
73 case 38: return 'upArrow';
74 case 39: return 'rightArrow';
75 case 40: return 'downArrow';
76 case 91: return 'cmdLeft';
77 case 93: return 'cmdRight';
78 default:
79 if ((code >= 48 && code <= 57) ||
80 (code >= 65 && code <= 90)) {
81 return String.fromCharCode(code);
82 } else if (code >= 112 && code <= 123) {
83 return 'F' + (code - 111);
84 }
85 return '.';
86 }
87 }
88
89
Simon Hunt195cb382014-11-03 17:50:51 -080090 // ..........................................................
91 // Internal functions
92
93 // throw an error
94 function throwError(msg) {
95 // separate function, as we might add tracing here too, later
96 throw new Error(msg);
97 }
98
99 function doError(msg) {
100 errorCount++;
Simon Hunt25248912014-11-04 11:25:48 -0800101 console.error(msg);
102 }
103
104 function trace(msg) {
105 if (settings.trace) {
106 console.log(msg);
107 }
108 }
109
110 function traceFn(fn, params) {
111 if (settings.trace) {
112 console.log('*FN* ' + fn + '(...): ' + params);
113 }
Simon Hunt195cb382014-11-03 17:50:51 -0800114 }
115
116 // hash navigation
117 function hash() {
118 var hash = window.location.hash,
119 redo = false,
120 view,
121 t;
122
Simon Hunt25248912014-11-04 11:25:48 -0800123 traceFn('hash', hash);
124
Simon Hunt195cb382014-11-03 17:50:51 -0800125 if (!hash) {
Simon Hunt142d0032014-11-04 20:13:09 -0800126 hash = settings.startVid;
Simon Hunt195cb382014-11-03 17:50:51 -0800127 redo = true;
128 }
129
130 t = parseHash(hash);
131 if (!t || !t.vid) {
132 doError('Unable to parse target hash: ' + hash);
133 }
134
135 view = views[t.vid];
136 if (!view) {
137 doError('No view defined with id: ' + t.vid);
138 }
139
140 if (redo) {
141 window.location.hash = makeHash(t);
142 // the above will result in a hashchange event, invoking
143 // this function again
144 } else {
145 // hash was not modified... navigate to where we need to be
146 navigate(hash, view, t);
147 }
Simon Hunt195cb382014-11-03 17:50:51 -0800148 }
149
150 function parseHash(s) {
151 // extract navigation coordinates from the supplied string
152 // "vid,ctx" --> { vid:vid, ctx:ctx }
Simon Hunt25248912014-11-04 11:25:48 -0800153 traceFn('parseHash', s);
Simon Hunt195cb382014-11-03 17:50:51 -0800154
155 var m = /^[#]{0,1}(\S+),(\S*)$/.exec(s);
156 if (m) {
157 return { vid: m[1], ctx: m[2] };
158 }
159
160 m = /^[#]{0,1}(\S+)$/.exec(s);
161 return m ? { vid: m[1] } : null;
162 }
163
164 function makeHash(t, ctx) {
Simon Hunt25248912014-11-04 11:25:48 -0800165 traceFn('makeHash');
Simon Hunt195cb382014-11-03 17:50:51 -0800166 // make a hash string from the given navigation coordinates.
167 // if t is not an object, then it is a vid
168 var h = t,
169 c = ctx || '';
170
171 if ($.isPlainObject(t)) {
172 h = t.vid;
173 c = t.ctx || '';
174 }
175
176 if (c) {
177 h += ',' + c;
178 }
Simon Hunt25248912014-11-04 11:25:48 -0800179 trace('hash = "' + h + '"');
Simon Hunt195cb382014-11-03 17:50:51 -0800180 return h;
181 }
182
183 function navigate(hash, view, t) {
Simon Hunt25248912014-11-04 11:25:48 -0800184 traceFn('navigate', view.vid);
Simon Hunt195cb382014-11-03 17:50:51 -0800185 // closePanes() // flyouts etc.
Simon Hunt25248912014-11-04 11:25:48 -0800186 // updateNav() // accordion / selected nav item etc.
Simon Hunt195cb382014-11-03 17:50:51 -0800187 createView(view);
188 setView(view, hash, t);
189 }
190
191 function reportBuildErrors() {
Simon Hunt25248912014-11-04 11:25:48 -0800192 traceFn('reportBuildErrors');
Simon Hunt195cb382014-11-03 17:50:51 -0800193 // TODO: validate registered views / nav-item linkage etc.
194 console.log('(no build errors)');
195 }
196
Simon Hunt25248912014-11-04 11:25:48 -0800197 // returns the reference if it is a function, null otherwise
198 function isF(f) {
199 return $.isFunction(f) ? f : null;
200 }
201
Simon Hunt195cb382014-11-03 17:50:51 -0800202 // ..........................................................
203 // View life-cycle functions
204
Simon Hunt25248912014-11-04 11:25:48 -0800205 function setViewDimensions(sel) {
206 var w = window.innerWidth,
207 h = window.innerHeight - mastHeight;
208 sel.each(function () {
209 $(this)
210 .css('width', w + 'px')
211 .css('height', h + 'px')
212 });
213 }
214
Simon Hunt195cb382014-11-03 17:50:51 -0800215 function createView(view) {
216 var $d;
Simon Hunt25248912014-11-04 11:25:48 -0800217
Simon Hunt195cb382014-11-03 17:50:51 -0800218 // lazy initialization of the view
219 if (view && !view.$div) {
Simon Hunt25248912014-11-04 11:25:48 -0800220 trace('creating view for ' + view.vid);
Simon Hunt195cb382014-11-03 17:50:51 -0800221 $d = $view.append('div')
222 .attr({
Simon Hunt25248912014-11-04 11:25:48 -0800223 id: view.vid,
224 class: 'onosView'
Simon Hunt195cb382014-11-03 17:50:51 -0800225 });
Simon Hunt25248912014-11-04 11:25:48 -0800226 setViewDimensions($d);
227 view.$div = $d; // cache a reference to the D3 selection
Simon Hunt195cb382014-11-03 17:50:51 -0800228 }
229 }
230
231 function setView(view, hash, t) {
Simon Hunt25248912014-11-04 11:25:48 -0800232 traceFn('setView', view.vid);
Simon Hunt195cb382014-11-03 17:50:51 -0800233 // set the specified view as current, while invoking the
234 // appropriate life-cycle callbacks
235
236 // if there is a current view, and it is not the same as
237 // the incoming view, then unload it...
Simon Hunt25248912014-11-04 11:25:48 -0800238 if (current.view && (current.view.vid !== view.vid)) {
Simon Hunt195cb382014-11-03 17:50:51 -0800239 current.view.unload();
Simon Huntdb9eb072014-11-04 19:12:46 -0800240
Simon Hunt0df1b1d2014-11-04 22:58:29 -0800241 // detach radio buttons, key handlers, etc.
242 $('#mastRadio').children().detach();
243 keyHandler.fn = null;
244 keyHandler.map = {};
Simon Hunt195cb382014-11-03 17:50:51 -0800245 }
246
247 // cache new view and context
248 current.view = view;
249 current.ctx = t.ctx || '';
250
Simon Hunt195cb382014-11-03 17:50:51 -0800251 // preload is called only once, after the view is in the DOM
252 if (!view.preloaded) {
Simon Hunt25248912014-11-04 11:25:48 -0800253 view.preload(current.ctx);
254 view.preloaded = true;
Simon Hunt195cb382014-11-03 17:50:51 -0800255 }
256
257 // clear the view of stale data
258 view.reset();
259
260 // load the view
Simon Hunt25248912014-11-04 11:25:48 -0800261 view.load(current.ctx);
Simon Hunt195cb382014-11-03 17:50:51 -0800262 }
263
Simon Huntdb9eb072014-11-04 19:12:46 -0800264 // generate 'unique' id by prefixing view id
Simon Hunt934c3ce2014-11-05 11:45:07 -0800265 function makeUid(view, id) {
Simon Huntdb9eb072014-11-04 19:12:46 -0800266 return view.vid + '-' + id;
267 }
268
269 // restore id by removing view id prefix
Simon Hunt934c3ce2014-11-05 11:45:07 -0800270 function unmakeUid(view, uid) {
Simon Huntdb9eb072014-11-04 19:12:46 -0800271 var re = new RegExp('^' + view.vid + '-');
272 return uid.replace(re, '');
273 }
274
Simon Hunt934c3ce2014-11-05 11:45:07 -0800275 function setRadioButtons(vid, btnSet) {
Simon Huntdb9eb072014-11-04 19:12:46 -0800276 var view = views[vid],
277 btnG;
278
279 // lazily create the buttons...
280 if (!(btnG = view.radioButtons)) {
281 btnG = d3.select(document.createElement('div'));
Simon Hunt934c3ce2014-11-05 11:45:07 -0800282 btnG.buttonDef = {};
Simon Huntdb9eb072014-11-04 19:12:46 -0800283
284 btnSet.forEach(function (btn, i) {
285 var bid = btn.id || 'b' + i,
286 txt = btn.text || 'Button #' + i,
Simon Hunt934c3ce2014-11-05 11:45:07 -0800287 uid = makeUid(view, bid),
288 button = btnG.append('span')
Simon Huntdb9eb072014-11-04 19:12:46 -0800289 .attr({
Simon Hunt934c3ce2014-11-05 11:45:07 -0800290 id: uid,
Simon Huntdb9eb072014-11-04 19:12:46 -0800291 class: 'radio'
292 })
293 .text(txt);
Simon Hunt934c3ce2014-11-05 11:45:07 -0800294
295 btnG.buttonDef[uid] = btn;
296
Simon Huntdb9eb072014-11-04 19:12:46 -0800297 if (i === 0) {
Simon Hunt934c3ce2014-11-05 11:45:07 -0800298 button.classed('active', true);
Simon Huntdb9eb072014-11-04 19:12:46 -0800299 }
300 });
301
302 btnG.selectAll('span')
303 .on('click', function (d) {
Simon Hunt934c3ce2014-11-05 11:45:07 -0800304 var button = d3.select(this),
305 uid = button.attr('id'),
306 btn = btnG.buttonDef[uid],
307 act = button.classed('active');
Simon Huntdb9eb072014-11-04 19:12:46 -0800308
309 if (!act) {
Simon Hunt934c3ce2014-11-05 11:45:07 -0800310 btnG.selectAll('span').classed('active', false);
311 button.classed('active', true);
312 if (isF(btn.cb)) {
313 btn.cb(view.token(), btn);
314 }
Simon Huntdb9eb072014-11-04 19:12:46 -0800315 }
316 });
317
318 view.radioButtons = btnG;
319 }
320
321 // attach the buttons to the masthead
322 $mastRadio.node().appendChild(btnG.node());
323 }
324
Simon Hunt0df1b1d2014-11-04 22:58:29 -0800325 function setKeyBindings(keyArg) {
326 if ($.isFunction(keyArg)) {
327 // set general key handler callback
328 keyHandler.fn = keyArg;
329 } else {
330 // set specific key filter map
331 keyHandler.map = keyArg;
332 }
333 }
334
Simon Hunt1a9eff92014-11-07 11:06:34 -0800335 var alerts = {
336 open: false,
337 count: 0
338 };
339
340 function createAlerts() {
341 var al = d3.select('#alerts')
342 .style('display', 'block');
343 al.append('span')
344 .attr('class', 'close')
345 .text('X')
346 .on('click', closeAlerts);
347 al.append('pre');
348 alerts.open = true;
349 alerts.count = 0;
350 }
351
352 function closeAlerts() {
353 d3.select('#alerts')
354 .style('display', 'none');
355 d3.select('#alerts span').remove();
356 d3.select('#alerts pre').remove();
357 alerts.open = false;
358 }
359
360 function addAlert(msg) {
361 var lines,
362 oldContent;
363
364 if (alerts.count) {
365 oldContent = d3.select('#alerts pre').html();
366 }
367
368 lines = msg.split('\n');
369 lines[0] += ' '; // spacing so we don't crowd 'X'
370 lines = lines.join('\n');
371
372 if (oldContent) {
373 lines += '\n----\n' + oldContent;
374 }
375
376 d3.select('#alerts pre').html(lines);
377 alerts.count++;
378 }
379
380 function doAlert(msg) {
381 if (!alerts.open) {
382 createAlerts();
383 }
384 addAlert(msg);
385 }
386
Simon Hunt0df1b1d2014-11-04 22:58:29 -0800387 function keyIn() {
388 var event = d3.event,
389 keyCode = event.keyCode,
390 key = whatKey(keyCode),
391 cb = isF(keyHandler.map[key]) || isF(keyHandler.fn);
392
393 if (cb) {
394 cb(current.view.token(), key, keyCode, event);
395 }
396 }
397
Simon Hunt25248912014-11-04 11:25:48 -0800398 function resize(e) {
399 d3.selectAll('.onosView').call(setViewDimensions);
400 // allow current view to react to resize event...
Simon Hunt195cb382014-11-03 17:50:51 -0800401 if (current.view) {
Simon Hunt25248912014-11-04 11:25:48 -0800402 current.view.resize(current.ctx);
Simon Hunt195cb382014-11-03 17:50:51 -0800403 }
404 }
405
406 // ..........................................................
407 // View class
408 // Captures state information about a view.
409
410 // Constructor
411 // vid : view id
412 // nid : id of associated nav-item (optional)
Simon Hunt25248912014-11-04 11:25:48 -0800413 // cb : callbacks (preload, reset, load, unload, resize, error)
Simon Hunt195cb382014-11-03 17:50:51 -0800414 function View(vid) {
415 var av = 'addView(): ',
416 args = Array.prototype.slice.call(arguments),
417 nid,
Simon Hunt25248912014-11-04 11:25:48 -0800418 cb;
Simon Hunt195cb382014-11-03 17:50:51 -0800419
420 args.shift(); // first arg is always vid
421 if (typeof args[0] === 'string') { // nid specified
422 nid = args.shift();
423 }
424 cb = args.shift();
Simon Hunt195cb382014-11-03 17:50:51 -0800425
426 this.vid = vid;
427
428 if (validateViewArgs(vid)) {
429 this.nid = nid; // explicit navitem id (can be null)
430 this.cb = $.isPlainObject(cb) ? cb : {}; // callbacks
Simon Huntdb9eb072014-11-04 19:12:46 -0800431 this.$div = null; // view not yet added to DOM
432 this.radioButtons = null; // no radio buttons yet
433 this.ok = true; // valid view
Simon Hunt195cb382014-11-03 17:50:51 -0800434 }
Simon Hunt195cb382014-11-03 17:50:51 -0800435 }
436
437 function validateViewArgs(vid) {
Simon Hunt25248912014-11-04 11:25:48 -0800438 var av = "ui.addView(...): ",
439 ok = false;
Simon Hunt195cb382014-11-03 17:50:51 -0800440 if (typeof vid !== 'string' || !vid) {
441 doError(av + 'vid required');
442 } else if (views[vid]) {
443 doError(av + 'View ID "' + vid + '" already exists');
444 } else {
445 ok = true;
446 }
447 return ok;
448 }
449
450 var viewInstanceMethods = {
Simon Hunt25248912014-11-04 11:25:48 -0800451 token: function () {
Simon Hunt195cb382014-11-03 17:50:51 -0800452 return {
Simon Hunt25248912014-11-04 11:25:48 -0800453 // attributes
Simon Hunt195cb382014-11-03 17:50:51 -0800454 vid: this.vid,
455 nid: this.nid,
Simon Hunt25248912014-11-04 11:25:48 -0800456 $div: this.$div,
457
458 // functions
459 width: this.width,
Simon Huntdb9eb072014-11-04 19:12:46 -0800460 height: this.height,
Simon Hunt142d0032014-11-04 20:13:09 -0800461 uid: this.uid,
Simon Hunt0df1b1d2014-11-04 22:58:29 -0800462 setRadio: this.setRadio,
Simon Huntc7ee0662014-11-05 16:44:37 -0800463 setKeys: this.setKeys,
Simon Hunt1a9eff92014-11-07 11:06:34 -0800464 dataLoadError: this.dataLoadError,
465 alert: this.alert
Simon Hunt195cb382014-11-03 17:50:51 -0800466 }
Simon Hunt25248912014-11-04 11:25:48 -0800467 },
468
469 preload: function (ctx) {
470 var c = ctx || '',
471 fn = isF(this.cb.preload);
472 traceFn('View.preload', this.vid + ', ' + c);
473 if (fn) {
474 trace('PRELOAD cb for ' + this.vid);
475 fn(this.token(), c);
476 }
477 },
478
479 reset: function () {
480 var fn = isF(this.cb.reset);
481 traceFn('View.reset', this.vid);
482 if (fn) {
483 trace('RESET cb for ' + this.vid);
484 fn(this.token());
485 } else if (this.cb.reset === true) {
486 // boolean true signifies "clear view"
487 trace(' [true] cleaing view...');
488 viewApi.empty();
489 }
490 },
491
492 load: function (ctx) {
493 var c = ctx || '',
494 fn = isF(this.cb.load);
495 traceFn('View.load', this.vid + ', ' + c);
496 this.$div.classed('currentView', true);
497 // TODO: add radio button set, if needed
498 if (fn) {
499 trace('LOAD cb for ' + this.vid);
500 fn(this.token(), c);
501 }
502 },
503
504 unload: function () {
505 var fn = isF(this.cb.unload);
506 traceFn('View.unload', this.vid);
507 this.$div.classed('currentView', false);
508 // TODO: remove radio button set, if needed
509 if (fn) {
510 trace('UNLOAD cb for ' + this.vid);
511 fn(this.token());
512 }
513 },
514
515 resize: function (ctx) {
516 var c = ctx || '',
517 fn = isF(this.cb.resize),
518 w = this.width(),
519 h = this.height();
520 traceFn('View.resize', this.vid + '/' + c +
521 ' [' + w + 'x' + h + ']');
522 if (fn) {
523 trace('RESIZE cb for ' + this.vid);
524 fn(this.token(), c);
525 }
526 },
527
528 error: function (ctx) {
529 var c = ctx || '',
530 fn = isF(this.cb.error);
531 traceFn('View.error', this.vid + ', ' + c);
532 if (fn) {
533 trace('ERROR cb for ' + this.vid);
534 fn(this.token(), c);
535 }
536 },
537
538 width: function () {
539 return $(this.$div.node()).width();
540 },
541
542 height: function () {
543 return $(this.$div.node()).height();
Simon Huntdb9eb072014-11-04 19:12:46 -0800544 },
Simon Hunt25248912014-11-04 11:25:48 -0800545
Simon Hunt934c3ce2014-11-05 11:45:07 -0800546 setRadio: function (btnSet) {
547 setRadioButtons(this.vid, btnSet);
Simon Hunt142d0032014-11-04 20:13:09 -0800548 },
549
Simon Hunt0df1b1d2014-11-04 22:58:29 -0800550 setKeys: function (keyArg) {
551 setKeyBindings(keyArg);
552 },
553
Simon Hunt142d0032014-11-04 20:13:09 -0800554 uid: function (id) {
Simon Hunt934c3ce2014-11-05 11:45:07 -0800555 return makeUid(this, id);
Simon Huntc7ee0662014-11-05 16:44:37 -0800556 },
557
Simon Hunt1a9eff92014-11-07 11:06:34 -0800558 // TODO : implement custom dialogs
559
560 // Consider enhancing alert mechanism to handle multiples
561 // as individually closable.
562 alert: function (msg) {
563 doAlert(msg);
564 },
Simon Huntc7ee0662014-11-05 16:44:37 -0800565
566 dataLoadError: function (err, url) {
567 var msg = 'Data Load Error\n\n' +
568 err.status + ' -- ' + err.statusText + '\n\n' +
569 'relative-url: "' + url + '"\n\n' +
570 'complete-url: "' + err.responseURL + '"';
Simon Hunt1a9eff92014-11-07 11:06:34 -0800571 this.alert(msg);
Simon Huntdb9eb072014-11-04 19:12:46 -0800572 }
Simon Hunt25248912014-11-04 11:25:48 -0800573
574 // TODO: consider schedule, clearTimer, etc.
Simon Hunt195cb382014-11-03 17:50:51 -0800575 };
576
577 // attach instance methods to the view prototype
578 $.extend(View.prototype, viewInstanceMethods);
579
580 // ..........................................................
Simon Hunt25248912014-11-04 11:25:48 -0800581 // UI API
Simon Hunt195cb382014-11-03 17:50:51 -0800582
Simon Hunt25248912014-11-04 11:25:48 -0800583 uiApi = {
Simon Hunt1a9eff92014-11-07 11:06:34 -0800584 addLib: function (libName, api) {
585 // TODO: validation of args
586 libApi[libName] = api;
587 },
588
589 // TODO: it remains to be seen whether we keep this style of docs
Simon Hunt25248912014-11-04 11:25:48 -0800590 /** @api ui addView( vid, nid, cb )
591 * Adds a view to the UI.
592 * <p>
593 * Views are loaded/unloaded into the view content pane at
594 * appropriate times, by the navigation framework. This method
595 * adds a view to the UI and returns a token object representing
596 * the view. A view's token is always passed as the first
597 * argument to each of the view's life-cycle callback functions.
598 * <p>
599 * Note that if the view is directly referenced by a nav-item,
600 * or in a group of views with one of those views referenced by
601 * a nav-item, then the <i>nid</i> argument can be omitted as
602 * the framework can infer it.
603 * <p>
604 * <i>cb</i> is a plain object containing callback functions:
605 * "preload", "reset", "load", "unload", "resize", "error".
606 * <pre>
607 * function myLoad(view, ctx) { ... }
608 * ...
609 * // short form...
610 * onos.ui.addView('viewId', {
611 * load: myLoad
612 * });
613 * </pre>
614 *
615 * @param vid (string) [*] view ID (a unique DOM element id)
616 * @param nid (string) nav-item ID (a unique DOM element id)
617 * @param cb (object) [*] callbacks object
618 * @return the view token
619 */
620 addView: function (vid, nid, cb) {
621 traceFn('addView', vid);
622 var view = new View(vid, nid, cb),
Simon Hunt195cb382014-11-03 17:50:51 -0800623 token;
624 if (view.ok) {
625 views[vid] = view;
626 token = view.token();
627 } else {
628 token = { vid: view.vid, bad: true };
629 }
630 return token;
631 }
632 };
633
Simon Hunt25248912014-11-04 11:25:48 -0800634 // ..........................................................
635 // View API
636
637 viewApi = {
638 /** @api view empty( )
639 * Empties the current view.
640 * <p>
641 * More specifically, removes all DOM elements from the
642 * current view's display div.
643 */
644 empty: function () {
645 if (!current.view) {
646 return;
647 }
648 current.view.$div.html('');
649 }
650 };
651
652 // ..........................................................
653 // Nav API
654 navApi = {
655
656 };
657
658 // ..........................................................
Simon Hunt1a9eff92014-11-07 11:06:34 -0800659 // Library API
660 libApi = {
661
662 };
663
664 // ..........................................................
Simon Hunt25248912014-11-04 11:25:48 -0800665 // Exported API
666
Simon Hunt195cb382014-11-03 17:50:51 -0800667 // function to be called from index.html to build the ONOS UI
668 function buildOnosUi() {
669 tsB = new Date().getTime();
670 tsI = tsB - tsI; // initialization duration
671
672 console.log('ONOS UI initialized in ' + tsI + 'ms');
673
674 if (built) {
675 throwError("ONOS UI already built!");
676 }
677 built = true;
678
679 $view = d3.select('#view');
Simon Huntdb9eb072014-11-04 19:12:46 -0800680 $mastRadio = d3.select('#mastRadio');
Simon Hunt195cb382014-11-03 17:50:51 -0800681
682 $(window).on('hashchange', hash);
Simon Hunt25248912014-11-04 11:25:48 -0800683 $(window).on('resize', resize);
Simon Hunt195cb382014-11-03 17:50:51 -0800684
Simon Hunt0df1b1d2014-11-04 22:58:29 -0800685 d3.select('body').on('keydown', keyIn);
686
Simon Hunt195cb382014-11-03 17:50:51 -0800687 // Invoke hashchange callback to navigate to content
688 // indicated by the window location hash.
689 hash();
690
691 // If there were any build errors, report them
692 reportBuildErrors();
693 }
694
Simon Hunt195cb382014-11-03 17:50:51 -0800695 // export the api and build-UI function
696 return {
Simon Hunt25248912014-11-04 11:25:48 -0800697 ui: uiApi,
Simon Hunt1a9eff92014-11-07 11:06:34 -0800698 lib: libApi,
699 //view: viewApi,
Simon Hunt25248912014-11-04 11:25:48 -0800700 nav: navApi,
Simon Hunt195cb382014-11-03 17:50:51 -0800701 buildUi: buildOnosUi
702 };
703 };
704
Simon Huntdb9eb072014-11-04 19:12:46 -0800705}(jQuery));