DatabaseQueryView.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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. * @constructor
  27. * @extends {WebInspector.View}
  28. */
  29. WebInspector.DatabaseQueryView = function(database)
  30. {
  31. WebInspector.View.call(this);
  32. this.database = database;
  33. this.element.addStyleClass("storage-view");
  34. this.element.addStyleClass("query");
  35. this.element.addStyleClass("monospace");
  36. this.element.addEventListener("selectstart", this._selectStart.bind(this), false);
  37. this._promptElement = document.createElement("div");
  38. this._promptElement.className = "database-query-prompt";
  39. this._promptElement.appendChild(document.createElement("br"));
  40. this._promptElement.addEventListener("keydown", this._promptKeyDown.bind(this), true);
  41. this.element.appendChild(this._promptElement);
  42. this.prompt = new WebInspector.TextPromptWithHistory(this.completions.bind(this), " ");
  43. this.prompt.attach(this._promptElement);
  44. this.element.addEventListener("click", this._messagesClicked.bind(this), true);
  45. }
  46. WebInspector.DatabaseQueryView.Events = {
  47. SchemaUpdated: "SchemaUpdated"
  48. }
  49. WebInspector.DatabaseQueryView.prototype = {
  50. _messagesClicked: function()
  51. {
  52. if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed)
  53. this.prompt.moveCaretToEndOfPrompt();
  54. },
  55. /**
  56. * @param {Element} proxyElement
  57. * @param {Range} wordRange
  58. * @param {boolean} force
  59. * @param {function(!Array.<string>, number=)} completionsReadyCallback
  60. */
  61. completions: function(proxyElement, wordRange, force, completionsReadyCallback)
  62. {
  63. var prefix = wordRange.toString().toLowerCase();
  64. if (!prefix)
  65. return;
  66. var results = [];
  67. function accumulateMatches(textArray)
  68. {
  69. for (var i = 0; i < textArray.length; ++i) {
  70. var text = textArray[i].toLowerCase();
  71. if (text.length < prefix.length)
  72. continue;
  73. if (!text.startsWith(prefix))
  74. continue;
  75. results.push(textArray[i]);
  76. }
  77. }
  78. function tableNamesCallback(tableNames)
  79. {
  80. accumulateMatches(tableNames.map(function(name) { return name + " " }));
  81. accumulateMatches(["SELECT ", "FROM ", "WHERE ", "LIMIT ", "DELETE FROM ", "CREATE ", "DROP ", "TABLE ", "INDEX ", "UPDATE ", "INSERT INTO ", "VALUES ("]);
  82. completionsReadyCallback(results);
  83. }
  84. this.database.getTableNames(tableNamesCallback);
  85. },
  86. _selectStart: function(event)
  87. {
  88. if (this._selectionTimeout)
  89. clearTimeout(this._selectionTimeout);
  90. this.prompt.clearAutoComplete();
  91. function moveBackIfOutside()
  92. {
  93. delete this._selectionTimeout;
  94. if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed)
  95. this.prompt.moveCaretToEndOfPrompt();
  96. this.prompt.autoCompleteSoon();
  97. }
  98. this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100);
  99. },
  100. _promptKeyDown: function(event)
  101. {
  102. if (isEnterKey(event)) {
  103. this._enterKeyPressed(event);
  104. return;
  105. }
  106. },
  107. _enterKeyPressed: function(event)
  108. {
  109. event.consume(true);
  110. this.prompt.clearAutoComplete(true);
  111. var query = this.prompt.text;
  112. if (!query.length)
  113. return;
  114. this.prompt.pushHistoryItem(query);
  115. this.prompt.text = "";
  116. this.database.executeSql(query, this._queryFinished.bind(this, query), this._queryError.bind(this, query));
  117. },
  118. _queryFinished: function(query, columnNames, values)
  119. {
  120. var dataGrid = WebInspector.DataGrid.createSortableDataGrid(columnNames, values);
  121. var trimmedQuery = query.trim();
  122. if (dataGrid) {
  123. dataGrid.renderInline();
  124. this._appendViewQueryResult(trimmedQuery, dataGrid);
  125. dataGrid.autoSizeColumns(5);
  126. }
  127. if (trimmedQuery.match(/^create /i) || trimmedQuery.match(/^drop table /i))
  128. this.dispatchEventToListeners(WebInspector.DatabaseQueryView.Events.SchemaUpdated, this.database);
  129. },
  130. _queryError: function(query, errorMessage)
  131. {
  132. this._appendErrorQueryResult(query, errorMessage);
  133. },
  134. /**
  135. * @param {string} query
  136. * @param {WebInspector.View} view
  137. */
  138. _appendViewQueryResult: function(query, view)
  139. {
  140. var resultElement = this._appendQueryResult(query);
  141. view.show(resultElement);
  142. this._promptElement.scrollIntoView(false);
  143. },
  144. /**
  145. * @param {string} query
  146. * @param {string} errorText
  147. */
  148. _appendErrorQueryResult: function(query, errorText)
  149. {
  150. var resultElement = this._appendQueryResult(query);
  151. resultElement.addStyleClass("error")
  152. resultElement.textContent = errorText;
  153. this._promptElement.scrollIntoView(false);
  154. },
  155. _appendQueryResult: function(query)
  156. {
  157. var element = document.createElement("div");
  158. element.className = "database-user-query";
  159. this.element.insertBefore(element, this.prompt.proxyElement);
  160. var commandTextElement = document.createElement("span");
  161. commandTextElement.className = "database-query-text";
  162. commandTextElement.textContent = query;
  163. element.appendChild(commandTextElement);
  164. var resultElement = document.createElement("div");
  165. resultElement.className = "database-query-result";
  166. element.appendChild(resultElement);
  167. return resultElement;
  168. },
  169. __proto__: WebInspector.View.prototype
  170. }