| 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 |