1 /* 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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. 24 */ 25 26 WebInspector.DatabaseQueryView = function(database) 27 { 28 WebInspector.View.call(this); 29 30 this.database = database; 31 32 this.element.addStyleClass("storage-view"); 33 this.element.addStyleClass("query"); 34 this.element.addStyleClass("monospace"); 35 this.element.tabIndex = 0; 36 37 this.element.addEventListener("selectstart", this._selectStart.bind(this), false); 38 39 this.promptElement = document.createElement("div"); 40 this.promptElement.className = "database-query-prompt"; 41 this.promptElement.appendChild(document.createElement("br")); 42 this.promptElement.addEventListener("keydown", this._promptKeyDown.bind(this), true); 43 this.element.appendChild(this.promptElement); 44 45 this.prompt = new WebInspector.TextPrompt(this.promptElement, this.completions.bind(this), " "); 46 } 47 48 WebInspector.DatabaseQueryView.prototype = { 49 show: function(parentElement) 50 { 51 WebInspector.View.prototype.show.call(this, parentElement); 52 53 function moveBackIfOutside() 54 { 55 if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed) 56 this.prompt.moveCaretToEndOfPrompt(); 57 } 58 59 setTimeout(moveBackIfOutside.bind(this), 0); 60 }, 61 62 completions: function(wordRange, bestMatchOnly, completionsReadyCallback) 63 { 64 var prefix = wordRange.toString().toLowerCase(); 65 if (!prefix.length) 66 return; 67 68 var results = []; 69 70 function accumulateMatches(textArray) 71 { 72 if (bestMatchOnly && results.length) 73 return; 74 for (var i = 0; i < textArray.length; ++i) { 75 var text = textArray[i].toLowerCase(); 76 if (text.length < prefix.length) 77 continue; 78 if (text.indexOf(prefix) !== 0) 79 continue; 80 results.push(textArray[i]); 81 if (bestMatchOnly) 82 return; 83 } 84 } 85 86 function tableNamesCallback(tableNames) 87 { 88 accumulateMatches(tableNames.map(function(name) { return name + " " })); 89 accumulateMatches(["SELECT ", "FROM ", "WHERE ", "LIMIT ", "DELETE FROM ", "CREATE ", "DROP ", "TABLE ", "INDEX ", "UPDATE ", "INSERT INTO ", "VALUES ("]); 90 91 completionsReadyCallback(results); 92 } 93 this.database.getTableNames(tableNamesCallback); 94 }, 95 96 _promptKeyDown: function(event) 97 { 98 if (isEnterKey(event)) { 99 this._enterKeyPressed(event); 100 return; 101 } 102 }, 103 104 _selectStart: function(event) 105 { 106 if (this._selectionTimeout) 107 clearTimeout(this._selectionTimeout); 108 109 this.prompt.clearAutoComplete(); 110 111 function moveBackIfOutside() 112 { 113 delete this._selectionTimeout; 114 if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed) 115 this.prompt.moveCaretToEndOfPrompt(); 116 this.prompt.autoCompleteSoon(); 117 } 118 119 this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100); 120 }, 121 122 _enterKeyPressed: function(event) 123 { 124 event.preventDefault(); 125 event.stopPropagation(); 126 127 this.prompt.clearAutoComplete(true); 128 129 var query = this.prompt.text; 130 if (!query.length) 131 return; 132 133 this.prompt.history.push(query); 134 this.prompt.historyOffset = 0; 135 this.prompt.text = ""; 136 137 this.database.executeSql(query, this._queryFinished.bind(this, query), this._queryError.bind(this, query)); 138 }, 139 140 _queryFinished: function(query, columnNames, values) 141 { 142 var dataGrid = WebInspector.panels.resources.dataGridForResult(columnNames, values); 143 var trimmedQuery = query.trim(); 144 145 if (dataGrid) { 146 dataGrid.element.addStyleClass("inline"); 147 this._appendQueryResult(trimmedQuery, dataGrid.element); 148 dataGrid.autoSizeColumns(5); 149 } 150 151 if (trimmedQuery.match(/^create /i) || trimmedQuery.match(/^drop table /i)) 152 WebInspector.panels.resources.updateDatabaseTables(this.database); 153 }, 154 155 _queryError: function(query, error) 156 { 157 if (error.message) 158 var message = error.message; 159 else if (error.code == 2) 160 var message = WebInspector.UIString("Database no longer has expected version."); 161 else 162 var message = WebInspector.UIString("An unexpected error %s occurred.", error.code); 163 164 this._appendQueryResult(query, message, "error"); 165 }, 166 167 _appendQueryResult: function(query, result, resultClassName) 168 { 169 var element = document.createElement("div"); 170 element.className = "database-user-query"; 171 172 var commandTextElement = document.createElement("span"); 173 commandTextElement.className = "database-query-text"; 174 commandTextElement.textContent = query; 175 element.appendChild(commandTextElement); 176 177 var resultElement = document.createElement("div"); 178 resultElement.className = "database-query-result"; 179 180 if (resultClassName) 181 resultElement.addStyleClass(resultClassName); 182 183 if (typeof result === "string" || result instanceof String) 184 resultElement.textContent = result; 185 else if (result && result.nodeName) 186 resultElement.appendChild(result); 187 188 if (resultElement.childNodes.length) 189 element.appendChild(resultElement); 190 191 this.element.insertBefore(element, this.promptElement); 192 this.promptElement.scrollIntoView(false); 193 } 194 } 195 196 WebInspector.DatabaseQueryView.prototype.__proto__ = WebInspector.View.prototype; 197