GUI -- TopoView - Implemented much of the node selection logic. (WIP)
- introduced topoSelect.js. Change-Id: Ic843c7d8dc2249fe0cb8c33de60dce12c07aea44
Showing
13 changed files
with
593 additions
and
164 deletions
| ... | @@ -77,6 +77,7 @@ | ... | @@ -77,6 +77,7 @@ |
| 77 | width: panelWidth, | 77 | width: panelWidth, |
| 78 | height: panelHeight, | 78 | height: panelHeight, |
| 79 | isVisible: panelIsVisible, | 79 | isVisible: panelIsVisible, |
| 80 | + classed: classed, | ||
| 80 | el: panelEl | 81 | el: panelEl |
| 81 | }; | 82 | }; |
| 82 | 83 | ||
| ... | @@ -146,6 +147,10 @@ | ... | @@ -146,6 +147,10 @@ |
| 146 | return p.on; | 147 | return p.on; |
| 147 | } | 148 | } |
| 148 | 149 | ||
| 150 | + function classed(cls, bool) { | ||
| 151 | + return p.el.classed(cls, bool); | ||
| 152 | + } | ||
| 153 | + | ||
| 149 | function panelEl() { | 154 | function panelEl() { |
| 150 | return p.el; | 155 | return p.el; |
| 151 | } | 156 | } | ... | ... |
| ... | @@ -34,6 +34,7 @@ | ... | @@ -34,6 +34,7 @@ |
| 34 | $log = _$log_; | 34 | $log = _$log_; |
| 35 | fs = _fs_; | 35 | fs = _fs_; |
| 36 | 36 | ||
| 37 | + // TODO: change 'force' ref to be 'force.alpha' ref. | ||
| 37 | function createDragBehavior(force, selectCb, atDragEnd, | 38 | function createDragBehavior(force, selectCb, atDragEnd, |
| 38 | dragEnabled, clickEnabled) { | 39 | dragEnabled, clickEnabled) { |
| 39 | var draggedThreshold = d3.scale.linear() | 40 | var draggedThreshold = d3.scale.linear() | ... | ... |
| ... | @@ -82,9 +82,10 @@ | ... | @@ -82,9 +82,10 @@ |
| 82 | <script src="view/topo/topo.js"></script> | 82 | <script src="view/topo/topo.js"></script> |
| 83 | <script src="view/topo/topoEvent.js"></script> | 83 | <script src="view/topo/topoEvent.js"></script> |
| 84 | <script src="view/topo/topoForce.js"></script> | 84 | <script src="view/topo/topoForce.js"></script> |
| 85 | + <script src="view/topo/topoInst.js"></script> | ||
| 85 | <script src="view/topo/topoModel.js"></script> | 86 | <script src="view/topo/topoModel.js"></script> |
| 86 | <script src="view/topo/topoPanel.js"></script> | 87 | <script src="view/topo/topoPanel.js"></script> |
| 87 | - <script src="view/topo/topoInst.js"></script> | 88 | + <script src="view/topo/topoSelect.js"></script> |
| 88 | <script src="view/device/device.js"></script> | 89 | <script src="view/device/device.js"></script> |
| 89 | <!-- TODO: inject javascript refs server-side --> | 90 | <!-- TODO: inject javascript refs server-side --> |
| 90 | 91 | ... | ... |
| ... | @@ -72,71 +72,121 @@ | ... | @@ -72,71 +72,121 @@ |
| 72 | 72 | ||
| 73 | #topo-p-summary { | 73 | #topo-p-summary { |
| 74 | /* Base css from panel.css */ | 74 | /* Base css from panel.css */ |
| 75 | - | ||
| 76 | } | 75 | } |
| 77 | 76 | ||
| 78 | -#topo-p-summary svg { | 77 | +/* --- Topo Detail Panel --- */ |
| 78 | + | ||
| 79 | +#topo-p-detail { | ||
| 80 | + /* Base css from panel.css */ | ||
| 81 | + top: 320px; | ||
| 82 | +} | ||
| 83 | + | ||
| 84 | +/* --- general topo-panel styling --- */ | ||
| 85 | + | ||
| 86 | +.topo-p svg { | ||
| 79 | display: inline-block; | 87 | display: inline-block; |
| 80 | width: 42px; | 88 | width: 42px; |
| 81 | height: 42px; | 89 | height: 42px; |
| 82 | } | 90 | } |
| 83 | 91 | ||
| 84 | -#topo-p-summary h2 { | 92 | +.light .topo-p svg .glyph { |
| 93 | + fill: #222; | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +.dark .topo-p svg .glyph.overlay { | ||
| 97 | + fill: #222; | ||
| 98 | +} | ||
| 99 | + | ||
| 100 | +.dark .topo-p svg .glyph { | ||
| 101 | + fill: #ddd; | ||
| 102 | +} | ||
| 103 | +.light .topo-p svg .glyph.overlay { | ||
| 104 | + fill: #fff; | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | + | ||
| 108 | +.topo-p h2 { | ||
| 85 | position: absolute; | 109 | position: absolute; |
| 86 | margin: 0 4px; | 110 | margin: 0 4px; |
| 87 | top: 20px; | 111 | top: 20px; |
| 88 | left: 50px; | 112 | left: 50px; |
| 89 | } | 113 | } |
| 90 | -.light #topo-p-summary h2 { | 114 | +.light .topo-p h2 { |
| 91 | color: black; | 115 | color: black; |
| 92 | } | 116 | } |
| 93 | -.dark #topo-p-summary h2 { | 117 | +.dark .topo-p h2 { |
| 94 | color: #ddd; | 118 | color: #ddd; |
| 95 | } | 119 | } |
| 96 | 120 | ||
| 97 | -#topo-p-summary h3 { | 121 | +.topo-p h3 { |
| 98 | margin: 0 4px; | 122 | margin: 0 4px; |
| 99 | top: 20px; | 123 | top: 20px; |
| 100 | left: 50px; | 124 | left: 50px; |
| 101 | } | 125 | } |
| 102 | -.light #topo-p-summary h3 { | 126 | +.light .topo-p h3 { |
| 103 | color: black; | 127 | color: black; |
| 104 | } | 128 | } |
| 105 | -.dark #topo-p-summary h3 { | 129 | +.dark .topo-p h3 { |
| 106 | color: #ddd; | 130 | color: #ddd; |
| 107 | } | 131 | } |
| 108 | 132 | ||
| 109 | -#topo-p-summary p, table { | 133 | +.topo-p p, table { |
| 110 | margin: 4px 4px; | 134 | margin: 4px 4px; |
| 111 | } | 135 | } |
| 112 | 136 | ||
| 113 | -#topo-p-summary td.label { | 137 | +.topo-p td.label { |
| 114 | font-style: italic; | 138 | font-style: italic; |
| 115 | padding-right: 12px; | 139 | padding-right: 12px; |
| 116 | /* works for both light and dark themes ... */ | 140 | /* works for both light and dark themes ... */ |
| 117 | color: #777; | 141 | color: #777; |
| 118 | } | 142 | } |
| 119 | 143 | ||
| 120 | -#topo-p-summary td.value { | 144 | +.topo-p td.value { |
| 121 | } | 145 | } |
| 122 | 146 | ||
| 123 | -#topo-p-summary hr { | 147 | +.topo-p hr { |
| 124 | height: 1px; | 148 | height: 1px; |
| 125 | border: 0; | 149 | border: 0; |
| 126 | } | 150 | } |
| 127 | -.light #topo-p-summary hr { | 151 | +.light .topo-p hr { |
| 128 | background-color: #ccc; | 152 | background-color: #ccc; |
| 129 | color: #ccc; | 153 | color: #ccc; |
| 130 | } | 154 | } |
| 131 | -.dark #topo-p-summary hr { | 155 | +.dark .topo-p hr { |
| 132 | background-color: #888; | 156 | background-color: #888; |
| 133 | color: #888; | 157 | color: #888; |
| 134 | } | 158 | } |
| 135 | 159 | ||
| 136 | 160 | ||
| 137 | -/* --- Topo Detail Panel --- */ | 161 | +.topo-p .actionBtn { |
| 162 | + margin: 6px 12px; | ||
| 163 | + padding: 2px 6px; | ||
| 164 | + font-size: 9pt; | ||
| 165 | + cursor: pointer; | ||
| 166 | + width: 200px; | ||
| 167 | + text-align: center; | ||
| 168 | + border-radius: 4px; | ||
| 169 | +} | ||
| 170 | +.light .topo-p .actionBtn { | ||
| 171 | + border: 2px solid #ddd; | ||
| 172 | + color: #eee; | ||
| 173 | + background: #888; | ||
| 174 | +} | ||
| 175 | +.dark .topo-p .actionBtn { | ||
| 176 | + border: 2px solid #222; | ||
| 177 | + color: #888; | ||
| 178 | + background: #444; | ||
| 179 | +} | ||
| 180 | + | ||
| 181 | +.light .topo-p .actionBtn:hover { | ||
| 182 | + color: #eee; | ||
| 183 | + background: #444; | ||
| 184 | +} | ||
| 185 | +.dark .topo-p .actionBtn:hover { | ||
| 186 | + color: #eee; | ||
| 187 | + background: #666; | ||
| 188 | +} | ||
| 138 | 189 | ||
| 139 | -/* TODO: add CSS rules */ | ||
| 140 | 190 | ||
| 141 | 191 | ||
| 142 | /* --- Topo Instance Panel --- */ | 192 | /* --- Topo Instance Panel --- */ | ... | ... |
| ... | @@ -66,7 +66,7 @@ | ... | @@ -66,7 +66,7 @@ |
| 66 | 66 | ||
| 67 | //E: [equalizeMasters, 'Equalize mastership roles'], | 67 | //E: [equalizeMasters, 'Equalize mastership roles'], |
| 68 | 68 | ||
| 69 | - //esc: handleEscape, | 69 | + esc: handleEscape, |
| 70 | 70 | ||
| 71 | _helpFormat: [ | 71 | _helpFormat: [ |
| 72 | ['O', 'I', 'D', '-', 'H', 'M', 'B', 'P' ], | 72 | ['O', 'I', 'D', '-', 'H', 'M', 'B', 'P' ], |
| ... | @@ -85,12 +85,29 @@ | ... | @@ -85,12 +85,29 @@ |
| 85 | ]; | 85 | ]; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | + // --- Keystroke functions ------------------------------------------- | ||
| 88 | 89 | ||
| 89 | function toggleInstances() { | 90 | function toggleInstances() { |
| 90 | tis.toggle(); | 91 | tis.toggle(); |
| 91 | tfs.updateDeviceColors(); | 92 | tfs.updateDeviceColors(); |
| 92 | } | 93 | } |
| 93 | 94 | ||
| 95 | + function resetZoom() { | ||
| 96 | + zoomer.reset(); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + function handleEscape() { | ||
| 100 | + $log.debug("TODO: handle-ESCAPE..."); | ||
| 101 | + // if showingAffinity: cancelAffinity | ||
| 102 | + | ||
| 103 | + // else if showingDetails: deselectAll | ||
| 104 | + | ||
| 105 | + // else if oiBox visible: hide oiBox | ||
| 106 | + | ||
| 107 | + // else if summary panel visible: cancel Summary | ||
| 108 | + | ||
| 109 | + // else: hoverMode = hoverModeNone | ||
| 110 | + } | ||
| 94 | 111 | ||
| 95 | // --- Glyphs, Icons, and the like ----------------------------------- | 112 | // --- Glyphs, Icons, and the like ----------------------------------- |
| 96 | 113 | ||
| ... | @@ -124,10 +141,6 @@ | ... | @@ -124,10 +141,6 @@ |
| 124 | }); | 141 | }); |
| 125 | } | 142 | } |
| 126 | 143 | ||
| 127 | - function resetZoom() { | ||
| 128 | - zoomer.reset(); | ||
| 129 | - } | ||
| 130 | - | ||
| 131 | 144 | ||
| 132 | // callback invoked when the SVG view has been resized.. | 145 | // callback invoked when the SVG view has been resized.. |
| 133 | function svgResized(s) { | 146 | function svgResized(s) { | ... | ... |
| ... | @@ -27,7 +27,7 @@ | ... | @@ -27,7 +27,7 @@ |
| 27 | 'use strict'; | 27 | 'use strict'; |
| 28 | 28 | ||
| 29 | // injected refs | 29 | // injected refs |
| 30 | - var $log, wss, wes, tps, tis, tfs; | 30 | + var $log, wss, wes, tps, tis, tfs, tss; |
| 31 | 31 | ||
| 32 | // internal state | 32 | // internal state |
| 33 | var wsock, evApis; | 33 | var wsock, evApis; |
| ... | @@ -37,9 +37,13 @@ | ... | @@ -37,9 +37,13 @@ |
| 37 | function bindApis() { | 37 | function bindApis() { |
| 38 | evApis = { | 38 | evApis = { |
| 39 | showSummary: tps, | 39 | showSummary: tps, |
| 40 | + | ||
| 41 | + showDetails: tss, | ||
| 42 | + | ||
| 40 | addInstance: tis, | 43 | addInstance: tis, |
| 41 | updateInstance: tis, | 44 | updateInstance: tis, |
| 42 | removeInstance: tis, | 45 | removeInstance: tis, |
| 46 | + | ||
| 43 | addDevice: tfs, | 47 | addDevice: tfs, |
| 44 | updateDevice: tfs, | 48 | updateDevice: tfs, |
| 45 | removeDevice: tfs, | 49 | removeDevice: tfs, |
| ... | @@ -100,14 +104,16 @@ | ... | @@ -100,14 +104,16 @@ |
| 100 | .factory('TopoEventService', | 104 | .factory('TopoEventService', |
| 101 | ['$log', '$location', 'WebSocketService', 'WsEventService', | 105 | ['$log', '$location', 'WebSocketService', 'WsEventService', |
| 102 | 'TopoPanelService', 'TopoInstService', 'TopoForceService', | 106 | 'TopoPanelService', 'TopoInstService', 'TopoForceService', |
| 107 | + 'TopoSelectService', | ||
| 103 | 108 | ||
| 104 | - function (_$log_, $loc, _wss_, _wes_, _tps_, _tis_, _tfs_) { | 109 | + function (_$log_, $loc, _wss_, _wes_, _tps_, _tis_, _tfs_, _tss_) { |
| 105 | $log = _$log_; | 110 | $log = _$log_; |
| 106 | wss = _wss_; | 111 | wss = _wss_; |
| 107 | wes = _wes_; | 112 | wes = _wes_; |
| 108 | tps = _tps_; | 113 | tps = _tps_; |
| 109 | tis = _tis_; | 114 | tis = _tis_; |
| 110 | tfs = _tfs_; | 115 | tfs = _tfs_; |
| 116 | + tss = _tss_; | ||
| 111 | 117 | ||
| 112 | bindApis(); | 118 | bindApis(); |
| 113 | 119 | ... | ... |
| ... | @@ -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, fs, sus, is, ts, flash, tis, tms, icfg, uplink; | 26 | + var $log, fs, sus, is, ts, flash, tis, tms, tss, icfg, uplink; |
| 27 | 27 | ||
| 28 | // configuration | 28 | // configuration |
| 29 | var labelConfig = { | 29 | var labelConfig = { |
| ... | @@ -77,10 +77,7 @@ | ... | @@ -77,10 +77,7 @@ |
| 77 | showOffline = true, // whether offline devices are displayed | 77 | showOffline = true, // whether offline devices are displayed |
| 78 | oblique = false, // whether we are in the oblique view | 78 | oblique = false, // whether we are in the oblique view |
| 79 | nodeLock = false, // whether nodes can be dragged or not (locked) | 79 | nodeLock = false, // whether nodes can be dragged or not (locked) |
| 80 | - dim, // the dimensions of the force layout [w,h] | 80 | + dim; // the dimensions of the force layout [w,h] |
| 81 | - hovered, // the node over which the mouse is hovering | ||
| 82 | - selections = {}, // what is currently selected | ||
| 83 | - selectOrder = []; // the order in which we made selections | ||
| 84 | 81 | ||
| 85 | // SVG elements; | 82 | // SVG elements; |
| 86 | var linkG, linkLabelG, nodeG; | 83 | var linkG, linkLabelG, nodeG; |
| ... | @@ -311,8 +308,6 @@ | ... | @@ -311,8 +308,6 @@ |
| 311 | .attr('stroke', linkConfig[th].baseColor); | 308 | .attr('stroke', linkConfig[th].baseColor); |
| 312 | } | 309 | } |
| 313 | 310 | ||
| 314 | - | ||
| 315 | - | ||
| 316 | function removeLinkElement(d) { | 311 | function removeLinkElement(d) { |
| 317 | var idx = fs.find(d.key, network.links, 'key'), | 312 | var idx = fs.find(d.key, network.links, 'key'), |
| 318 | removed; | 313 | removed; |
| ... | @@ -418,34 +413,10 @@ | ... | @@ -418,34 +413,10 @@ |
| 418 | }); | 413 | }); |
| 419 | } | 414 | } |
| 420 | 415 | ||
| 421 | - function requestTrafficForMode() { | ||
| 422 | - $log.debug('TODO: requestTrafficForMode()...'); | ||
| 423 | - } | ||
| 424 | - | ||
| 425 | 416 | ||
| 426 | // ========================== | 417 | // ========================== |
| 427 | // === Devices and hosts - D3 rendering | 418 | // === Devices and hosts - D3 rendering |
| 428 | 419 | ||
| 429 | - function nodeMouseOver(m) { | ||
| 430 | - if (!m.dragStarted) { | ||
| 431 | - $log.debug("MouseOver()...", m); | ||
| 432 | - if (hovered != m) { | ||
| 433 | - hovered = m; | ||
| 434 | - requestTrafficForMode(); | ||
| 435 | - } | ||
| 436 | - } | ||
| 437 | - } | ||
| 438 | - | ||
| 439 | - function nodeMouseOut(m) { | ||
| 440 | - if (!m.dragStarted) { | ||
| 441 | - if (hovered) { | ||
| 442 | - hovered = null; | ||
| 443 | - requestTrafficForMode(); | ||
| 444 | - } | ||
| 445 | - $log.debug("MouseOut()...", m); | ||
| 446 | - } | ||
| 447 | - } | ||
| 448 | - | ||
| 449 | 420 | ||
| 450 | // Returns the newly computed bounding box of the rectangle | 421 | // Returns the newly computed bounding box of the rectangle |
| 451 | function adjustRectToFitText(n) { | 422 | function adjustRectToFitText(n) { |
| ... | @@ -568,10 +539,11 @@ | ... | @@ -568,10 +539,11 @@ |
| 568 | } | 539 | } |
| 569 | 540 | ||
| 570 | function unpin() { | 541 | function unpin() { |
| 571 | - if (hovered) { | 542 | + var hov = tss.hovered(); |
| 572 | - sendUpdateMeta(hovered, true); | 543 | + if (hov) { |
| 573 | - hovered.fixed = false; | 544 | + sendUpdateMeta(hov, true); |
| 574 | - hovered.el.classed('fixed', false); | 545 | + hov.fixed = false; |
| 546 | + hov.el.classed('fixed', false); | ||
| 575 | fResume(); | 547 | fResume(); |
| 576 | } | 548 | } |
| 577 | } | 549 | } |
| ... | @@ -668,8 +640,8 @@ | ... | @@ -668,8 +640,8 @@ |
| 668 | opacity: 0 | 640 | opacity: 0 |
| 669 | }) | 641 | }) |
| 670 | .call(drag) | 642 | .call(drag) |
| 671 | - .on('mouseover', nodeMouseOver) | 643 | + .on('mouseover', tss.nodeMouseOver) |
| 672 | - .on('mouseout', nodeMouseOut) | 644 | + .on('mouseout', tss.nodeMouseOut) |
| 673 | .transition() | 645 | .transition() |
| 674 | .attr('opacity', 1); | 646 | .attr('opacity', 1); |
| 675 | 647 | ||
| ... | @@ -998,72 +970,6 @@ | ... | @@ -998,72 +970,6 @@ |
| 998 | } | 970 | } |
| 999 | 971 | ||
| 1000 | 972 | ||
| 1001 | - function updateDetailPanel() { | ||
| 1002 | - // TODO update detail panel | ||
| 1003 | - $log.debug("TODO: updateDetailPanel() ..."); | ||
| 1004 | - } | ||
| 1005 | - | ||
| 1006 | - | ||
| 1007 | - // ========================== | ||
| 1008 | - // === SELECTION / DESELECTION | ||
| 1009 | - | ||
| 1010 | - function selectObject(obj) { | ||
| 1011 | - var el = this, | ||
| 1012 | - ev = d3.event.sourceEvent, | ||
| 1013 | - n; | ||
| 1014 | - | ||
| 1015 | - if (zoomingOrPanning(ev)) { | ||
| 1016 | - return; | ||
| 1017 | - } | ||
| 1018 | - | ||
| 1019 | - if (el) { | ||
| 1020 | - n = d3.select(el); | ||
| 1021 | - } else { | ||
| 1022 | - node.each(function (d) { | ||
| 1023 | - if (d == obj) { | ||
| 1024 | - n = d3.select(el = this); | ||
| 1025 | - } | ||
| 1026 | - }); | ||
| 1027 | - } | ||
| 1028 | - if (!n) return; | ||
| 1029 | - | ||
| 1030 | - if (ev.shiftKey && n.classed('selected')) { | ||
| 1031 | - deselectObject(obj.id); | ||
| 1032 | - updateDetailPanel(); | ||
| 1033 | - return; | ||
| 1034 | - } | ||
| 1035 | - | ||
| 1036 | - if (!ev.shiftKey) { | ||
| 1037 | - deselectAll(); | ||
| 1038 | - } | ||
| 1039 | - | ||
| 1040 | - selections[obj.id] = { obj: obj, el: el }; | ||
| 1041 | - selectOrder.push(obj.id); | ||
| 1042 | - | ||
| 1043 | - n.classed('selected', true); | ||
| 1044 | - updateDeviceColors(obj); | ||
| 1045 | - updateDetailPanel(); | ||
| 1046 | - } | ||
| 1047 | - | ||
| 1048 | - function deselectObject(id) { | ||
| 1049 | - var obj = selections[id]; | ||
| 1050 | - if (obj) { | ||
| 1051 | - d3.select(obj.el).classed('selected', false); | ||
| 1052 | - delete selections[id]; | ||
| 1053 | - fs.removeFromArray(id, selectOrder); | ||
| 1054 | - updateDeviceColors(obj.obj); | ||
| 1055 | - } | ||
| 1056 | - } | ||
| 1057 | - | ||
| 1058 | - function deselectAll() { | ||
| 1059 | - // deselect all nodes in the network... | ||
| 1060 | - node.classed('selected', false); | ||
| 1061 | - selections = {}; | ||
| 1062 | - selectOrder = []; | ||
| 1063 | - updateDeviceColors(); | ||
| 1064 | - updateDetailPanel(); | ||
| 1065 | - } | ||
| 1066 | - | ||
| 1067 | // ========================== | 973 | // ========================== |
| 1068 | // === MOUSE GESTURE HANDLERS | 974 | // === MOUSE GESTURE HANDLERS |
| 1069 | 975 | ||
| ... | @@ -1103,12 +1009,22 @@ | ... | @@ -1103,12 +1009,22 @@ |
| 1103 | }; | 1009 | }; |
| 1104 | } | 1010 | } |
| 1105 | 1011 | ||
| 1012 | + function mkSelectApi(uplink) { | ||
| 1013 | + return { | ||
| 1014 | + node: function () { return node; }, | ||
| 1015 | + zoomingOrPanning: zoomingOrPanning, | ||
| 1016 | + updateDeviceColors: updateDeviceColors, | ||
| 1017 | + sendEvent: uplink.sendEvent | ||
| 1018 | + }; | ||
| 1019 | + } | ||
| 1020 | + | ||
| 1106 | angular.module('ovTopo') | 1021 | angular.module('ovTopo') |
| 1107 | .factory('TopoForceService', | 1022 | .factory('TopoForceService', |
| 1108 | ['$log', 'FnService', 'SvgUtilService', 'IconService', 'ThemeService', | 1023 | ['$log', 'FnService', 'SvgUtilService', 'IconService', 'ThemeService', |
| 1109 | 'FlashService', 'TopoInstService', 'TopoModelService', | 1024 | 'FlashService', 'TopoInstService', 'TopoModelService', |
| 1025 | + 'TopoSelectService', | ||
| 1110 | 1026 | ||
| 1111 | - function (_$log_, _fs_, _sus_, _is_, _ts_, _flash_, _tis_, _tms_) { | 1027 | + function (_$log_, _fs_, _sus_, _is_, _ts_, _flash_, _tis_, _tms_, _tss_) { |
| 1112 | $log = _$log_; | 1028 | $log = _$log_; |
| 1113 | fs = _fs_; | 1029 | fs = _fs_; |
| 1114 | sus = _sus_; | 1030 | sus = _sus_; |
| ... | @@ -1117,6 +1033,7 @@ | ... | @@ -1117,6 +1033,7 @@ |
| 1117 | flash = _flash_; | 1033 | flash = _flash_; |
| 1118 | tis = _tis_; | 1034 | tis = _tis_; |
| 1119 | tms = _tms_; | 1035 | tms = _tms_; |
| 1036 | + tss = _tss_; | ||
| 1120 | 1037 | ||
| 1121 | icfg = is.iconConfig(); | 1038 | icfg = is.iconConfig(); |
| 1122 | 1039 | ||
| ... | @@ -1131,6 +1048,7 @@ | ... | @@ -1131,6 +1048,7 @@ |
| 1131 | $log.debug('initForce().. dim = ' + dim); | 1048 | $log.debug('initForce().. dim = ' + dim); |
| 1132 | 1049 | ||
| 1133 | tms.initModel(mkModelApi(uplink), dim); | 1050 | tms.initModel(mkModelApi(uplink), dim); |
| 1051 | + tss.initSelect(mkSelectApi(uplink)); | ||
| 1134 | 1052 | ||
| 1135 | settings = angular.extend({}, defaultSettings, opts); | 1053 | settings = angular.extend({}, defaultSettings, opts); |
| 1136 | 1054 | ||
| ... | @@ -1154,7 +1072,7 @@ | ... | @@ -1154,7 +1072,7 @@ |
| 1154 | .on('tick', tick); | 1072 | .on('tick', tick); |
| 1155 | 1073 | ||
| 1156 | drag = sus.createDragBehavior(force, | 1074 | drag = sus.createDragBehavior(force, |
| 1157 | - selectObject, atDragEnd, dragEnabled, clickEnabled); | 1075 | + tss.selectObject, atDragEnd, dragEnabled, clickEnabled); |
| 1158 | } | 1076 | } |
| 1159 | 1077 | ||
| 1160 | function newDim(_dim_) { | 1078 | function newDim(_dim_) { | ... | ... |
| ... | @@ -24,18 +24,21 @@ | ... | @@ -24,18 +24,21 @@ |
| 24 | 'use strict'; | 24 | 'use strict'; |
| 25 | 25 | ||
| 26 | // injected refs | 26 | // injected refs |
| 27 | - var $log, fs, rnd, api; | 27 | + var $log, fs, rnd; |
| 28 | + | ||
| 29 | + // api to topoForce | ||
| 30 | + var api; | ||
| 31 | + /* | ||
| 32 | + projection() | ||
| 33 | + network {...} | ||
| 34 | + restyleLinkElement( ldata ) | ||
| 35 | + removeLinkElement( ldata ) | ||
| 36 | + */ | ||
| 28 | 37 | ||
| 29 | // shorthand | 38 | // shorthand |
| 30 | var lu, rlk, nodes, links; | 39 | var lu, rlk, nodes, links; |
| 31 | 40 | ||
| 32 | - // api: | 41 | + var dim; // dimensions of layout [w,h] |
| 33 | - // projection: func() | ||
| 34 | - // network {...} | ||
| 35 | - // restyleLinkElement: func(ldata) | ||
| 36 | - // removeLinkElement: func(ldata) | ||
| 37 | - | ||
| 38 | - var dim; // dimensions of layout, as [w,h] | ||
| 39 | 42 | ||
| 40 | // configuration 'constants' | 43 | // configuration 'constants' |
| 41 | var defaultLinkType = 'direct', | 44 | var defaultLinkType = 'direct', | ... | ... |
| ... | @@ -26,7 +26,8 @@ | ... | @@ -26,7 +26,8 @@ |
| 26 | var $log, ps, gs; | 26 | var $log, ps, gs; |
| 27 | 27 | ||
| 28 | // constants | 28 | // constants |
| 29 | - var idSum = 'topo-p-summary', | 29 | + var pCls = 'topo-p', |
| 30 | + idSum = 'topo-p-summary', | ||
| 30 | idDet = 'topo-p-detail', | 31 | idDet = 'topo-p-detail', |
| 31 | panelOpts = { | 32 | panelOpts = { |
| 32 | width: 260 | 33 | width: 260 |
| ... | @@ -36,60 +37,134 @@ | ... | @@ -36,60 +37,134 @@ |
| 36 | var summaryPanel, | 37 | var summaryPanel, |
| 37 | detailPanel; | 38 | detailPanel; |
| 38 | 39 | ||
| 39 | - // ========================== | ||
| 40 | - // *** SHOW SUMMARY *** | ||
| 41 | 40 | ||
| 42 | - function showSummary(data) { | 41 | + // === ----------------------------------------------------- |
| 43 | - populateSummary(data); | 42 | + // Utility functions |
| 44 | - showSummaryPanel(); | 43 | + |
| 44 | + function addSep(tbody) { | ||
| 45 | + tbody.append('tr').append('td').attr('colspan', 2).append('hr'); | ||
| 45 | } | 46 | } |
| 46 | 47 | ||
| 48 | + function addProp(tbody, label, value) { | ||
| 49 | + var tr = tbody.append('tr'); | ||
| 50 | + | ||
| 51 | + function addCell(cls, txt) { | ||
| 52 | + tr.append('td').attr('class', cls).text(txt); | ||
| 53 | + } | ||
| 54 | + addCell('label', label + ' :'); | ||
| 55 | + addCell('value', value); | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + function listProps(tbody, data) { | ||
| 59 | + data.propOrder.forEach(function(p) { | ||
| 60 | + if (p === '-') { | ||
| 61 | + addSep(tbody); | ||
| 62 | + } else { | ||
| 63 | + addProp(tbody, p, data.props[p]); | ||
| 64 | + } | ||
| 65 | + }); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + function dpa(x) { | ||
| 69 | + return detailPanel.append(x); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + function spa(x) { | ||
| 73 | + return summaryPanel.append(x); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + // === ----------------------------------------------------- | ||
| 77 | + // Functions for populating the summary panel | ||
| 78 | + | ||
| 47 | function populateSummary(data) { | 79 | function populateSummary(data) { |
| 48 | summaryPanel.empty(); | 80 | summaryPanel.empty(); |
| 49 | 81 | ||
| 50 | - var svg = summaryPanel.append('svg'), | 82 | + var svg = spa('svg'), |
| 51 | - title = summaryPanel.append('h2'), | 83 | + title = spa('h2'), |
| 52 | - table = summaryPanel.append('table'), | 84 | + table = spa('table'), |
| 53 | tbody = table.append('tbody'); | 85 | tbody = table.append('tbody'); |
| 54 | 86 | ||
| 55 | gs.addGlyph(svg, 'node', 40); | 87 | gs.addGlyph(svg, 'node', 40); |
| 56 | gs.addGlyph(svg, 'bird', 24, true, [8,12]); | 88 | gs.addGlyph(svg, 'bird', 24, true, [8,12]); |
| 57 | 89 | ||
| 58 | title.text(data.id); | 90 | title.text(data.id); |
| 91 | + listProps(tbody, data); | ||
| 92 | + } | ||
| 59 | 93 | ||
| 60 | - data.propOrder.forEach(function(p) { | 94 | + // === ----------------------------------------------------- |
| 61 | - if (p === '-') { | 95 | + // Functions for populating the detail panel |
| 62 | - addSep(tbody); | 96 | + |
| 63 | - } else { | 97 | + function displaySingle(data) { |
| 64 | - addProp(tbody, p, data.props[p]); | 98 | + detailPanel.empty(); |
| 65 | - } | 99 | + |
| 100 | + var svg = dpa('svg'), | ||
| 101 | + title = dpa('h2'), | ||
| 102 | + table = dpa('table'), | ||
| 103 | + tbody = table.append('tbody'); | ||
| 104 | + | ||
| 105 | + gs.addGlyph(svg, (data.type || 'unknown'), 40); | ||
| 106 | + title.text(data.id); | ||
| 107 | + listProps(tbody, data); | ||
| 108 | + dpa('hr'); | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + function displayMulti(ids) { | ||
| 112 | + detailPanel.empty(); | ||
| 113 | + | ||
| 114 | + var title = dpa('h3'), | ||
| 115 | + table = dpa('table'), | ||
| 116 | + tbody = table.append('tbody'); | ||
| 117 | + | ||
| 118 | + title.text('Selected Nodes'); | ||
| 119 | + ids.forEach(function (d, i) { | ||
| 120 | + addProp(tbody, i+1, d); | ||
| 66 | }); | 121 | }); |
| 122 | + dpa('hr'); | ||
| 67 | } | 123 | } |
| 68 | 124 | ||
| 69 | - function addSep(tbody) { | 125 | + function addAction(text, cb) { |
| 70 | - tbody.append('tr').append('td').attr('colspan', 2).append('hr'); | 126 | + dpa('div') |
| 127 | + .classed('actionBtn', true) | ||
| 128 | + .text(text) | ||
| 129 | + .on('click', cb); | ||
| 71 | } | 130 | } |
| 72 | 131 | ||
| 73 | - function addProp(tbody, label, value) { | 132 | + // === ----------------------------------------------------- |
| 74 | - var tr = tbody.append('tr'); | 133 | + // Event Handlers |
| 75 | 134 | ||
| 76 | - function addCell(cls, txt) { | 135 | + function showSummary(data) { |
| 77 | - tr.append('td').attr('class', cls).text(txt); | 136 | + populateSummary(data); |
| 78 | - } | 137 | + showSummaryPanel(); |
| 79 | - addCell('label', label + ' :'); | ||
| 80 | - addCell('value', value); | ||
| 81 | } | 138 | } |
| 82 | 139 | ||
| 140 | + | ||
| 141 | + // === ----------------------------------------------------- | ||
| 142 | + // === LOGIC For showing/hiding summary and detail panels... | ||
| 143 | + | ||
| 83 | function showSummaryPanel() { | 144 | function showSummaryPanel() { |
| 84 | summaryPanel.show(); | 145 | summaryPanel.show(); |
| 85 | // TODO: augment, once we have the details pane also | 146 | // TODO: augment, once we have the details pane also |
| 86 | } | 147 | } |
| 87 | 148 | ||
| 149 | + function showDetailPanel() { | ||
| 150 | + // TODO: augment with summary-accomodation-logic | ||
| 151 | + detailPanel.show(); | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + function hideDetailPanel() { | ||
| 155 | + detailPanel.hide(); | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + | ||
| 159 | + | ||
| 88 | // ========================== | 160 | // ========================== |
| 89 | 161 | ||
| 90 | function initPanels() { | 162 | function initPanels() { |
| 91 | summaryPanel = ps.createPanel(idSum, panelOpts); | 163 | summaryPanel = ps.createPanel(idSum, panelOpts); |
| 92 | detailPanel = ps.createPanel(idDet, panelOpts); | 164 | detailPanel = ps.createPanel(idDet, panelOpts); |
| 165 | + | ||
| 166 | + summaryPanel.classed(pCls, true); | ||
| 167 | + detailPanel.classed(pCls, true); | ||
| 93 | } | 168 | } |
| 94 | 169 | ||
| 95 | function destroyPanels() { | 170 | function destroyPanels() { |
| ... | @@ -112,7 +187,18 @@ | ... | @@ -112,7 +187,18 @@ |
| 112 | return { | 187 | return { |
| 113 | initPanels: initPanels, | 188 | initPanels: initPanels, |
| 114 | destroyPanels: destroyPanels, | 189 | destroyPanels: destroyPanels, |
| 115 | - showSummary: showSummary | 190 | + |
| 191 | + showSummary: showSummary, | ||
| 192 | + | ||
| 193 | + displaySingle: displaySingle, | ||
| 194 | + displayMulti: displayMulti, | ||
| 195 | + addAction: addAction, | ||
| 196 | + | ||
| 197 | + showDetailPanel: showDetailPanel, | ||
| 198 | + hideDetailPanel: hideDetailPanel, | ||
| 199 | + | ||
| 200 | + detailVisible: function () { return detailPanel.isVisible(); }, | ||
| 201 | + summaryVisible: function () { return summaryPanel.isVisible(); } | ||
| 116 | }; | 202 | }; |
| 117 | }]); | 203 | }]); |
| 118 | }()); | 204 | }()); | ... | ... |
| 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 Selection Module. | ||
| 19 | + Defines behavior when selecting nodes. | ||
| 20 | + */ | ||
| 21 | + | ||
| 22 | +(function () { | ||
| 23 | + 'use strict'; | ||
| 24 | + | ||
| 25 | + // injected refs | ||
| 26 | + var $log, fs, tps; | ||
| 27 | + | ||
| 28 | + // api to topoForce | ||
| 29 | + var api; | ||
| 30 | + /* | ||
| 31 | + node() // get ref to D3 selection of nodes | ||
| 32 | + zoomingOrPanning( ev ) | ||
| 33 | + updateDeviceColors( [dev] ) | ||
| 34 | + sendEvent( type, {payload} ) | ||
| 35 | + */ | ||
| 36 | + | ||
| 37 | + // internal state | ||
| 38 | + var hovered, // the node over which the mouse is hovering | ||
| 39 | + selections = {}, // currently selected nodes (by id) | ||
| 40 | + selectOrder = [], // the order in which we made selections | ||
| 41 | + haveDetails = false, // do we have details of one or more nodes? | ||
| 42 | + useDetails = true; // should we show details if we have 'em? | ||
| 43 | + | ||
| 44 | + // ========================== | ||
| 45 | + | ||
| 46 | + function nSel() { | ||
| 47 | + return selectOrder.length; | ||
| 48 | + } | ||
| 49 | + function getSel(idx) { | ||
| 50 | + return selections[selectOrder[idx]]; | ||
| 51 | + } | ||
| 52 | + function allSelectionsClass(cls) { | ||
| 53 | + for (var i=0, n=nSel(); i<n; i++) { | ||
| 54 | + if (getSel(i).obj.class !== cls) { | ||
| 55 | + return false; | ||
| 56 | + } | ||
| 57 | + } | ||
| 58 | + return true; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + // ========================== | ||
| 62 | + | ||
| 63 | + function nodeMouseOver(m) { | ||
| 64 | + if (!m.dragStarted) { | ||
| 65 | + $log.debug("MouseOver()...", m); | ||
| 66 | + if (hovered != m) { | ||
| 67 | + hovered = m; | ||
| 68 | + requestTrafficForMode(); | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + function nodeMouseOut(m) { | ||
| 74 | + if (!m.dragStarted) { | ||
| 75 | + if (hovered) { | ||
| 76 | + hovered = null; | ||
| 77 | + requestTrafficForMode(); | ||
| 78 | + } | ||
| 79 | + $log.debug("MouseOut()...", m); | ||
| 80 | + } | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + // ========================== | ||
| 84 | + | ||
| 85 | + function selectObject(obj) { | ||
| 86 | + var el = this, | ||
| 87 | + ev = d3.event.sourceEvent, | ||
| 88 | + n; | ||
| 89 | + | ||
| 90 | + if (api.zoomingOrPanning(ev)) { | ||
| 91 | + return; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + if (el) { | ||
| 95 | + n = d3.select(el); | ||
| 96 | + } else { | ||
| 97 | + api.node().each(function (d) { | ||
| 98 | + if (d == obj) { | ||
| 99 | + n = d3.select(el = this); | ||
| 100 | + } | ||
| 101 | + }); | ||
| 102 | + } | ||
| 103 | + if (!n) return; | ||
| 104 | + | ||
| 105 | + if (ev.shiftKey && n.classed('selected')) { | ||
| 106 | + deselectObject(obj.id); | ||
| 107 | + updateDetail(); | ||
| 108 | + return; | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + if (!ev.shiftKey) { | ||
| 112 | + deselectAll(); | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + selections[obj.id] = { obj: obj, el: el }; | ||
| 116 | + selectOrder.push(obj.id); | ||
| 117 | + | ||
| 118 | + n.classed('selected', true); | ||
| 119 | + api.updateDeviceColors(obj); | ||
| 120 | + updateDetail(); | ||
| 121 | + | ||
| 122 | + debugSel(); | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + function deselectObject(id) { | ||
| 126 | + var obj = selections[id]; | ||
| 127 | + if (obj) { | ||
| 128 | + d3.select(obj.el).classed('selected', false); | ||
| 129 | + delete selections[id]; | ||
| 130 | + fs.removeFromArray(id, selectOrder); | ||
| 131 | + api.updateDeviceColors(obj.obj); | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + debugSel(); | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + function deselectAll() { | ||
| 138 | + // deselect all nodes in the network... | ||
| 139 | + api.node().classed('selected', false); | ||
| 140 | + selections = {}; | ||
| 141 | + selectOrder = []; | ||
| 142 | + api.updateDeviceColors(); | ||
| 143 | + updateDetail(); | ||
| 144 | + | ||
| 145 | + debugSel(); | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + function debugSel() { | ||
| 149 | + $log.debug(' ..... Selected now >> ', selectOrder); | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + // === ----------------------------------------------------- | ||
| 153 | + | ||
| 154 | + function requestDetails() { | ||
| 155 | + var data = getSel(0).obj; | ||
| 156 | + api.sendEvent('requestDetails', { | ||
| 157 | + id: data.id, | ||
| 158 | + class: data.class | ||
| 159 | + }); | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | + // === ----------------------------------------------------- | ||
| 163 | + | ||
| 164 | + function updateDetail() { | ||
| 165 | + var nSel = selectOrder.length; | ||
| 166 | + if (!nSel) { | ||
| 167 | + emptySelect(); | ||
| 168 | + } else if (nSel === 1) { | ||
| 169 | + singleSelect(); | ||
| 170 | + } else { | ||
| 171 | + multiSelect(); | ||
| 172 | + } | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + function emptySelect() { | ||
| 176 | + haveDetails = false; | ||
| 177 | + tps.hideDetailPanel(); | ||
| 178 | + cancelTraffic(); | ||
| 179 | + } | ||
| 180 | + | ||
| 181 | + function singleSelect() { | ||
| 182 | + // NOTE: detail is shown from 'showDetails' event callback | ||
| 183 | + requestDetails(); | ||
| 184 | + cancelTraffic(); | ||
| 185 | + requestTrafficForMode(); | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + function multiSelect() { | ||
| 189 | + haveDetails = true; | ||
| 190 | + | ||
| 191 | + // display the selected nodes in the detail panel | ||
| 192 | + tps.displayMulti(selectOrder); | ||
| 193 | + | ||
| 194 | + // always add the 'show traffic' action | ||
| 195 | + tps.addAction('Show Related Traffic', showRelatedIntentsAction); | ||
| 196 | + | ||
| 197 | + // add other actions, based on what is selected... | ||
| 198 | + if (nSel() === 2 && allSelectionsClass('host')) { | ||
| 199 | + tps.addAction('Create Host-to-Host Flow', addHostIntentAction); | ||
| 200 | + } else if (nSel() >= 2 && allSelectionsClass('host')) { | ||
| 201 | + tps.addAction('Create Multi-Source Flow', addMultiSourceIntentAction); | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + cancelTraffic(); | ||
| 205 | + requestTrafficForMode(); | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + | ||
| 209 | + // === ----------------------------------------------------- | ||
| 210 | + // Event Handlers | ||
| 211 | + | ||
| 212 | + function showDetails(data) { | ||
| 213 | + haveDetails = true; | ||
| 214 | + | ||
| 215 | + // display the data for the single selected node | ||
| 216 | + tps.displaySingle(data); | ||
| 217 | + | ||
| 218 | + // always add the 'show traffic' action | ||
| 219 | + tps.addAction('Show Related Traffic', showRelatedIntentsAction); | ||
| 220 | + | ||
| 221 | + // add other actions, based on what is selected... | ||
| 222 | + if (data.type === 'switch') { | ||
| 223 | + tps.addAction('Show Device Flows', showDeviceLinkFlowsAction); | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + // only show the details panel if the user hasn't "hidden" it | ||
| 227 | + if (useDetails) { | ||
| 228 | + tps.showDetailPanel(); | ||
| 229 | + } | ||
| 230 | + } | ||
| 231 | + | ||
| 232 | + // === ----------------------------------------------------- | ||
| 233 | + // TODO: migrate these to topoTraffic.js | ||
| 234 | + | ||
| 235 | + function cancelTraffic() { | ||
| 236 | + $log.debug('TODO: cancelTraffic'); | ||
| 237 | + | ||
| 238 | + } | ||
| 239 | + function requestTrafficForMode() { | ||
| 240 | + $log.debug('TODO: requestTrafficForMode'); | ||
| 241 | + | ||
| 242 | + } | ||
| 243 | + function showRelatedIntentsAction () { | ||
| 244 | + $log.debug('TODO: showRelatedIntentsAction'); | ||
| 245 | + | ||
| 246 | + } | ||
| 247 | + function addHostIntentAction () { | ||
| 248 | + $log.debug('TODO: addHostIntentAction'); | ||
| 249 | + | ||
| 250 | + } | ||
| 251 | + function addMultiSourceIntentAction () { | ||
| 252 | + $log.debug('TODO: addMultiSourceIntentAction'); | ||
| 253 | + | ||
| 254 | + } | ||
| 255 | + function showDeviceLinkFlowsAction () { | ||
| 256 | + $log.debug('TODO: showDeviceLinkFlowsAction'); | ||
| 257 | + | ||
| 258 | + } | ||
| 259 | + | ||
| 260 | + | ||
| 261 | + // === ----------------------------------------------------- | ||
| 262 | + // === MODULE DEFINITION === | ||
| 263 | + | ||
| 264 | + angular.module('ovTopo') | ||
| 265 | + .factory('TopoSelectService', | ||
| 266 | + ['$log', 'FnService', 'TopoPanelService', | ||
| 267 | + | ||
| 268 | + function (_$log_, _fs_, _tps_) { | ||
| 269 | + $log = _$log_; | ||
| 270 | + fs = _fs_; | ||
| 271 | + tps = _tps_; | ||
| 272 | + | ||
| 273 | + function initSelect(_api_) { | ||
| 274 | + api = _api_; | ||
| 275 | + } | ||
| 276 | + | ||
| 277 | + function destroySelect() { } | ||
| 278 | + | ||
| 279 | + return { | ||
| 280 | + initSelect: initSelect, | ||
| 281 | + destroySelect: destroySelect, | ||
| 282 | + | ||
| 283 | + showDetails: showDetails, | ||
| 284 | + | ||
| 285 | + nodeMouseOver: nodeMouseOver, | ||
| 286 | + nodeMouseOut: nodeMouseOut, | ||
| 287 | + selectObject: selectObject, | ||
| 288 | + deselectObject: deselectObject, | ||
| 289 | + deselectAll: deselectAll, | ||
| 290 | + hovered: function () { return hovered; } | ||
| 291 | + }; | ||
| 292 | + }]); | ||
| 293 | +}()); |
| ... | @@ -88,7 +88,7 @@ describe('factory: fw/layer/panel.js', function () { | ... | @@ -88,7 +88,7 @@ describe('factory: fw/layer/panel.js', function () { |
| 88 | var p = ps.createPanel('foo'); | 88 | var p = ps.createPanel('foo'); |
| 89 | expect(fs.areFunctions(p, [ | 89 | expect(fs.areFunctions(p, [ |
| 90 | 'show', 'hide', 'toggle', 'empty', 'append', | 90 | 'show', 'hide', 'toggle', 'empty', 'append', |
| 91 | - 'width', 'height', 'isVisible', 'el' | 91 | + 'width', 'height', 'isVisible', 'classed', 'el' |
| 92 | ])).toBeTruthy(); | 92 | ])).toBeTruthy(); |
| 93 | }); | 93 | }); |
| 94 | 94 | ... | ... |
| ... | @@ -34,7 +34,16 @@ describe('factory: view/topo/topoPanel.js', function() { | ... | @@ -34,7 +34,16 @@ describe('factory: view/topo/topoPanel.js', function() { |
| 34 | 34 | ||
| 35 | it('should define api functions', function () { | 35 | it('should define api functions', function () { |
| 36 | expect(fs.areFunctions(tps, [ | 36 | expect(fs.areFunctions(tps, [ |
| 37 | - 'initPanels', 'destroyPanels', 'showSummary' | 37 | + 'initPanels', |
| 38 | + 'destroyPanels', | ||
| 39 | + 'showSummary', | ||
| 40 | + 'displaySingle', | ||
| 41 | + 'displayMulti', | ||
| 42 | + 'addAction', | ||
| 43 | + 'showDetailPanel', | ||
| 44 | + 'hideDetailPanel', | ||
| 45 | + 'detailVisible', | ||
| 46 | + 'summaryVisible' | ||
| 38 | ])).toBeTruthy(); | 47 | ])).toBeTruthy(); |
| 39 | }); | 48 | }); |
| 40 | 49 | ... | ... |
| 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 -- Topo View -- Topo Selection Service - Unit Tests | ||
| 19 | + */ | ||
| 20 | +describe('factory: view/topo/topoSelect.js', function() { | ||
| 21 | + var $log, fs, tss; | ||
| 22 | + | ||
| 23 | + beforeEach(module('ovTopo', 'onosUtil', 'onosLayer')); | ||
| 24 | + | ||
| 25 | + beforeEach(inject(function (_$log_, FnService, TopoSelectService) { | ||
| 26 | + $log = _$log_; | ||
| 27 | + fs = FnService; | ||
| 28 | + tss = TopoSelectService; | ||
| 29 | + })); | ||
| 30 | + | ||
| 31 | + it('should define TopoSelectService', function () { | ||
| 32 | + expect(tss).toBeDefined(); | ||
| 33 | + }); | ||
| 34 | + | ||
| 35 | + it('should define api functions', function () { | ||
| 36 | + expect(fs.areFunctions(tss, [ | ||
| 37 | + 'initSelect', 'destroySelect', 'showDetails', | ||
| 38 | + 'nodeMouseOver', 'nodeMouseOut', 'selectObject', 'deselectObject', | ||
| 39 | + 'deselectAll', 'hovered' | ||
| 40 | + ])).toBeTruthy(); | ||
| 41 | + }); | ||
| 42 | + | ||
| 43 | + // TODO: more tests... | ||
| 44 | +}); |
-
Please register or login to post a comment