Home | History | Annotate | Download | only in front-end
      1 /*
      2  * Copyright (C) 2010 Nikita Vasilyev. All rights reserved.
      3  * Copyright (C) 2010 Joseph Pecoraro. All rights reserved.
      4  * Copyright (C) 2010 Google Inc. All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions are
      8  * met:
      9  *
     10  *     * Redistributions of source code must retain the above copyright
     11  * notice, this list of conditions and the following disclaimer.
     12  *     * Redistributions in binary form must reproduce the above
     13  * copyright notice, this list of conditions and the following disclaimer
     14  * in the documentation and/or other materials provided with the
     15  * distribution.
     16  *     * Neither the name of Google Inc. nor the names of its
     17  * contributors may be used to endorse or promote products derived from
     18  * this software without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 WebInspector.CSSCompletions = function(values, acceptEmptyPrefix)
     34 {
     35     this._values = values.slice();
     36     this._values.sort();
     37     this._acceptEmptyPrefix = acceptEmptyPrefix;
     38 }
     39 
     40 WebInspector.CSSCompletions.prototype = {
     41     startsWith: function(prefix)
     42     {
     43         var firstIndex = this._firstIndexOfPrefix(prefix);
     44         if (firstIndex === -1)
     45             return [];
     46 
     47         var results = [];
     48         while (firstIndex < this._values.length && this._values[firstIndex].indexOf(prefix) === 0)
     49             results.push(this._values[firstIndex++]);
     50         return results;
     51     },
     52 
     53     firstStartsWith: function(prefix)
     54     {
     55         var foundIndex = this._firstIndexOfPrefix(prefix);
     56         return (foundIndex === -1 ? "" : this._values[foundIndex]);
     57     },
     58 
     59     _firstIndexOfPrefix: function(prefix)
     60     {
     61         if (!this._values.length)
     62             return -1;
     63         if (!prefix)
     64             return this._acceptEmptyPrefix ? 0 : -1;
     65 
     66         var maxIndex = this._values.length - 1;
     67         var minIndex = 0;
     68         var foundIndex;
     69 
     70         do {
     71             var middleIndex = (maxIndex + minIndex) >> 1;
     72             if (this._values[middleIndex].indexOf(prefix) === 0) {
     73                 foundIndex = middleIndex;
     74                 break;
     75             }
     76             if (this._values[middleIndex] < prefix)
     77                 minIndex = middleIndex + 1;
     78             else
     79                 maxIndex = middleIndex - 1;
     80         } while (minIndex <= maxIndex);
     81 
     82         if (foundIndex === undefined)
     83             return -1;
     84 
     85         while (foundIndex && this._values[foundIndex - 1].indexOf(prefix) === 0)
     86             foundIndex--;
     87 
     88         return foundIndex;
     89     },
     90 
     91     keySet: function()
     92     {
     93         return this._values.keySet();
     94     },
     95 
     96     next: function(str, prefix)
     97     {
     98         return this._closest(str, prefix, 1);
     99     },
    100 
    101     previous: function(str, prefix)
    102     {
    103         return this._closest(str, prefix, -1);
    104     },
    105 
    106     _closest: function(str, prefix, shift)
    107     {
    108         if (!str)
    109             return "";
    110 
    111         var index = this._values.indexOf(str);
    112         if (index === -1)
    113             return "";
    114 
    115         if (!prefix) {
    116             index = (index + this._values.length + shift) % this._values.length;
    117             return this._values[index];
    118         }
    119 
    120         var propertiesWithPrefix = this.startsWith(prefix);
    121         var j = propertiesWithPrefix.indexOf(str);
    122         j = (j + propertiesWithPrefix.length + shift) % propertiesWithPrefix.length;
    123         return propertiesWithPrefix[j];
    124     }
    125 }
    126