home *** CD-ROM | disk | FTP | other *** search
/ Computer Active 2010 July / CA07.iso / Multimedija / QuickTimeInstaller.exe / AppleApplicationSupport.msi / WebKit.resources_inspector_TextPrompt.js < prev    next >
Encoding:
Text File  |  2010-03-15  |  10.8 KB  |  320 lines

  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.  *
  8.  * 1.  Redistributions of source code must retain the above copyright
  9.  *     notice, this list of conditions and the following disclaimer.
  10.  * 2.  Redistributions in binary form must reproduce the above copyright
  11.  *     notice, this list of conditions and the following disclaimer in the
  12.  *     documentation and/or other materials provided with the distribution.
  13.  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  14.  *     its contributors may be used to endorse or promote products derived
  15.  *     from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  18.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20.  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  21.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. WebInspector.TextPrompt = function(element, completions, stopCharacters)
  30. {
  31.     this.element = element;
  32.     this.completions = completions;
  33.     this.completionStopCharacters = stopCharacters;
  34.     this.history = [];
  35.     this.historyOffset = 0;
  36. }
  37.  
  38. WebInspector.TextPrompt.prototype = {
  39.     get text()
  40.     {
  41.         return this.element.textContent;
  42.     },
  43.  
  44.     set text(x)
  45.     {
  46.         if (!x) {
  47.             // Append a break element instead of setting textContent to make sure the selection is inside the prompt.
  48.             this.element.removeChildren();
  49.             this.element.appendChild(document.createElement("br"));
  50.         } else
  51.             this.element.textContent = x;
  52.  
  53.         this.moveCaretToEndOfPrompt();
  54.     },
  55.  
  56.     handleKeyEvent: function(event)
  57.     {
  58.         switch (event.keyIdentifier) {
  59.             case "Up":
  60.                 this._upKeyPressed(event);
  61.                 break;
  62.             case "Down":
  63.                 this._downKeyPressed(event);
  64.                 break;
  65.             case "U+0009": // Tab
  66.                 this._tabKeyPressed(event);
  67.                 break;
  68.             case "Right":
  69.                 if (!this.acceptAutoComplete())
  70.                     this.autoCompleteSoon();
  71.                 break;
  72.             default:
  73.                 this.clearAutoComplete();
  74.                 this.autoCompleteSoon();
  75.                 break;
  76.         }
  77.     },
  78.  
  79.     acceptAutoComplete: function()
  80.     {
  81.         if (!this.autoCompleteElement || !this.autoCompleteElement.parentNode)
  82.             return false;
  83.  
  84.         var text = this.autoCompleteElement.textContent;
  85.         var textNode = document.createTextNode(text);
  86.         this.autoCompleteElement.parentNode.replaceChild(textNode, this.autoCompleteElement);
  87.         delete this.autoCompleteElement;
  88.  
  89.         var finalSelectionRange = document.createRange();
  90.         finalSelectionRange.setStart(textNode, text.length);
  91.         finalSelectionRange.setEnd(textNode, text.length);
  92.  
  93.         var selection = window.getSelection();
  94.         selection.removeAllRanges();
  95.         selection.addRange(finalSelectionRange);
  96.  
  97.         return true;
  98.     },
  99.  
  100.     clearAutoComplete: function(includeTimeout)
  101.     {
  102.         if (includeTimeout && "_completeTimeout" in this) {
  103.             clearTimeout(this._completeTimeout);
  104.             delete this._completeTimeout;
  105.         }
  106.  
  107.         if (!this.autoCompleteElement)
  108.             return;
  109.  
  110.         if (this.autoCompleteElement.parentNode)
  111.             this.autoCompleteElement.parentNode.removeChild(this.autoCompleteElement);
  112.         delete this.autoCompleteElement;
  113.  
  114.         if (!this._userEnteredRange || !this._userEnteredText)
  115.             return;
  116.  
  117.         this._userEnteredRange.deleteContents();
  118.  
  119.         var userTextNode = document.createTextNode(this._userEnteredText);
  120.         this._userEnteredRange.insertNode(userTextNode);           
  121.  
  122.         var selectionRange = document.createRange();
  123.         selectionRange.setStart(userTextNode, this._userEnteredText.length);
  124.         selectionRange.setEnd(userTextNode, this._userEnteredText.length);
  125.  
  126.         var selection = window.getSelection();
  127.         selection.removeAllRanges();
  128.         selection.addRange(selectionRange);
  129.  
  130.         delete this._userEnteredRange;
  131.         delete this._userEnteredText;
  132.     },
  133.  
  134.     autoCompleteSoon: function()
  135.     {
  136.         if (!("_completeTimeout" in this))
  137.             this._completeTimeout = setTimeout(this.complete.bind(this, true), 250);
  138.     },
  139.  
  140.     complete: function(auto)
  141.     {
  142.         this.clearAutoComplete(true);
  143.         var selection = window.getSelection();
  144.         if (!selection.rangeCount)
  145.             return;
  146.  
  147.         var selectionRange = selection.getRangeAt(0);
  148.         if (!selectionRange.commonAncestorContainer.isDescendant(this.element))
  149.             return;
  150.         if (auto && !this.isCaretAtEndOfPrompt())
  151.             return;
  152.         var wordPrefixRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, this.completionStopCharacters, this.element, "backward");
  153.         this.completions(wordPrefixRange, auto, this._completionsReady.bind(this, selection, auto, wordPrefixRange));
  154.     },
  155.  
  156.     _completionsReady: function(selection, auto, originalWordPrefixRange, completions)
  157.     {
  158.         if (!completions || !completions.length)
  159.             return;
  160.  
  161.         var selectionRange = selection.getRangeAt(0);
  162.         var wordPrefixRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, this.completionStopCharacters, this.element, "backward");
  163.  
  164.         var fullWordRange = document.createRange();
  165.         fullWordRange.setStart(wordPrefixRange.startContainer, wordPrefixRange.startOffset);
  166.         fullWordRange.setEnd(selectionRange.endContainer, selectionRange.endOffset);
  167.  
  168.         if (originalWordPrefixRange.toString() + selectionRange.toString() != fullWordRange.toString())
  169.             return;
  170.  
  171.         if (completions.length === 1 || selection.isCollapsed || auto) {
  172.             var completionText = completions[0];
  173.         } else {
  174.             var currentText = fullWordRange.toString();
  175.  
  176.             var foundIndex = null;
  177.             for (var i = 0; i < completions.length; ++i) {
  178.                 if (completions[i] === currentText)
  179.                     foundIndex = i;
  180.             }
  181.  
  182.             if (foundIndex === null || (foundIndex + 1) >= completions.length)
  183.                 var completionText = completions[0];
  184.             else
  185.                 var completionText = completions[foundIndex + 1];
  186.         }
  187.  
  188.         var wordPrefixLength = wordPrefixRange.toString().length;
  189.  
  190.         this._userEnteredRange = fullWordRange;
  191.         this._userEnteredText = fullWordRange.toString();
  192.  
  193.         fullWordRange.deleteContents();
  194.  
  195.         var finalSelectionRange = document.createRange();
  196.  
  197.         if (auto) {
  198.             var prefixText = completionText.substring(0, wordPrefixLength);
  199.             var suffixText = completionText.substring(wordPrefixLength);
  200.  
  201.             var prefixTextNode = document.createTextNode(prefixText);
  202.             fullWordRange.insertNode(prefixTextNode);           
  203.  
  204.             this.autoCompleteElement = document.createElement("span");
  205.             this.autoCompleteElement.className = "auto-complete-text";
  206.             this.autoCompleteElement.textContent = suffixText;
  207.  
  208.             prefixTextNode.parentNode.insertBefore(this.autoCompleteElement, prefixTextNode.nextSibling);
  209.  
  210.             finalSelectionRange.setStart(prefixTextNode, wordPrefixLength);
  211.             finalSelectionRange.setEnd(prefixTextNode, wordPrefixLength);
  212.         } else {
  213.             var completionTextNode = document.createTextNode(completionText);
  214.             fullWordRange.insertNode(completionTextNode);           
  215.  
  216.             if (completions.length > 1)
  217.                 finalSelectionRange.setStart(completionTextNode, wordPrefixLength);
  218.             else
  219.                 finalSelectionRange.setStart(completionTextNode, completionText.length);
  220.  
  221.             finalSelectionRange.setEnd(completionTextNode, completionText.length);
  222.         }
  223.  
  224.         selection.removeAllRanges();
  225.         selection.addRange(finalSelectionRange);
  226.     },
  227.  
  228.     isCaretInsidePrompt: function()
  229.     {
  230.         return this.element.isInsertionCaretInside();
  231.     },
  232.  
  233.     isCaretAtEndOfPrompt: function()
  234.     {
  235.         var selection = window.getSelection();
  236.         if (!selection.rangeCount || !selection.isCollapsed)
  237.             return false;
  238.  
  239.         var selectionRange = selection.getRangeAt(0);
  240.         var node = selectionRange.startContainer;
  241.         if (node !== this.element && !node.isDescendant(this.element))
  242.             return false;
  243.  
  244.         if (node.nodeType === Node.TEXT_NODE && selectionRange.startOffset < node.nodeValue.length)
  245.             return false;
  246.  
  247.         var foundNextText = false;
  248.         while (node) {
  249.             if (node.nodeType === Node.TEXT_NODE && node.nodeValue.length) {
  250.                 if (foundNextText)
  251.                     return false;
  252.                 foundNextText = true;
  253.             }
  254.  
  255.             node = node.traverseNextNode(false, this.element);
  256.         }
  257.  
  258.         return true;
  259.     },
  260.  
  261.     moveCaretToEndOfPrompt: function()
  262.     {
  263.         var selection = window.getSelection();
  264.         var selectionRange = document.createRange();
  265.  
  266.         var offset = this.element.childNodes.length;
  267.         selectionRange.setStart(this.element, offset);
  268.         selectionRange.setEnd(this.element, offset);
  269.  
  270.         selection.removeAllRanges();
  271.         selection.addRange(selectionRange);
  272.     },
  273.  
  274.     _tabKeyPressed: function(event)
  275.     {
  276.         event.preventDefault();
  277.         event.stopPropagation();
  278.  
  279.         this.complete();
  280.     },
  281.  
  282.     _upKeyPressed: function(event)
  283.     {
  284.         event.preventDefault();
  285.         event.stopPropagation();
  286.  
  287.         if (this.historyOffset == this.history.length)
  288.             return;
  289.  
  290.         this.clearAutoComplete(true);
  291.  
  292.         if (this.historyOffset == 0)
  293.             this.tempSavedCommand = this.text;
  294.  
  295.         ++this.historyOffset;
  296.         this.text = this.history[this.history.length - this.historyOffset];
  297.     },
  298.  
  299.     _downKeyPressed: function(event)
  300.     {
  301.         event.preventDefault();
  302.         event.stopPropagation();
  303.  
  304.         if (this.historyOffset == 0)
  305.             return;
  306.  
  307.         this.clearAutoComplete(true);
  308.  
  309.         --this.historyOffset;
  310.  
  311.         if (this.historyOffset == 0) {
  312.             this.text = this.tempSavedCommand;
  313.             delete this.tempSavedCommand;
  314.             return;
  315.         }
  316.  
  317.         this.text = this.history[this.history.length - this.historyOffset];
  318.     }
  319. }
  320.