Home | History | Annotate | Download | only in front-end
      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