Primiano Tucci | 21b91bf | 2018-08-06 16:42:07 +0100 | [diff] [blame] | 1 | // 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 | |
| 15 | import * as m from 'mithril'; |
Primiano Tucci | 8afc06d | 2018-08-06 19:11:42 +0100 | [diff] [blame] | 16 | |
| 17 | import {deleteQuery, executeQuery} from '../common/actions'; |
| 18 | import {QueryResponse} from '../common/queries'; |
| 19 | import {EngineConfig} from '../common/state'; |
| 20 | |
| 21 | import {globals} from './globals'; |
| 22 | |
| 23 | const QUERY_ID = 'quicksearch'; |
Primiano Tucci | 21b91bf | 2018-08-06 16:42:07 +0100 | [diff] [blame] | 24 | |
| 25 | let selResult = 0; |
| 26 | let numResults = 0; |
| 27 | let mode: 'search'|'command' = 'search'; |
| 28 | |
| 29 | function clearOmniboxResults() { |
Primiano Tucci | 8afc06d | 2018-08-06 19:11:42 +0100 | [diff] [blame] | 30 | globals.queryResults.delete(QUERY_ID); |
| 31 | globals.dispatch(deleteQuery(QUERY_ID)); |
Primiano Tucci | 21b91bf | 2018-08-06 16:42:07 +0100 | [diff] [blame] | 32 | } |
| 33 | |
| 34 | function 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 Tucci | 8afc06d | 2018-08-06 19:11:42 +0100 | [diff] [blame] | 44 | const txt = (e.target as HTMLInputElement); |
Primiano Tucci | 21b91bf | 2018-08-06 16:42:07 +0100 | [diff] [blame] | 45 | if (key === ':' && txt.value === '') { |
| 46 | mode = 'command'; |
| 47 | m.redraw(); |
| 48 | e.preventDefault(); |
| 49 | return; |
| 50 | } |
| 51 | if (key === 'Escape' && mode === 'command') { |
| 52 | txt.value = ''; |
| 53 | mode = 'search'; |
| 54 | m.redraw(); |
| 55 | return; |
| 56 | } |
| 57 | if (key === 'Backspace' && txt.value.length === 0 && mode === 'command') { |
| 58 | mode = 'search'; |
| 59 | m.redraw(); |
| 60 | return; |
| 61 | } |
Primiano Tucci | 21b91bf | 2018-08-06 16:42:07 +0100 | [diff] [blame] | 62 | } |
| 63 | |
| 64 | function 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(); |
| 73 | m.redraw(); |
| 74 | return; |
| 75 | } |
| 76 | if (txt.value.length <= 0 || key === 'Escape') { |
| 77 | clearOmniboxResults(); |
| 78 | m.redraw(); |
| 79 | return; |
| 80 | } |
Primiano Tucci | 8afc06d | 2018-08-06 19:11:42 +0100 | [diff] [blame] | 81 | if (mode === 'search') { |
| 82 | const name = txt.value.replace(/'/g, '\\\'').replace(/[*]/g, '%'); |
Hector Dearman | 1232336 | 2018-08-09 16:09:28 +0100 | [diff] [blame] | 83 | const query = `select str from strings where str like '%${name}%' limit 10`; |
Primiano Tucci | 8afc06d | 2018-08-06 19:11:42 +0100 | [diff] [blame] | 84 | globals.dispatch(executeQuery('0', QUERY_ID, query)); |
| 85 | } |
| 86 | if (mode === 'command' && key === 'Enter') { |
| 87 | globals.dispatch(executeQuery('0', 'command', txt.value)); |
| 88 | } |
Primiano Tucci | 21b91bf | 2018-08-06 16:42:07 +0100 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | |
| 92 | const Omnibox: m.Component = { |
| 93 | oncreate(vnode) { |
| 94 | const txt = vnode.dom.querySelector('input') as HTMLInputElement; |
| 95 | txt.addEventListener('blur', clearOmniboxResults); |
| 96 | txt.addEventListener('keydown', onKeyDown); |
| 97 | txt.addEventListener('keyup', onKeyUp); |
| 98 | }, |
| 99 | view() { |
Primiano Tucci | e36ca63 | 2018-08-21 14:32:23 +0200 | [diff] [blame] | 100 | const msgTTL = globals.state.status.timestamp + 3 - Date.now() / 1e3; |
| 101 | let enginesAreBusy = false; |
| 102 | for (const engine of Object.values(globals.state.engines)) { |
| 103 | enginesAreBusy = enginesAreBusy || !engine.ready; |
| 104 | } |
| 105 | |
| 106 | if (msgTTL > 0 || enginesAreBusy) { |
| 107 | setTimeout(() => m.redraw(), msgTTL * 1000); |
| 108 | return m( |
| 109 | `.omnibox.message-mode`, |
| 110 | m(`input[placeholder=${globals.state.status.msg}][readonly]`)); |
| 111 | } |
| 112 | |
Primiano Tucci | 21b91bf | 2018-08-06 16:42:07 +0100 | [diff] [blame] | 113 | // TODO(primiano): handle query results here. |
Primiano Tucci | 8afc06d | 2018-08-06 19:11:42 +0100 | [diff] [blame] | 114 | const results = []; |
| 115 | const resp = globals.queryResults.get(QUERY_ID) as QueryResponse; |
| 116 | if (resp !== undefined) { |
| 117 | numResults = resp.rows ? resp.rows.length : 0; |
| 118 | for (let i = 0; i < resp.rows.length; i++) { |
| 119 | const clazz = (i === selResult) ? '.selected' : ''; |
| 120 | results.push(m(`div${clazz}`, resp.rows[i][resp.columns[0]])); |
| 121 | } |
| 122 | } |
Primiano Tucci | 21b91bf | 2018-08-06 16:42:07 +0100 | [diff] [blame] | 123 | const placeholder = { |
| 124 | search: 'Search or type : to enter command mode', |
| 125 | command: 'e.g., select * from sched left join thread using(utid) limit 10' |
| 126 | }; |
Primiano Tucci | e36ca63 | 2018-08-21 14:32:23 +0200 | [diff] [blame] | 127 | |
Primiano Tucci | 21b91bf | 2018-08-06 16:42:07 +0100 | [diff] [blame] | 128 | const commandMode = mode === 'command'; |
| 129 | return m( |
| 130 | `.omnibox${commandMode ? '.command-mode' : ''}`, |
Primiano Tucci | e36ca63 | 2018-08-21 14:32:23 +0200 | [diff] [blame] | 131 | m(`input[placeholder=${placeholder[mode]}]`), |
Primiano Tucci | 8afc06d | 2018-08-06 19:11:42 +0100 | [diff] [blame] | 132 | m('.omnibox-results', results)); |
Primiano Tucci | 21b91bf | 2018-08-06 16:42:07 +0100 | [diff] [blame] | 133 | }, |
| 134 | }; |
| 135 | |
| 136 | export const Topbar: m.Component = { |
| 137 | view() { |
Primiano Tucci | 8afc06d | 2018-08-06 19:11:42 +0100 | [diff] [blame] | 138 | const progBar = []; |
| 139 | const engine: EngineConfig = globals.state.engines['0']; |
| 140 | if (globals.state.queries[QUERY_ID] !== undefined || |
| 141 | (engine !== undefined && !engine.ready)) { |
| 142 | progBar.push(m('.progress')); |
| 143 | } |
| 144 | |
| 145 | return m('.topbar', m(Omnibox), ...progBar); |
Primiano Tucci | 21b91bf | 2018-08-06 16:42:07 +0100 | [diff] [blame] | 146 | }, |
| 147 | }; |