OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. | 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
12 * | 12 * |
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 */ | 24 */ |
25 | |
26 /** | 25 /** |
27 * @constructor | 26 * @unrestricted |
28 * @extends {WebInspector.VBox} | |
29 */ | 27 */ |
30 WebInspector.DatabaseQueryView = function(database) | 28 WebInspector.DatabaseQueryView = class extends WebInspector.VBox { |
31 { | 29 constructor(database) { |
32 WebInspector.VBox.call(this); | 30 super(); |
33 | 31 |
34 this.database = database; | 32 this.database = database; |
35 | 33 |
36 this.element.classList.add("storage-view", "query", "monospace"); | 34 this.element.classList.add('storage-view', 'query', 'monospace'); |
37 this.element.addEventListener("selectstart", this._selectStart.bind(this), f
alse); | 35 this.element.addEventListener('selectstart', this._selectStart.bind(this), f
alse); |
38 | 36 |
39 this._promptElement = createElement("div"); | 37 this._promptElement = createElement('div'); |
40 this._promptElement.className = "database-query-prompt"; | 38 this._promptElement.className = 'database-query-prompt'; |
41 this._promptElement.appendChild(createElement("br")); | 39 this._promptElement.appendChild(createElement('br')); |
42 this._promptElement.addEventListener("keydown", this._promptKeyDown.bind(thi
s), true); | 40 this._promptElement.addEventListener('keydown', this._promptKeyDown.bind(thi
s), true); |
43 this.element.appendChild(this._promptElement); | 41 this.element.appendChild(this._promptElement); |
44 | 42 |
45 this._prompt = new WebInspector.TextPrompt(); | 43 this._prompt = new WebInspector.TextPrompt(); |
46 this._prompt.initialize(this.completions.bind(this), " "); | 44 this._prompt.initialize(this.completions.bind(this), ' '); |
47 this._proxyElement = this._prompt.attach(this._promptElement); | 45 this._proxyElement = this._prompt.attach(this._promptElement); |
48 | 46 |
49 this.element.addEventListener("click", this._messagesClicked.bind(this), tru
e); | 47 this.element.addEventListener('click', this._messagesClicked.bind(this), tru
e); |
| 48 } |
| 49 |
| 50 _messagesClicked() { |
| 51 if (!this._prompt.isCaretInsidePrompt() && this.element.isComponentSelection
Collapsed()) |
| 52 this._prompt.moveCaretToEndOfPrompt(); |
| 53 } |
| 54 |
| 55 /** |
| 56 * @param {!Element} proxyElement |
| 57 * @param {!Range} wordRange |
| 58 * @param {boolean} force |
| 59 * @param {function(!Array.<string>, number=)} completionsReadyCallback |
| 60 */ |
| 61 completions(proxyElement, wordRange, force, completionsReadyCallback) { |
| 62 var prefix = wordRange.toString().toLowerCase(); |
| 63 if (!prefix) |
| 64 return; |
| 65 var results = []; |
| 66 |
| 67 function accumulateMatches(textArray) { |
| 68 for (var i = 0; i < textArray.length; ++i) { |
| 69 var text = textArray[i].toLowerCase(); |
| 70 if (text.length < prefix.length) |
| 71 continue; |
| 72 if (!text.startsWith(prefix)) |
| 73 continue; |
| 74 results.push(textArray[i]); |
| 75 } |
| 76 } |
| 77 |
| 78 function tableNamesCallback(tableNames) { |
| 79 accumulateMatches(tableNames.map(function(name) { |
| 80 return name + ' '; |
| 81 })); |
| 82 accumulateMatches([ |
| 83 'SELECT ', 'FROM ', 'WHERE ', 'LIMIT ', 'DELETE FROM ', 'CREATE ', 'DROP
', 'TABLE ', 'INDEX ', 'UPDATE ', |
| 84 'INSERT INTO ', 'VALUES (' |
| 85 ]); |
| 86 |
| 87 completionsReadyCallback(results); |
| 88 } |
| 89 this.database.getTableNames(tableNamesCallback); |
| 90 } |
| 91 |
| 92 _selectStart(event) { |
| 93 if (this._selectionTimeout) |
| 94 clearTimeout(this._selectionTimeout); |
| 95 |
| 96 this._prompt.clearAutocomplete(); |
| 97 |
| 98 /** |
| 99 * @this {WebInspector.DatabaseQueryView} |
| 100 */ |
| 101 function moveBackIfOutside() { |
| 102 delete this._selectionTimeout; |
| 103 if (!this._prompt.isCaretInsidePrompt() && this.element.isComponentSelecti
onCollapsed()) |
| 104 this._prompt.moveCaretToEndOfPrompt(); |
| 105 this._prompt.autoCompleteSoon(); |
| 106 } |
| 107 |
| 108 this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100); |
| 109 } |
| 110 |
| 111 _promptKeyDown(event) { |
| 112 if (isEnterKey(event)) { |
| 113 this._enterKeyPressed(event); |
| 114 return; |
| 115 } |
| 116 } |
| 117 |
| 118 _enterKeyPressed(event) { |
| 119 event.consume(true); |
| 120 |
| 121 this._prompt.clearAutocomplete(); |
| 122 |
| 123 var query = this._prompt.text(); |
| 124 if (!query.length) |
| 125 return; |
| 126 |
| 127 this._prompt.setText(''); |
| 128 |
| 129 this.database.executeSql(query, this._queryFinished.bind(this, query), this.
_queryError.bind(this, query)); |
| 130 } |
| 131 |
| 132 _queryFinished(query, columnNames, values) { |
| 133 var dataGrid = WebInspector.SortableDataGrid.create(columnNames, values); |
| 134 var trimmedQuery = query.trim(); |
| 135 |
| 136 if (dataGrid) { |
| 137 dataGrid.renderInline(); |
| 138 this._appendViewQueryResult(trimmedQuery, dataGrid.asWidget()); |
| 139 dataGrid.autoSizeColumns(5); |
| 140 } |
| 141 |
| 142 if (trimmedQuery.match(/^create /i) || trimmedQuery.match(/^drop table /i)) |
| 143 this.dispatchEventToListeners(WebInspector.DatabaseQueryView.Events.Schema
Updated, this.database); |
| 144 } |
| 145 |
| 146 _queryError(query, errorMessage) { |
| 147 this._appendErrorQueryResult(query, errorMessage); |
| 148 } |
| 149 |
| 150 /** |
| 151 * @param {string} query |
| 152 * @param {!WebInspector.Widget} view |
| 153 */ |
| 154 _appendViewQueryResult(query, view) { |
| 155 var resultElement = this._appendQueryResult(query); |
| 156 view.show(resultElement); |
| 157 this._promptElement.scrollIntoView(false); |
| 158 } |
| 159 |
| 160 /** |
| 161 * @param {string} query |
| 162 * @param {string} errorText |
| 163 */ |
| 164 _appendErrorQueryResult(query, errorText) { |
| 165 var resultElement = this._appendQueryResult(query); |
| 166 resultElement.classList.add('error'); |
| 167 resultElement.textContent = errorText; |
| 168 |
| 169 this._promptElement.scrollIntoView(false); |
| 170 } |
| 171 |
| 172 _appendQueryResult(query) { |
| 173 var element = createElement('div'); |
| 174 element.className = 'database-user-query'; |
| 175 this.element.insertBefore(element, this._proxyElement); |
| 176 |
| 177 var commandTextElement = createElement('span'); |
| 178 commandTextElement.className = 'database-query-text'; |
| 179 commandTextElement.textContent = query; |
| 180 element.appendChild(commandTextElement); |
| 181 |
| 182 var resultElement = createElement('div'); |
| 183 resultElement.className = 'database-query-result'; |
| 184 element.appendChild(resultElement); |
| 185 return resultElement; |
| 186 } |
50 }; | 187 }; |
51 | 188 |
52 /** @enum {symbol} */ | 189 /** @enum {symbol} */ |
53 WebInspector.DatabaseQueryView.Events = { | 190 WebInspector.DatabaseQueryView.Events = { |
54 SchemaUpdated: Symbol("SchemaUpdated") | 191 SchemaUpdated: Symbol('SchemaUpdated') |
55 }; | 192 }; |
56 | |
57 WebInspector.DatabaseQueryView.prototype = { | |
58 _messagesClicked: function() | |
59 { | |
60 if (!this._prompt.isCaretInsidePrompt() && this.element.isComponentSelec
tionCollapsed()) | |
61 this._prompt.moveCaretToEndOfPrompt(); | |
62 }, | |
63 | |
64 /** | |
65 * @param {!Element} proxyElement | |
66 * @param {!Range} wordRange | |
67 * @param {boolean} force | |
68 * @param {function(!Array.<string>, number=)} completionsReadyCallback | |
69 */ | |
70 completions: function(proxyElement, wordRange, force, completionsReadyCallba
ck) | |
71 { | |
72 var prefix = wordRange.toString().toLowerCase(); | |
73 if (!prefix) | |
74 return; | |
75 var results = []; | |
76 | |
77 function accumulateMatches(textArray) | |
78 { | |
79 for (var i = 0; i < textArray.length; ++i) { | |
80 var text = textArray[i].toLowerCase(); | |
81 if (text.length < prefix.length) | |
82 continue; | |
83 if (!text.startsWith(prefix)) | |
84 continue; | |
85 results.push(textArray[i]); | |
86 } | |
87 } | |
88 | |
89 function tableNamesCallback(tableNames) | |
90 { | |
91 accumulateMatches(tableNames.map(function(name) { return name + " ";
})); | |
92 accumulateMatches(["SELECT ", "FROM ", "WHERE ", "LIMIT ", "DELETE F
ROM ", "CREATE ", "DROP ", "TABLE ", "INDEX ", "UPDATE ", "INSERT INTO ", "VALUE
S ("]); | |
93 | |
94 completionsReadyCallback(results); | |
95 } | |
96 this.database.getTableNames(tableNamesCallback); | |
97 }, | |
98 | |
99 _selectStart: function(event) | |
100 { | |
101 if (this._selectionTimeout) | |
102 clearTimeout(this._selectionTimeout); | |
103 | |
104 this._prompt.clearAutocomplete(); | |
105 | |
106 /** | |
107 * @this {WebInspector.DatabaseQueryView} | |
108 */ | |
109 function moveBackIfOutside() | |
110 { | |
111 delete this._selectionTimeout; | |
112 if (!this._prompt.isCaretInsidePrompt() && this.element.isComponentS
electionCollapsed()) | |
113 this._prompt.moveCaretToEndOfPrompt(); | |
114 this._prompt.autoCompleteSoon(); | |
115 } | |
116 | |
117 this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100); | |
118 }, | |
119 | |
120 _promptKeyDown: function(event) | |
121 { | |
122 if (isEnterKey(event)) { | |
123 this._enterKeyPressed(event); | |
124 return; | |
125 } | |
126 }, | |
127 | |
128 _enterKeyPressed: function(event) | |
129 { | |
130 event.consume(true); | |
131 | |
132 this._prompt.clearAutocomplete(); | |
133 | |
134 var query = this._prompt.text(); | |
135 if (!query.length) | |
136 return; | |
137 | |
138 this._prompt.setText(""); | |
139 | |
140 this.database.executeSql(query, this._queryFinished.bind(this, query), t
his._queryError.bind(this, query)); | |
141 }, | |
142 | |
143 _queryFinished: function(query, columnNames, values) | |
144 { | |
145 var dataGrid = WebInspector.SortableDataGrid.create(columnNames, values)
; | |
146 var trimmedQuery = query.trim(); | |
147 | |
148 if (dataGrid) { | |
149 dataGrid.renderInline(); | |
150 this._appendViewQueryResult(trimmedQuery, dataGrid.asWidget()); | |
151 dataGrid.autoSizeColumns(5); | |
152 } | |
153 | |
154 if (trimmedQuery.match(/^create /i) || trimmedQuery.match(/^drop table /
i)) | |
155 this.dispatchEventToListeners(WebInspector.DatabaseQueryView.Events.
SchemaUpdated, this.database); | |
156 }, | |
157 | |
158 _queryError: function(query, errorMessage) | |
159 { | |
160 this._appendErrorQueryResult(query, errorMessage); | |
161 }, | |
162 | |
163 /** | |
164 * @param {string} query | |
165 * @param {!WebInspector.Widget} view | |
166 */ | |
167 _appendViewQueryResult: function(query, view) | |
168 { | |
169 var resultElement = this._appendQueryResult(query); | |
170 view.show(resultElement); | |
171 this._promptElement.scrollIntoView(false); | |
172 }, | |
173 | |
174 /** | |
175 * @param {string} query | |
176 * @param {string} errorText | |
177 */ | |
178 _appendErrorQueryResult: function(query, errorText) | |
179 { | |
180 var resultElement = this._appendQueryResult(query); | |
181 resultElement.classList.add("error"); | |
182 resultElement.textContent = errorText; | |
183 | |
184 this._promptElement.scrollIntoView(false); | |
185 }, | |
186 | |
187 _appendQueryResult: function(query) | |
188 { | |
189 var element = createElement("div"); | |
190 element.className = "database-user-query"; | |
191 this.element.insertBefore(element, this._proxyElement); | |
192 | |
193 var commandTextElement = createElement("span"); | |
194 commandTextElement.className = "database-query-text"; | |
195 commandTextElement.textContent = query; | |
196 element.appendChild(commandTextElement); | |
197 | |
198 var resultElement = createElement("div"); | |
199 resultElement.className = "database-query-result"; | |
200 element.appendChild(resultElement); | |
201 return resultElement; | |
202 }, | |
203 | |
204 __proto__: WebInspector.VBox.prototype | |
205 }; | |
OLD | NEW |