ONOS-2876 -- GUI - first cut at client-side code for device friendly name setting (still WIP).
Change-Id: I531a2f1fef698cb72a5529f732bb2a0a97e2acc4
Showing
3 changed files
with
117 additions
and
5 deletions
... | @@ -153,6 +153,10 @@ public class DeviceViewMessageHandler extends UiMessageHandler { | ... | @@ -153,6 +153,10 @@ public class DeviceViewMessageHandler extends UiMessageHandler { |
153 | ObjectNode data = MAPPER.createObjectNode(); | 153 | ObjectNode data = MAPPER.createObjectNode(); |
154 | 154 | ||
155 | data.put(ID, deviceId.toString()); | 155 | data.put(ID, deviceId.toString()); |
156 | + | ||
157 | + // TODO: get friendly name from the device | ||
158 | + data.put(NAME, deviceId.toString()); | ||
159 | + | ||
156 | data.put(TYPE, capitalizeFully(device.type().toString())); | 160 | data.put(TYPE, capitalizeFully(device.type().toString())); |
157 | data.put(TYPE_IID, getTypeIconId(device)); | 161 | data.put(TYPE_IID, getTypeIconId(device)); |
158 | data.put(MFR, device.manufacturer()); | 162 | data.put(MFR, device.manufacturer()); | ... | ... |
... | @@ -75,6 +75,30 @@ | ... | @@ -75,6 +75,30 @@ |
75 | margin: 8px 0; | 75 | margin: 8px 0; |
76 | } | 76 | } |
77 | 77 | ||
78 | +#device-details-panel .name-div { | ||
79 | + height: 20px; | ||
80 | + padding: 8px 0 0 8px; | ||
81 | +} | ||
82 | + | ||
83 | +#device-details-panel .name-div span { | ||
84 | + display: inline-block; | ||
85 | +} | ||
86 | + | ||
87 | +#device-details-panel .name-div .label { | ||
88 | + font-style: italic; | ||
89 | + padding-right: 12px; | ||
90 | + /* works for both light and dark themes ... */ | ||
91 | + color: #777; | ||
92 | +} | ||
93 | + | ||
94 | +#device-details-panel .name-div .value { | ||
95 | +} | ||
96 | + | ||
97 | +#device-details-panel .editable { | ||
98 | + cursor: pointer; | ||
99 | + border-bottom: 1px dashed darkgreen; | ||
100 | +} | ||
101 | + | ||
78 | #device-details-panel .top div.left { | 102 | #device-details-panel .top div.left { |
79 | float: left; | 103 | float: left; |
80 | padding: 0 18px 0 0; | 104 | padding: 0 18px 0 0; | ... | ... |
... | @@ -26,9 +26,13 @@ | ... | @@ -26,9 +26,13 @@ |
26 | 26 | ||
27 | // internal state | 27 | // internal state |
28 | var detailsPanel, | 28 | var detailsPanel, |
29 | - pStartY, pHeight, | 29 | + pStartY, |
30 | - top, bottom, iconDiv, | 30 | + pHeight, |
31 | - wSize; | 31 | + top, |
32 | + bottom, | ||
33 | + iconDiv, | ||
34 | + wSize, | ||
35 | + editingName = false; | ||
32 | 36 | ||
33 | // constants | 37 | // constants |
34 | var topPdg = 13, | 38 | var topPdg = 13, |
... | @@ -59,7 +63,9 @@ | ... | @@ -59,7 +63,9 @@ |
59 | if (detailsPanel.isVisible()) { | 63 | if (detailsPanel.isVisible()) { |
60 | $scope.selId = null; | 64 | $scope.selId = null; |
61 | detailsPanel.hide(); | 65 | detailsPanel.hide(); |
66 | + return true; | ||
62 | } | 67 | } |
68 | + return false; | ||
63 | } | 69 | } |
64 | 70 | ||
65 | function addCloseBtn(div) { | 71 | function addCloseBtn(div) { |
... | @@ -68,6 +74,72 @@ | ... | @@ -68,6 +74,72 @@ |
68 | div.on('click', closePanel); | 74 | div.on('click', closePanel); |
69 | } | 75 | } |
70 | 76 | ||
77 | + function getNameSpan() { | ||
78 | + return top.select('.name-div').select('.value'); | ||
79 | + } | ||
80 | + | ||
81 | + function nameValid(name) { | ||
82 | + // TODO: guard against empty strings etc. | ||
83 | + return true; | ||
84 | + } | ||
85 | + | ||
86 | + function editNameSave() { | ||
87 | + var span = getNameSpan(), | ||
88 | + newVal; | ||
89 | + if (editingName) { | ||
90 | + newVal = span.select('input').property('value'); | ||
91 | + | ||
92 | + $log.debug("TODO: Saving name change... to '" + newVal + "'"); | ||
93 | + if (!nameValid(newVal)) { | ||
94 | + return editNameCancel(); | ||
95 | + } | ||
96 | + | ||
97 | + // TODO: send event to server to set friendly name for device | ||
98 | + $scope.panelData.name = newVal; | ||
99 | + | ||
100 | + span.html(newVal); | ||
101 | + span.classed('editable', true); | ||
102 | + editingName = false; | ||
103 | + } | ||
104 | + } | ||
105 | + | ||
106 | + function editNameCancel() { | ||
107 | + var span = getNameSpan(); | ||
108 | + if (editingName) { | ||
109 | + $log.debug("Canceling name change..."); | ||
110 | + span.html($scope.panelData.name); | ||
111 | + span.classed('editable', true); | ||
112 | + editingName = false; | ||
113 | + return true; | ||
114 | + } | ||
115 | + return false; | ||
116 | + } | ||
117 | + | ||
118 | + function editName() { | ||
119 | + $log.log('editName() .. editing=' + editingName); | ||
120 | + var span = getNameSpan(); | ||
121 | + if (!editingName) { | ||
122 | + editingName = true; | ||
123 | + span.classed('editable', false); | ||
124 | + span.html(''); | ||
125 | + span.append('input').classed('name-input', true) | ||
126 | + .attr('type', 'text') | ||
127 | + .attr('value', $scope.panelData.name); | ||
128 | + } | ||
129 | + } | ||
130 | + | ||
131 | + function handleEscape() { | ||
132 | + return editNameCancel() || closePanel(); | ||
133 | + } | ||
134 | + | ||
135 | + function setUpEditableName(top) { | ||
136 | + var div = top.append('div').classed('name-div', true); | ||
137 | + | ||
138 | + div.append('span').classed('label', true); | ||
139 | + div.append('span').classed('value editable', true) | ||
140 | + .on('click', editName); | ||
141 | + } | ||
142 | + | ||
71 | function setUpPanel() { | 143 | function setUpPanel() { |
72 | var container, closeBtn, tblDiv; | 144 | var container, closeBtn, tblDiv; |
73 | detailsPanel.empty(); | 145 | detailsPanel.empty(); |
... | @@ -80,6 +152,8 @@ | ... | @@ -80,6 +152,8 @@ |
80 | iconDiv = top.append('div').classed('dev-icon', true); | 152 | iconDiv = top.append('div').classed('dev-icon', true); |
81 | top.append('h2'); | 153 | top.append('h2'); |
82 | 154 | ||
155 | + setUpEditableName(top); | ||
156 | + | ||
83 | tblDiv = top.append('div').classed('top-tables', true); | 157 | tblDiv = top.append('div').classed('top-tables', true); |
84 | tblDiv.append('div').classed('left', true).append('table'); | 158 | tblDiv.append('div').classed('left', true).append('table'); |
85 | tblDiv.append('div').classed('right', true).append('table'); | 159 | tblDiv.append('div').classed('right', true).append('table'); |
... | @@ -156,14 +230,23 @@ | ... | @@ -156,14 +230,23 @@ |
156 | detailsPanel.width(tbWidth + ctnrPdg); | 230 | detailsPanel.width(tbWidth + ctnrPdg); |
157 | } | 231 | } |
158 | 232 | ||
233 | + function populateName(div, name) { | ||
234 | + var lab = div.select('.label'), | ||
235 | + val = div.select('.value'); | ||
236 | + lab.html('Friendly Name:'); | ||
237 | + val.html(name); | ||
238 | + } | ||
239 | + | ||
159 | function populateDetails(details) { | 240 | function populateDetails(details) { |
160 | - var topTbs, btmTbl, ports; | 241 | + var nameDiv, topTbs, btmTbl, ports; |
161 | setUpPanel(); | 242 | setUpPanel(); |
162 | 243 | ||
244 | + nameDiv = top.select('.name-div'); | ||
163 | topTbs = top.select('.top-tables'); | 245 | topTbs = top.select('.top-tables'); |
164 | btmTbl = bottom.select('table'); | 246 | btmTbl = bottom.select('table'); |
165 | ports = details.ports; | 247 | ports = details.ports; |
166 | 248 | ||
249 | + populateName(nameDiv, details.name); | ||
167 | populateTop(topTbs, details); | 250 | populateTop(topTbs, details); |
168 | populateBottom(btmTbl, ports); | 251 | populateBottom(btmTbl, ports); |
169 | 252 | ||
... | @@ -278,7 +361,8 @@ | ... | @@ -278,7 +361,8 @@ |
278 | } | 361 | } |
279 | // create key bindings to handle panel | 362 | // create key bindings to handle panel |
280 | ks.keyBindings({ | 363 | ks.keyBindings({ |
281 | - esc: [closePanel, 'Close the details panel'], | 364 | + enter: editNameSave, |
365 | + esc: [handleEscape, 'Close the details panel'], | ||
282 | _helpFormat: ['esc'] | 366 | _helpFormat: ['esc'] |
283 | }); | 367 | }); |
284 | ks.gestureNotes([ | 368 | ks.gestureNotes([ | ... | ... |
-
Please register or login to post a comment