blob: 6e1acdb73f1bd08762b94a2a4d12ed315e2fd12d [file] [log] [blame]
Primiano Tucci21b91bf2018-08-06 16:42:07 +01001// Copyright (C) 2018 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import * as m from 'mithril';
Primiano Tucci8afc06d2018-08-06 19:11:42 +010016
Hector Dearman5ae82472018-10-03 08:30:35 +010017import {Actions, deleteQuery} from '../common/actions';
Primiano Tucci8afc06d2018-08-06 19:11:42 +010018import {QueryResponse} from '../common/queries';
19import {EngineConfig} from '../common/state';
20
21import {globals} from './globals';
22
23const QUERY_ID = 'quicksearch';
Primiano Tucci21b91bf2018-08-06 16:42:07 +010024
25let selResult = 0;
26let numResults = 0;
27let mode: 'search'|'command' = 'search';
28
29function clearOmniboxResults() {
Primiano Tucci8afc06d2018-08-06 19:11:42 +010030 globals.queryResults.delete(QUERY_ID);
31 globals.dispatch(deleteQuery(QUERY_ID));
Primiano Tucci21b91bf2018-08-06 16:42:07 +010032}
33
34function onKeyDown(e: Event) {
35 e.stopPropagation();
36 const key = (e as KeyboardEvent).key;
37
38 // Avoid that the global 'a', 'd', 'w', 's' handler sees these keystrokes.
39 // TODO: this seems a bug in the pan_and_zoom_handler.ts.
40 if (key === 'ArrowUp' || key === 'ArrowDown') {
41 e.preventDefault();
42 return;
43 }
Primiano Tucci8afc06d2018-08-06 19:11:42 +010044 const txt = (e.target as HTMLInputElement);
Primiano Tucci21b91bf2018-08-06 16:42:07 +010045 if (key === ':' && txt.value === '') {
46 mode = 'command';
Deepanjan Royf190cb22018-08-28 10:43:07 -040047 globals.rafScheduler.scheduleFullRedraw();
Primiano Tucci21b91bf2018-08-06 16:42:07 +010048 e.preventDefault();
49 return;
50 }
51 if (key === 'Escape' && mode === 'command') {
52 txt.value = '';
53 mode = 'search';
Deepanjan Royf190cb22018-08-28 10:43:07 -040054 globals.rafScheduler.scheduleFullRedraw();
Primiano Tucci21b91bf2018-08-06 16:42:07 +010055 return;
56 }
57 if (key === 'Backspace' && txt.value.length === 0 && mode === 'command') {
58 mode = 'search';
Deepanjan Royf190cb22018-08-28 10:43:07 -040059 globals.rafScheduler.scheduleFullRedraw();
Primiano Tucci21b91bf2018-08-06 16:42:07 +010060 return;
61 }
Primiano Tucci21b91bf2018-08-06 16:42:07 +010062}
63
64function onKeyUp(e: Event) {
65 e.stopPropagation();
66 const key = (e as KeyboardEvent).key;
67 const txt = e.target as HTMLInputElement;
68 if (key === 'ArrowUp' || key === 'ArrowDown') {
69 selResult += (key === 'ArrowUp') ? -1 : 1;
70 selResult = Math.max(selResult, 0);
71 selResult = Math.min(selResult, numResults - 1);
72 e.preventDefault();
Deepanjan Royf190cb22018-08-28 10:43:07 -040073 globals.rafScheduler.scheduleFullRedraw();
Primiano Tucci21b91bf2018-08-06 16:42:07 +010074 return;
75 }
76 if (txt.value.length <= 0 || key === 'Escape') {
77 clearOmniboxResults();
Deepanjan Royf190cb22018-08-28 10:43:07 -040078 globals.rafScheduler.scheduleFullRedraw();
Primiano Tucci21b91bf2018-08-06 16:42:07 +010079 return;
80 }
Primiano Tucci8afc06d2018-08-06 19:11:42 +010081 if (mode === 'search') {
82 const name = txt.value.replace(/'/g, '\\\'').replace(/[*]/g, '%');
Hector Dearman12323362018-08-09 16:09:28 +010083 const query = `select str from strings where str like '%${name}%' limit 10`;
Hector Dearman5ae82472018-10-03 08:30:35 +010084 globals.dispatch(
85 Actions.executeQuery({engineId: '0', queryId: QUERY_ID, query}));
Primiano Tucci8afc06d2018-08-06 19:11:42 +010086 }
87 if (mode === 'command' && key === 'Enter') {
Hector Dearman5ae82472018-10-03 08:30:35 +010088 globals.dispatch(Actions.executeQuery(
89 {engineId: '0', queryId: 'command', query: txt.value}));
Primiano Tucci8afc06d2018-08-06 19:11:42 +010090 }
Primiano Tucci21b91bf2018-08-06 16:42:07 +010091}
92
93
Deepanjan Roy97f63242018-09-20 15:32:01 -040094class Omnibox implements m.ClassComponent {
95 oncreate(vnode: m.VnodeDOM) {
Primiano Tucci21b91bf2018-08-06 16:42:07 +010096 const txt = vnode.dom.querySelector('input') as HTMLInputElement;
97 txt.addEventListener('blur', clearOmniboxResults);
98 txt.addEventListener('keydown', onKeyDown);
99 txt.addEventListener('keyup', onKeyUp);
Deepanjan Roy97f63242018-09-20 15:32:01 -0400100 }
101
Primiano Tucci21b91bf2018-08-06 16:42:07 +0100102 view() {
Primiano Tuccie36ca632018-08-21 14:32:23 +0200103 const msgTTL = globals.state.status.timestamp + 3 - Date.now() / 1e3;
104 let enginesAreBusy = false;
105 for (const engine of Object.values(globals.state.engines)) {
106 enginesAreBusy = enginesAreBusy || !engine.ready;
107 }
108
109 if (msgTTL > 0 || enginesAreBusy) {
Deepanjan Royf190cb22018-08-28 10:43:07 -0400110 setTimeout(
111 () => globals.rafScheduler.scheduleFullRedraw(), msgTTL * 1000);
Primiano Tuccie36ca632018-08-21 14:32:23 +0200112 return m(
113 `.omnibox.message-mode`,
114 m(`input[placeholder=${globals.state.status.msg}][readonly]`));
115 }
116
Primiano Tucci21b91bf2018-08-06 16:42:07 +0100117 // TODO(primiano): handle query results here.
Primiano Tucci8afc06d2018-08-06 19:11:42 +0100118 const results = [];
119 const resp = globals.queryResults.get(QUERY_ID) as QueryResponse;
120 if (resp !== undefined) {
121 numResults = resp.rows ? resp.rows.length : 0;
122 for (let i = 0; i < resp.rows.length; i++) {
123 const clazz = (i === selResult) ? '.selected' : '';
124 results.push(m(`div${clazz}`, resp.rows[i][resp.columns[0]]));
125 }
126 }
Primiano Tucci21b91bf2018-08-06 16:42:07 +0100127 const placeholder = {
128 search: 'Search or type : to enter command mode',
129 command: 'e.g., select * from sched left join thread using(utid) limit 10'
130 };
Primiano Tuccie36ca632018-08-21 14:32:23 +0200131
Primiano Tucci21b91bf2018-08-06 16:42:07 +0100132 const commandMode = mode === 'command';
133 return m(
134 `.omnibox${commandMode ? '.command-mode' : ''}`,
Primiano Tuccie36ca632018-08-21 14:32:23 +0200135 m(`input[placeholder=${placeholder[mode]}]`),
Primiano Tucci8afc06d2018-08-06 19:11:42 +0100136 m('.omnibox-results', results));
Deepanjan Roy97f63242018-09-20 15:32:01 -0400137 }
138}
Primiano Tucci21b91bf2018-08-06 16:42:07 +0100139
Deepanjan Roy97f63242018-09-20 15:32:01 -0400140export class Topbar implements m.ClassComponent {
Primiano Tucci21b91bf2018-08-06 16:42:07 +0100141 view() {
Primiano Tucci8afc06d2018-08-06 19:11:42 +0100142 const progBar = [];
143 const engine: EngineConfig = globals.state.engines['0'];
144 if (globals.state.queries[QUERY_ID] !== undefined ||
145 (engine !== undefined && !engine.ready)) {
146 progBar.push(m('.progress'));
147 }
Deepanjan Roy97f63242018-09-20 15:32:01 -0400148 return m('.topbar', m(Omnibox), ...progBar);
149 }
150}