blob: 28c488b2b0b2e3ae36950b136fceae9f98de809f [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: '/',
Simon Hunt41effbe2014-12-04 09:41:44 -080058 backSlash: '\\',
Thomas Vachuska1e68bdd2014-11-29 13:53:10 -080059 backQuote: '`',
Simon Hunt5cef9062014-11-24 15:24:35 -080060 leftArrow: 'L-arrow',
61 upArrow: 'U-arrow',
62 rightArrow: 'R-arrow',
63 downArrow: 'D-arrow'
64 };
Simon Hunt56ef0fe2014-11-21 08:24:43 -080065
Simon Hunt5cef9062014-11-24 15:24:35 -080066 function cap(s) {
67 return s.replace(/^[a-z]/, function (m) { return m.toUpperCase(); });
68 }
Simon Hunt56ef0fe2014-11-21 08:24:43 -080069
Simon Hunt5cef9062014-11-24 15:24:35 -080070 function mkKeyDisp(id) {
71 var v = keyDisp[id] || id;
72 return cap(v);
73 }
74
75 // layout configuration
76 var pad = 8,
77 offy = 45,
Thomas Vachuska6810b7882014-12-03 00:37:25 -080078 dy = 10,
Simon Hunt87514342014-11-24 16:41:27 -080079 offDesc = 8;
Simon Hunt5cef9062014-11-24 15:24:35 -080080
81 // D3 magic
Simon Hunt56ef0fe2014-11-21 08:24:43 -080082 function updateKeyItems() {
Simon Hunt5cef9062014-11-24 15:24:35 -080083 var keyItems = items.selectAll('.keyItem')
Simon Hunt988c6fc2014-11-20 17:43:03 -080084 .data(data);
85
Simon Hunt5cef9062014-11-24 15:24:35 -080086 var entering = keyItems.enter()
Simon Hunt988c6fc2014-11-20 17:43:03 -080087 .append('g')
88 .attr({
Simon Hunt56ef0fe2014-11-21 08:24:43 -080089 id: function (d) { return d.id; },
90 class: 'keyItem'
91 });
Simon Hunt988c6fc2014-11-20 17:43:03 -080092
Simon Hunt56ef0fe2014-11-21 08:24:43 -080093 entering.each(function (d, i) {
Simon Hunt988c6fc2014-11-20 17:43:03 -080094 var el = d3.select(this),
Simon Hunt56ef0fe2014-11-21 08:24:43 -080095 y = offy + dy * i;
Simon Hunt988c6fc2014-11-20 17:43:03 -080096
Simon Hunt87514342014-11-24 16:41:27 -080097 if (d.id[0] === '_') {
Simon Hunt56ef0fe2014-11-21 08:24:43 -080098 el.append('line')
Simon Hunt5cef9062014-11-24 15:24:35 -080099 .attr({ x1: 0, y1: y, x2: 1, y2: y});
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800100 } else {
101 el.append('text')
102 .text(d.key)
103 .attr({
104 class: 'key',
Simon Hunt5cef9062014-11-24 15:24:35 -0800105 x: 0,
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800106 y: y
107 });
Simon Hunt87514342014-11-24 16:41:27 -0800108 // NOTE: used for sizing column width...
109 keyAgg.append('text').text(d.key).attr('class', 'key');
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800110
111 el.append('text')
112 .text(d.desc)
113 .attr({
114 class: 'desc',
115 x: offDesc,
116 y: y
117 });
118 }
119 });
Simon Hunt5cef9062014-11-24 15:24:35 -0800120
Simon Hunt87514342014-11-24 16:41:27 -0800121 var kbox = keyAgg.node().getBBox();
122 items.selectAll('.desc').attr('x', kbox.width + offDesc);
123
Simon Hunt5cef9062014-11-24 15:24:35 -0800124 var box = items.node().getBBox(),
125 paneW = box.width + pad * 2,
126 paneH = box.height + offy;
127
Simon Hunt87514342014-11-24 16:41:27 -0800128 items.selectAll('line').attr('x2', box.width);
Simon Hunt5cef9062014-11-24 15:24:35 -0800129 items.attr('transform', translate(-paneW/2, -pad));
130 rect.attr({
131 width: paneW,
132 height: paneH,
133 transform: translate(-paneW/2-pad, 0)
134 });
135 }
136
137 function translate(x, y) {
138 return 'translate(' + x + ',' + y + ')';
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800139 }
140
141 function aggregateData(bindings) {
Simon Hunta1162d82014-12-03 14:34:43 -0800142 var hf = '_helpFormat',
143 gmap = d3.map(bindings.globalKeys),
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800144 vmap = d3.map(bindings.viewKeys),
Simon Hunta1162d82014-12-03 14:34:43 -0800145 fmt = vmap.get(hf),
Simon Hunt87514342014-11-24 16:41:27 -0800146 vgest = bindings.viewGestures,
Simon Hunta1162d82014-12-03 14:34:43 -0800147 gkeys = gmap.keys(),
148 vkeys,
Simon Hunt87514342014-11-24 16:41:27 -0800149 sep = 0;
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800150
Simon Hunta1162d82014-12-03 14:34:43 -0800151 // filter out help format entry
152 vmap.remove(hf);
153 vkeys = vmap.keys(),
154
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800155 gkeys.sort();
156 vkeys.sort();
157
158 data = [];
159 gkeys.forEach(function (k) {
Simon Hunt87514342014-11-24 16:41:27 -0800160 addItem('glob', k, gmap.get(k));
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800161 });
Simon Hunt87514342014-11-24 16:41:27 -0800162 addItem('sep');
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800163 vkeys.forEach(function (k) {
164 addItem('view', k, vmap.get(k));
Simon Hunt988c6fc2014-11-20 17:43:03 -0800165 });
Simon Hunt87514342014-11-24 16:41:27 -0800166 addItem('sep');
167 vgest.forEach(function (g) {
168 if (g.length === 2) {
169 addItem('gest', g[0], g[1]);
170 }
171 });
172
Simon Hunt988c6fc2014-11-20 17:43:03 -0800173
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800174 function addItem(type, k, d) {
175 var id = type + '-' + k,
176 a = isA(d),
177 desc = a && a[1];
Simon Hunt87514342014-11-24 16:41:27 -0800178
179 if (type === 'sep') {
180 data.push({
181 id: '_' + sep++,
182 type: type
183 });
184 } else if (type === 'gest') {
185 data.push({
186 id: id,
187 type: type,
188 key: k,
189 desc: d
190 });
191 } else if (desc) {
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800192 data.push(
193 {
194 id: id,
195 type: type,
Simon Hunt5cef9062014-11-24 15:24:35 -0800196 key: mkKeyDisp(k),
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800197 desc: desc
198 }
199 );
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800200 }
Simon Hunt988c6fc2014-11-20 17:43:03 -0800201 }
Simon Hunt988c6fc2014-11-20 17:43:03 -0800202 }
203
Simon Hunt5cef9062014-11-24 15:24:35 -0800204 function popBind(bindings) {
205 pane = svg.append('g')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800206 .attr({
Simon Hunt5cef9062014-11-24 15:24:35 -0800207 class: 'help',
Simon Hunt988c6fc2014-11-20 17:43:03 -0800208 opacity: 0
Simon Hunt988c6fc2014-11-20 17:43:03 -0800209 });
210
Simon Hunt5cef9062014-11-24 15:24:35 -0800211 rect = pane.append('rect')
212 .attr('rx', 8);
213
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800214 pane.append('text')
Simon Hunt5cef9062014-11-24 15:24:35 -0800215 .text('Quick Help')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800216 .attr({
Simon Hunt5cef9062014-11-24 15:24:35 -0800217 class: 'title',
218 dy: '1.2em',
219 transform: translate(-pad,0)
Simon Hunt988c6fc2014-11-20 17:43:03 -0800220 });
221
Simon Hunt5cef9062014-11-24 15:24:35 -0800222 items = pane.append('g');
Simon Hunt87514342014-11-24 16:41:27 -0800223 keyAgg = pane.append('g').style('visibility', 'hidden');
Simon Hunt5cef9062014-11-24 15:24:35 -0800224
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800225 aggregateData(bindings);
226 updateKeyItems();
Simon Hunt5cef9062014-11-24 15:24:35 -0800227
228 _fade(1);
Simon Hunt988c6fc2014-11-20 17:43:03 -0800229 }
230
231 function fadeBindings() {
Simon Hunt5cef9062014-11-24 15:24:35 -0800232 _fade(0);
233 }
234
235 function _fade(o) {
236 svg.selectAll('g.help')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800237 .transition()
238 .duration(fade)
Simon Hunt5cef9062014-11-24 15:24:35 -0800239 .attr('opacity', o);
Simon Hunt988c6fc2014-11-20 17:43:03 -0800240 }
241
242 function addSvg() {
Simon Hunt5cef9062014-11-24 15:24:35 -0800243 svg = qhdiv.append('svg')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800244 .attr({
245 width: w,
246 height: h,
247 viewBox: vb
248 });
249 }
250
251 function removeSvg() {
252 svg.transition()
253 .delay(fade + 20)
254 .remove();
255 }
256
Simon Hunt5cef9062014-11-24 15:24:35 -0800257 function showQuickHelp(bindings) {
258 svg = qhdiv.select('svg');
Simon Hunt988c6fc2014-11-20 17:43:03 -0800259 if (svg.empty()) {
260 addSvg();
Simon Hunt5cef9062014-11-24 15:24:35 -0800261 popBind(bindings);
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800262 } else {
Simon Hunt5cef9062014-11-24 15:24:35 -0800263 hideQuickHelp();
Simon Hunt988c6fc2014-11-20 17:43:03 -0800264 }
265 }
266
Simon Hunt5cef9062014-11-24 15:24:35 -0800267 function hideQuickHelp() {
268 svg = qhdiv.select('svg');
Simon Hunt988c6fc2014-11-20 17:43:03 -0800269 if (!svg.empty()) {
270 fadeBindings();
271 removeSvg();
Simon Hunt988c6fc2014-11-20 17:43:03 -0800272 return true;
273 }
274 return false;
275 }
276
Simon Hunt5cef9062014-11-24 15:24:35 -0800277 onos.ui.addLib('quickHelp', {
278 show: showQuickHelp,
279 hide: hideQuickHelp
Simon Hunt988c6fc2014-11-20 17:43:03 -0800280 });
281}(ONOS));