blob: 2cc2a1847326e2dbdb5ed999a657bf8ee8c3eb1e [file] [log] [blame]
Simon Hunt988c6fc2014-11-20 17:43:03 -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/*
Simon Hunt5cef9062014-11-24 15:24:35 -080018 ONOS GUI -- Quick Help Layer
Simon Hunt988c6fc2014-11-20 17:43:03 -080019
20 Defines the key-map layer for the UI. Used to give user a list of
21 key bindings; both global, and for the current view.
22
23 @author Simon Hunt
24 */
25
26(function (onos){
27 'use strict';
28
29 // API's
30 var api = onos.api;
31
32 // Config variables
33 var w = '100%',
34 h = '80%',
Simon Hunt209155e2014-11-21 12:16:09 -080035 fade = 500,
Simon Hunt5cef9062014-11-24 15:24:35 -080036 vb = '-200 0 400 400';
Simon Hunt988c6fc2014-11-20 17:43:03 -080037
38 // State variables
39 var data = [];
40
41 // DOM elements and the like
Simon Hunt5cef9062014-11-24 15:24:35 -080042 var qhdiv = d3.select('#quickhelp'),
43 svg = qhdiv.select('svg'),
44 pane,
45 rect,
Simon Hunt87514342014-11-24 16:41:27 -080046 items,
47 keyAgg;
Simon Hunt988c6fc2014-11-20 17:43:03 -080048
Simon Hunt5cef9062014-11-24 15:24:35 -080049 // General functions
Simon Hunt56ef0fe2014-11-21 08:24:43 -080050 function isA(a) {
51 return $.isArray(a) ? a : null;
Simon Hunt988c6fc2014-11-20 17:43:03 -080052 }
53
Simon Hunt5cef9062014-11-24 15:24:35 -080054 var keyDisp = {
55 equals: '=',
56 dash: '-',
57 slash: '/',
Thomas Vachuska1e68bdd2014-11-29 13:53:10 -080058 backQuote: '`',
Simon Hunt5cef9062014-11-24 15:24:35 -080059 leftArrow: 'L-arrow',
60 upArrow: 'U-arrow',
61 rightArrow: 'R-arrow',
62 downArrow: 'D-arrow'
63 };
Simon Hunt56ef0fe2014-11-21 08:24:43 -080064
Simon Hunt5cef9062014-11-24 15:24:35 -080065 function cap(s) {
66 return s.replace(/^[a-z]/, function (m) { return m.toUpperCase(); });
67 }
Simon Hunt56ef0fe2014-11-21 08:24:43 -080068
Simon Hunt5cef9062014-11-24 15:24:35 -080069 function mkKeyDisp(id) {
70 var v = keyDisp[id] || id;
71 return cap(v);
72 }
73
74 // layout configuration
75 var pad = 8,
76 offy = 45,
Thomas Vachuska6810b7882014-12-03 00:37:25 -080077 dy = 10,
Simon Hunt87514342014-11-24 16:41:27 -080078 offDesc = 8;
Simon Hunt5cef9062014-11-24 15:24:35 -080079
80 // D3 magic
Simon Hunt56ef0fe2014-11-21 08:24:43 -080081 function updateKeyItems() {
Simon Hunt5cef9062014-11-24 15:24:35 -080082 var keyItems = items.selectAll('.keyItem')
Simon Hunt988c6fc2014-11-20 17:43:03 -080083 .data(data);
84
Simon Hunt5cef9062014-11-24 15:24:35 -080085 var entering = keyItems.enter()
Simon Hunt988c6fc2014-11-20 17:43:03 -080086 .append('g')
87 .attr({
Simon Hunt56ef0fe2014-11-21 08:24:43 -080088 id: function (d) { return d.id; },
89 class: 'keyItem'
90 });
Simon Hunt988c6fc2014-11-20 17:43:03 -080091
Simon Hunt56ef0fe2014-11-21 08:24:43 -080092 entering.each(function (d, i) {
Simon Hunt988c6fc2014-11-20 17:43:03 -080093 var el = d3.select(this),
Simon Hunt56ef0fe2014-11-21 08:24:43 -080094 y = offy + dy * i;
Simon Hunt988c6fc2014-11-20 17:43:03 -080095
Simon Hunt87514342014-11-24 16:41:27 -080096 if (d.id[0] === '_') {
Simon Hunt56ef0fe2014-11-21 08:24:43 -080097 el.append('line')
Simon Hunt5cef9062014-11-24 15:24:35 -080098 .attr({ x1: 0, y1: y, x2: 1, y2: y});
Simon Hunt56ef0fe2014-11-21 08:24:43 -080099 } else {
100 el.append('text')
101 .text(d.key)
102 .attr({
103 class: 'key',
Simon Hunt5cef9062014-11-24 15:24:35 -0800104 x: 0,
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800105 y: y
106 });
Simon Hunt87514342014-11-24 16:41:27 -0800107 // NOTE: used for sizing column width...
108 keyAgg.append('text').text(d.key).attr('class', 'key');
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800109
110 el.append('text')
111 .text(d.desc)
112 .attr({
113 class: 'desc',
114 x: offDesc,
115 y: y
116 });
117 }
118 });
Simon Hunt5cef9062014-11-24 15:24:35 -0800119
Simon Hunt87514342014-11-24 16:41:27 -0800120 var kbox = keyAgg.node().getBBox();
121 items.selectAll('.desc').attr('x', kbox.width + offDesc);
122
Simon Hunt5cef9062014-11-24 15:24:35 -0800123 var box = items.node().getBBox(),
124 paneW = box.width + pad * 2,
125 paneH = box.height + offy;
126
Simon Hunt87514342014-11-24 16:41:27 -0800127 items.selectAll('line').attr('x2', box.width);
Simon Hunt5cef9062014-11-24 15:24:35 -0800128 items.attr('transform', translate(-paneW/2, -pad));
129 rect.attr({
130 width: paneW,
131 height: paneH,
132 transform: translate(-paneW/2-pad, 0)
133 });
134 }
135
136 function translate(x, y) {
137 return 'translate(' + x + ',' + y + ')';
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800138 }
139
140 function aggregateData(bindings) {
Simon Hunta1162d82014-12-03 14:34:43 -0800141 var hf = '_helpFormat',
142 gmap = d3.map(bindings.globalKeys),
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800143 vmap = d3.map(bindings.viewKeys),
Simon Hunta1162d82014-12-03 14:34:43 -0800144 fmt = vmap.get(hf),
Simon Hunt87514342014-11-24 16:41:27 -0800145 vgest = bindings.viewGestures,
Simon Hunta1162d82014-12-03 14:34:43 -0800146 gkeys = gmap.keys(),
147 vkeys,
Simon Hunt87514342014-11-24 16:41:27 -0800148 sep = 0;
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800149
Simon Hunta1162d82014-12-03 14:34:43 -0800150 // filter out help format entry
151 vmap.remove(hf);
152 vkeys = vmap.keys(),
153
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800154 gkeys.sort();
155 vkeys.sort();
156
157 data = [];
158 gkeys.forEach(function (k) {
Simon Hunt87514342014-11-24 16:41:27 -0800159 addItem('glob', k, gmap.get(k));
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800160 });
Simon Hunt87514342014-11-24 16:41:27 -0800161 addItem('sep');
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800162 vkeys.forEach(function (k) {
163 addItem('view', k, vmap.get(k));
Simon Hunt988c6fc2014-11-20 17:43:03 -0800164 });
Simon Hunt87514342014-11-24 16:41:27 -0800165 addItem('sep');
166 vgest.forEach(function (g) {
167 if (g.length === 2) {
168 addItem('gest', g[0], g[1]);
169 }
170 });
171
Simon Hunt988c6fc2014-11-20 17:43:03 -0800172
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800173 function addItem(type, k, d) {
174 var id = type + '-' + k,
175 a = isA(d),
176 desc = a && a[1];
Simon Hunt87514342014-11-24 16:41:27 -0800177
178 if (type === 'sep') {
179 data.push({
180 id: '_' + sep++,
181 type: type
182 });
183 } else if (type === 'gest') {
184 data.push({
185 id: id,
186 type: type,
187 key: k,
188 desc: d
189 });
190 } else if (desc) {
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800191 data.push(
192 {
193 id: id,
194 type: type,
Simon Hunt5cef9062014-11-24 15:24:35 -0800195 key: mkKeyDisp(k),
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800196 desc: desc
197 }
198 );
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800199 }
Simon Hunt988c6fc2014-11-20 17:43:03 -0800200 }
Simon Hunt988c6fc2014-11-20 17:43:03 -0800201 }
202
Simon Hunt5cef9062014-11-24 15:24:35 -0800203 function popBind(bindings) {
204 pane = svg.append('g')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800205 .attr({
Simon Hunt5cef9062014-11-24 15:24:35 -0800206 class: 'help',
Simon Hunt988c6fc2014-11-20 17:43:03 -0800207 opacity: 0
Simon Hunt988c6fc2014-11-20 17:43:03 -0800208 });
209
Simon Hunt5cef9062014-11-24 15:24:35 -0800210 rect = pane.append('rect')
211 .attr('rx', 8);
212
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800213 pane.append('text')
Simon Hunt5cef9062014-11-24 15:24:35 -0800214 .text('Quick Help')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800215 .attr({
Simon Hunt5cef9062014-11-24 15:24:35 -0800216 class: 'title',
217 dy: '1.2em',
218 transform: translate(-pad,0)
Simon Hunt988c6fc2014-11-20 17:43:03 -0800219 });
220
Simon Hunt5cef9062014-11-24 15:24:35 -0800221 items = pane.append('g');
Simon Hunt87514342014-11-24 16:41:27 -0800222 keyAgg = pane.append('g').style('visibility', 'hidden');
Simon Hunt5cef9062014-11-24 15:24:35 -0800223
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800224 aggregateData(bindings);
225 updateKeyItems();
Simon Hunt5cef9062014-11-24 15:24:35 -0800226
227 _fade(1);
Simon Hunt988c6fc2014-11-20 17:43:03 -0800228 }
229
230 function fadeBindings() {
Simon Hunt5cef9062014-11-24 15:24:35 -0800231 _fade(0);
232 }
233
234 function _fade(o) {
235 svg.selectAll('g.help')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800236 .transition()
237 .duration(fade)
Simon Hunt5cef9062014-11-24 15:24:35 -0800238 .attr('opacity', o);
Simon Hunt988c6fc2014-11-20 17:43:03 -0800239 }
240
241 function addSvg() {
Simon Hunt5cef9062014-11-24 15:24:35 -0800242 svg = qhdiv.append('svg')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800243 .attr({
244 width: w,
245 height: h,
246 viewBox: vb
247 });
248 }
249
250 function removeSvg() {
251 svg.transition()
252 .delay(fade + 20)
253 .remove();
254 }
255
Simon Hunt5cef9062014-11-24 15:24:35 -0800256 function showQuickHelp(bindings) {
257 svg = qhdiv.select('svg');
Simon Hunt988c6fc2014-11-20 17:43:03 -0800258 if (svg.empty()) {
259 addSvg();
Simon Hunt5cef9062014-11-24 15:24:35 -0800260 popBind(bindings);
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800261 } else {
Simon Hunt5cef9062014-11-24 15:24:35 -0800262 hideQuickHelp();
Simon Hunt988c6fc2014-11-20 17:43:03 -0800263 }
264 }
265
Simon Hunt5cef9062014-11-24 15:24:35 -0800266 function hideQuickHelp() {
267 svg = qhdiv.select('svg');
Simon Hunt988c6fc2014-11-20 17:43:03 -0800268 if (!svg.empty()) {
269 fadeBindings();
270 removeSvg();
Simon Hunt988c6fc2014-11-20 17:43:03 -0800271 return true;
272 }
273 return false;
274 }
275
Simon Hunt5cef9062014-11-24 15:24:35 -0800276 onos.ui.addLib('quickHelp', {
277 show: showQuickHelp,
278 hide: hideQuickHelp
Simon Hunt988c6fc2014-11-20 17:43:03 -0800279 });
280}(ONOS));