Simon Hunt

GUI -- augmented hash parsing to include flags (after '?'), which are passed int…

…o view callbacks as a boolean map.
 - moved event test files into sub directories
 - prepared topo2.js for scenario choice via hash context and 'local' (and 'debug') flag.
 - added 'simple' scenario: 2 switches, 1 link, and 2 hosts.
 - augmented topo event dispatch for yet-to-be-implemented event handlers.
 - implemented addHost() event handler.

Change-Id: I06b032684fd4d5f85262d13d58ad10edae23b3ed
Showing 56 changed files with 280 additions and 35 deletions
...@@ -90,6 +90,7 @@ ...@@ -90,6 +90,7 @@
90 <script src="sampleAlt2.js"></script> 90 <script src="sampleAlt2.js"></script>
91 <script src="sampleRadio.js"></script> 91 <script src="sampleRadio.js"></script>
92 <script src="sampleKeys.js"></script> 92 <script src="sampleKeys.js"></script>
93 + <script src="sampleHash.js"></script>
93 94
94 <!-- Contributed (application) views injected here --> 95 <!-- Contributed (application) views injected here -->
95 <!-- TODO: replace with template marker and inject refs server-side --> 96 <!-- TODO: replace with template marker and inject refs server-side -->
......
1 +{
2 + "comments": [
3 + "This scenario steps through adding a host intent."
4 + ],
5 + "title": "Host Intent Scenario",
6 + "params": {
7 + "lastAuto": 0
8 + }
9 +}
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "event": "addDevice",
3 + "payload": {
4 + "id": "of:0000ffffffff0008",
5 + "type": "switch",
6 + "online": false,
7 + "labels": [
8 + "0000ffffffff0008",
9 + "FF:FF:FF:FF:00:08",
10 + "sw-8"
11 + ],
12 + "metaUi": {
13 + "x": 400,
14 + "y": 280
15 + }
16 + }
17 +}
1 +{
2 + "event": "addDevice",
3 + "payload": {
4 + "id": "of:0000ffffffff0003",
5 + "type": "switch",
6 + "online": false,
7 + "labels": [
8 + "0000ffffffff0003",
9 + "FF:FF:FF:FF:00:03",
10 + "sw-3"
11 + ],
12 + "metaUi": {
13 + "x": 800,
14 + "y": 280
15 + }
16 + }
17 +}
1 +{
2 + "event": "addLink",
3 + "payload": {
4 + "src": "of:0000ffffffff0003",
5 + "srcPort": "21",
6 + "dst": "of:0000ffffffff0008",
7 + "dstPort": "20",
8 + "type": "infra",
9 + "linkWidth": 2,
10 + "props" : {
11 + "BW": "70 G"
12 + }
13 + }
14 +}
1 +{
2 + "event": "addHost",
3 + "payload": {
4 + "id": "00:00:00:00:00:03/-1",
5 + "cp": {
6 + "device": "of:0000ffffffff0003",
7 + "port": 1
8 + },
9 + "labels": [
10 + "10.0.0.3",
11 + "00:00:00:00:00:03"
12 + ],
13 + "metaUi": {
14 + }
15 + }
16 +}
1 +{
2 + "event": "addHost",
3 + "payload": {
4 + "id": "00:00:00:00:00:08/-1",
5 + "cp": {
6 + "device": "of:0000ffffffff0008",
7 + "port": 1
8 + },
9 + "labels": [
10 + "10.0.0.8",
11 + "00:00:00:00:00:08"
12 + ],
13 + "metaUi": {
14 + }
15 + }
16 +}
1 +{
2 + "comments": [
3 + "Add two devices and one link (auto), and two hosts."
4 + ],
5 + "title": "Simple Startup Scenario",
6 + "params": {
7 + "lastAuto": 0
8 + }
9 +}
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "comments": [
3 + "This scenario steps through adding devices and links.",
4 + "(Typical 'start-ip' of the view.)"
5 + ],
6 + "title": "Startup Scenario",
7 + "params": {
8 + "lastAuto": 32
9 + }
10 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
52 current = { 52 current = {
53 view: null, 53 view: null,
54 ctx: '', 54 ctx: '',
55 + flags: {},
55 theme: settings.theme 56 theme: settings.theme
56 }, 57 },
57 built = false, 58 built = false,
...@@ -110,6 +111,7 @@ ...@@ -110,6 +111,7 @@
110 function doError(msg) { 111 function doError(msg) {
111 errorCount++; 112 errorCount++;
112 console.error(msg); 113 console.error(msg);
114 + doAlert(msg);
113 } 115 }
114 116
115 function trace(msg) { 117 function trace(msg) {
...@@ -140,7 +142,7 @@ ...@@ -140,7 +142,7 @@
140 142
141 t = parseHash(hash); 143 t = parseHash(hash);
142 if (!t || !t.vid) { 144 if (!t || !t.vid) {
143 - doError('Unable to parse target hash: ' + hash); 145 + doError('Unable to parse target hash: "' + hash + '"');
144 } 146 }
145 147
146 view = views[t.vid]; 148 view = views[t.vid];
...@@ -160,33 +162,72 @@ ...@@ -160,33 +162,72 @@
160 162
161 function parseHash(s) { 163 function parseHash(s) {
162 // extract navigation coordinates from the supplied string 164 // extract navigation coordinates from the supplied string
163 - // "vid,ctx" --> { vid:vid, ctx:ctx } 165 + // "vid,ctx?flag1,flag2" --> { vid:vid, ctx:ctx, flags:{...} }
164 traceFn('parseHash', s); 166 traceFn('parseHash', s);
165 167
166 - var m = /^[#]{0,1}(\S+),(\S*)$/.exec(s); 168 + // look for use of flags, first
169 + var vidctx,
170 + vid,
171 + ctx,
172 + flags,
173 + flagMap,
174 + m;
175 +
176 + // RE that includes flags ('?flag1,flag2')
177 + m = /^[#]{0,1}(.+)\?(.+)$/.exec(s);
167 if (m) { 178 if (m) {
168 - return { vid: m[1], ctx: m[2] }; 179 + vidctx = m[1];
180 + flags = m[2];
181 + flagMap = {};
182 + } else {
183 + // no flags
184 + m = /^[#]{0,1}((.+)(,.+)*)$/.exec(s);
185 + if (m) {
186 + vidctx = m[1];
187 + } else {
188 + // bad hash
189 + return null;
190 + }
191 + }
192 +
193 + vidctx = vidctx.split(',');
194 + vid = vidctx[0];
195 + ctx = vidctx[1];
196 + if (flags) {
197 + flags.split(',').forEach(function (f) {
198 + flagMap[f.trim()] = true;
199 + });
169 } 200 }
170 201
171 - m = /^[#]{0,1}(\S+)$/.exec(s); 202 + return {
172 - return m ? { vid: m[1] } : null; 203 + vid: vid.trim(),
204 + ctx: ctx ? ctx.trim() : '',
205 + flags: flagMap
206 + };
207 +
173 } 208 }
174 209
175 - function makeHash(t, ctx) { 210 + function makeHash(t, ctx, flags) {
176 traceFn('makeHash'); 211 traceFn('makeHash');
177 - // make a hash string from the given navigation coordinates. 212 + // make a hash string from the given navigation coordinates,
213 + // and optional flags map.
178 // if t is not an object, then it is a vid 214 // if t is not an object, then it is a vid
179 var h = t, 215 var h = t,
180 - c = ctx || ''; 216 + c = ctx || '',
217 + f = $.isPlainObject(flags) ? flags : null;
181 218
182 if ($.isPlainObject(t)) { 219 if ($.isPlainObject(t)) {
183 h = t.vid; 220 h = t.vid;
184 c = t.ctx || ''; 221 c = t.ctx || '';
222 + f = t.flags || null;
185 } 223 }
186 224
187 if (c) { 225 if (c) {
188 h += ',' + c; 226 h += ',' + c;
189 } 227 }
228 + if (f) {
229 + h += '?' + d3.map(f).keys().join(',');
230 + }
190 trace('hash = "' + h + '"'); 231 trace('hash = "' + h + '"');
191 return h; 232 return h;
192 } 233 }
...@@ -244,6 +285,9 @@ ...@@ -244,6 +285,9 @@
244 // set the specified view as current, while invoking the 285 // set the specified view as current, while invoking the
245 // appropriate life-cycle callbacks 286 // appropriate life-cycle callbacks
246 287
288 + // first, we'll start by closing the alerts pane, if open
289 + closeAlerts();
290 +
247 // if there is a current view, and it is not the same as 291 // if there is a current view, and it is not the same as
248 // the incoming view, then unload it... 292 // the incoming view, then unload it...
249 if (current.view && (current.view.vid !== view.vid)) { 293 if (current.view && (current.view.vid !== view.vid)) {
...@@ -258,10 +302,11 @@ ...@@ -258,10 +302,11 @@
258 // cache new view and context 302 // cache new view and context
259 current.view = view; 303 current.view = view;
260 current.ctx = t.ctx || ''; 304 current.ctx = t.ctx || '';
305 + current.flags = t.flags || {};
261 306
262 // preload is called only once, after the view is in the DOM 307 // preload is called only once, after the view is in the DOM
263 if (!view.preloaded) { 308 if (!view.preloaded) {
264 - view.preload(current.ctx); 309 + view.preload(current.ctx, current.flags);
265 view.preloaded = true; 310 view.preloaded = true;
266 } 311 }
267 312
...@@ -269,7 +314,7 @@ ...@@ -269,7 +314,7 @@
269 view.reset(); 314 view.reset();
270 315
271 // load the view 316 // load the view
272 - view.load(current.ctx); 317 + view.load(current.ctx, current.flags);
273 } 318 }
274 319
275 // generate 'unique' id by prefixing view id 320 // generate 'unique' id by prefixing view id
...@@ -454,7 +499,7 @@ ...@@ -454,7 +499,7 @@
454 d3.selectAll('.onosView').call(setViewDimensions); 499 d3.selectAll('.onosView').call(setViewDimensions);
455 // allow current view to react to resize event... 500 // allow current view to react to resize event...
456 if (current.view) { 501 if (current.view) {
457 - current.view.resize(current.ctx); 502 + current.view.resize(current.ctx, current.flags);
458 } 503 }
459 } 504 }
460 505
...@@ -521,13 +566,13 @@ ...@@ -521,13 +566,13 @@
521 } 566 }
522 }, 567 },
523 568
524 - preload: function (ctx) { 569 + preload: function (ctx, flags) {
525 var c = ctx || '', 570 var c = ctx || '',
526 fn = isF(this.cb.preload); 571 fn = isF(this.cb.preload);
527 traceFn('View.preload', this.vid + ', ' + c); 572 traceFn('View.preload', this.vid + ', ' + c);
528 if (fn) { 573 if (fn) {
529 trace('PRELOAD cb for ' + this.vid); 574 trace('PRELOAD cb for ' + this.vid);
530 - fn(this.token(), c); 575 + fn(this.token(), c, flags);
531 } 576 }
532 }, 577 },
533 578
...@@ -544,15 +589,14 @@ ...@@ -544,15 +589,14 @@
544 } 589 }
545 }, 590 },
546 591
547 - load: function (ctx) { 592 + load: function (ctx, flags) {
548 var c = ctx || '', 593 var c = ctx || '',
549 fn = isF(this.cb.load); 594 fn = isF(this.cb.load);
550 traceFn('View.load', this.vid + ', ' + c); 595 traceFn('View.load', this.vid + ', ' + c);
551 this.$div.classed('currentView', true); 596 this.$div.classed('currentView', true);
552 - // TODO: add radio button set, if needed
553 if (fn) { 597 if (fn) {
554 trace('LOAD cb for ' + this.vid); 598 trace('LOAD cb for ' + this.vid);
555 - fn(this.token(), c); 599 + fn(this.token(), c, flags);
556 } 600 }
557 }, 601 },
558 602
...@@ -560,14 +604,13 @@ ...@@ -560,14 +604,13 @@
560 var fn = isF(this.cb.unload); 604 var fn = isF(this.cb.unload);
561 traceFn('View.unload', this.vid); 605 traceFn('View.unload', this.vid);
562 this.$div.classed('currentView', false); 606 this.$div.classed('currentView', false);
563 - // TODO: remove radio button set, if needed
564 if (fn) { 607 if (fn) {
565 trace('UNLOAD cb for ' + this.vid); 608 trace('UNLOAD cb for ' + this.vid);
566 fn(this.token()); 609 fn(this.token());
567 } 610 }
568 }, 611 },
569 612
570 - resize: function (ctx) { 613 + resize: function (ctx, flags) {
571 var c = ctx || '', 614 var c = ctx || '',
572 fn = isF(this.cb.resize), 615 fn = isF(this.cb.resize),
573 w = this.width(), 616 w = this.width(),
...@@ -576,7 +619,7 @@ ...@@ -576,7 +619,7 @@
576 ' [' + w + 'x' + h + ']'); 619 ' [' + w + 'x' + h + ']');
577 if (fn) { 620 if (fn) {
578 trace('RESIZE cb for ' + this.vid); 621 trace('RESIZE cb for ' + this.vid);
579 - fn(this.token(), c); 622 + fn(this.token(), c, flags);
580 } 623 }
581 }, 624 },
582 625
......
...@@ -21,12 +21,17 @@ ...@@ -21,12 +21,17 @@
21 */ 21 */
22 22
23 (function () { 23 (function () {
24 +
25 + // NOTE: DON'T Want to do this.. we want to be able to
26 + // use the parameter section, for example:
27 + // #viewId,context?flag1,flag2,flag3
28 +
24 // Check if the URL in the address bar contains a parameter section 29 // Check if the URL in the address bar contains a parameter section
25 // (delineated by '?'). If this is the case, rewrite using '#' instead. 30 // (delineated by '?'). If this is the case, rewrite using '#' instead.
26 31
27 - var m = /([^?]*)\?(.*)/.exec(window.location.href); 32 + //var m = /([^?]*)\?(.*)/.exec(window.location.href);
28 - if (m) { 33 + //if (m) {
29 - window.location.href = m[1] + '#' + m[2]; 34 + // window.location.href = m[1] + '#' + m[2];
30 - } 35 + //}
31 36
32 }()); 37 }());
......
1 +/*
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 + Sample view to illustrate hash formats.
19 +
20 + @author Simon Hunt
21 + */
22 +
23 +(function (onos) {
24 + 'use strict';
25 +
26 + var intro = "Try using the following hashes in the address bar:",
27 + hashPrefix = '#sampleHash',
28 + suffixes = [
29 + '',
30 + ',one',
31 + ',two',
32 + ',context,ignored',
33 + ',context,ignored?a,b,c',
34 + ',two?foo',
35 + ',three?foo,bar'
36 + ],
37 + $d;
38 +
39 + function note(txt) {
40 + $d.append('p')
41 + .text(txt)
42 + .style({
43 + 'font-size': '10pt',
44 + color: 'darkorange',
45 + padding: '0 20px',
46 + margin: 0
47 + });
48 + }
49 +
50 + function para(txt, color) {
51 + var c = color || 'black';
52 + $d.append('p')
53 + .text(txt)
54 + .style({
55 + padding: '2px 8px',
56 + color: c
57 + });
58 + }
59 +
60 + function load(view, ctx, flags) {
61 + var c = ctx || '(undefined)',
62 + f = flags ? d3.map(flags).keys() : [];
63 +
64 + $d = view.$div;
65 +
66 + para(intro);
67 +
68 + suffixes.forEach(function (s) {
69 + note(hashPrefix + s);
70 + });
71 +
72 + para('View ID: ' + view.vid, 'blue');
73 + para('Context: ' + c, 'blue');
74 + para('Flags: { ' + f.join(', ') + ' }', 'magenta');
75 + }
76 +
77 + // == register the view here, with links to lifecycle callbacks
78 +
79 + onos.ui.addView('sampleHash', {
80 + reset: true, // empty the div on reset
81 + load: load
82 + });
83 +
84 +}(ONOS));
...@@ -20,55 +20,59 @@ ...@@ -20,55 +20,59 @@
20 @author Simon Hunt 20 @author Simon Hunt
21 */ 21 */
22 22
23 -svg #topo-bg { 23 +#topo svg #topo-bg {
24 opacity: 0.5; 24 opacity: 0.5;
25 } 25 }
26 26
27 /* NODES */ 27 /* NODES */
28 28
29 -svg .node.device { 29 +#topo svg .node.device {
30 stroke: none; 30 stroke: none;
31 stroke-width: 1.5px; 31 stroke-width: 1.5px;
32 cursor: pointer; 32 cursor: pointer;
33 } 33 }
34 34
35 -svg .node.device rect { 35 +#topo svg .node.device rect {
36 stroke-width: 1.5px; 36 stroke-width: 1.5px;
37 } 37 }
38 38
39 -svg .node.device.fixed rect { 39 +#topo svg .node.device.fixed rect {
40 stroke-width: 1.5; 40 stroke-width: 1.5;
41 stroke: #ccc; 41 stroke: #ccc;
42 } 42 }
43 43
44 -svg .node.device.switch { 44 +#topo svg .node.device.switch {
45 fill: #17f; 45 fill: #17f;
46 } 46 }
47 47
48 -svg .node.device.roadm { 48 +#topo svg .node.device.roadm {
49 fill: #03c; 49 fill: #03c;
50 } 50 }
51 51
52 -svg .node text { 52 +#topo svg .node.host {
53 + fill: #846;
54 +}
55 +
56 +#topo svg .node text {
53 stroke: none; 57 stroke: none;
54 fill: white; 58 fill: white;
55 font: 10pt sans-serif; 59 font: 10pt sans-serif;
56 pointer-events: none; 60 pointer-events: none;
57 } 61 }
58 62
59 -svg .node.selected rect, 63 +#topo svg .node.selected rect,
60 -svg .node.selected circle { 64 +#topo svg .node.selected circle {
61 filter: url(#blue-glow); 65 filter: url(#blue-glow);
62 } 66 }
63 67
64 /* LINKS */ 68 /* LINKS */
65 69
66 -svg .link { 70 +#topo svg .link {
67 opacity: .7; 71 opacity: .7;
68 } 72 }
69 73
70 /* for debugging */ 74 /* for debugging */
71 -svg .node circle.debug { 75 +#topo svg .node circle.debug {
72 fill: white; 76 fill: white;
73 stroke: red; 77 stroke: red;
74 } 78 }
......
This diff is collapsed. Click to expand it.