home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / mozil06.zip / bin / chrome / toolkit.jar / content / global / autocomplete.xml < prev    next >
Extensible Markup Language  |  2001-02-14  |  17KB  |  446 lines

  1. <?xml version="1.0"?>
  2.  
  3. <bindings   id="autocompleteBindings"
  4.             xmlns="http://www.mozilla.org/xbl"
  5.             xmlns:html="http://www.w3.org/1999/xhtml"
  6.             xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  7.  
  8. <binding id="autocomplete" extends="chrome://global/content/xulBindings.xml#textfield">
  9.     <content>
  10.         <xul:box class="textfield-internal-box" flex="1">
  11.             <html:input class="textfield-input" flex="1" inherits="onfocus,onblur,value,type,maxlength,disabled,size,readonly"/>
  12.             <xul:popupset ignorekeys="true"
  13.                 oncommand="var me = this.parentNode.parentNode; me.privatefunc.onMenuCommand(me, this);"
  14.             >
  15.                 <xul:popup oncreate="this.parentNode.parentNode.parentNode.menuOpen='true'" ondestroy="this.parentNode.parentNode.parentNode.menuOpen='false';">
  16.                 </xul:popup>
  17.             </xul:popupset>
  18.         </xul:box>
  19.     </content>
  20.  
  21.     <implementation>
  22.         <property name="value"
  23.             onset="
  24.               if (this.ignoreInputEventTimer)
  25.                 clearTimeout(this.ignoreInputEventTimer);
  26.               this.ignoreInputEvent = true;
  27.               this.ignoreInputEventTimer = setTimeout(this.privatefunc.resetInput, 250, this);
  28.               return document.getAnonymousNodes(this)[0].firstChild.value = val;"
  29.             onget="this.privatefunc.cleanupInputField(this); return document.getAnonymousNodes(this)[0].firstChild.value;"
  30.         />
  31.  
  32.         <property name="timeout"
  33.             onset="return this.setAttribute('timeout', val);"
  34.             onget="return this.getAttribute('timeout');"
  35.         />
  36.  
  37.         <property name="displayMenu"
  38.             onset="return this.setAttribute('displayMenu', val);"
  39.             onget="return this.getAttribute('displayMenu');"
  40.         />
  41.  
  42.         <property name="autoCompleteSession">
  43.         <![CDATA[
  44.             if (this.getAttribute('searchSessionType') != "") {
  45.                 var searchSession = unescape('@mozilla%2Eorg%2FautocompleteSession%3B1%3Ftype=');
  46.                 searchSession = searchSession + this.getAttribute('searchSessionType');
  47.                 try {
  48.                     Components.classes[searchSession].getService(Components.interfaces.nsIAutoCompleteSession);
  49. //                      var session = Components.classes[searchSession].createInstance();
  50. //                      session.QueryInterface(Components.interfaces.nsIAutoCompleteSession);
  51.                 } catch (e) {dump("### ERROR, cannot create a search session. " + e + "\n");}
  52.             }
  53.         ]]>
  54.         </property>
  55.         
  56.         <property name="disableAutocomplete"
  57.             onset="return this.setAttribute('disableAutocomplete', val);"
  58.             onget="return this.getAttribute('disableAutocomplete');"
  59.         />
  60.  
  61.         <property name="autoCompleteTimer">
  62.         <![CDATA[
  63.             0;
  64.         ]]>
  65.         </property>
  66.  
  67.         <property name="ignoreInputEventTimer">
  68.         <![CDATA[
  69.             0;
  70.         ]]>
  71.         </property>
  72.  
  73.         <property name="lastResults">
  74.         <![CDATA[
  75.             var results = Components.classes["@mozilla.org/autocomplete/results;1"].createInstance();
  76.             results.QueryInterface(Components.interfaces.nsIAutoCompleteResults);
  77.         ]]>
  78.         </property>
  79.  
  80.        <property name="lastKeyPressed">  <![CDATA[ 0; ]]> </property>
  81.        <property name="noDirectMatch">   <![CDATA[ 0; ]]> </property>
  82.        <property name="menuOpen">        <![CDATA[ 0; ]]> </property>
  83.  
  84.         <property name="autoCompleteListener">
  85.         <![CDATA[
  86.         ({
  87.             onAutoComplete: function(result, status) {
  88.                 var me = this.param;
  89.                 if (status == Components.interfaces.nsIAutoCompleteStatus.failed)
  90.                     return;
  91.                 
  92.                 if (me.disableAutocomplete == "true")
  93.                     return;
  94.  
  95.                 me.lastResults = result;
  96.                 if (status == Components.interfaces.nsIAutoCompleteStatus.ignored || 
  97.                     status == Components.interfaces.nsIAutoCompleteStatus.noMatch)
  98.                     return;
  99.                 
  100.                 if (result == null && result.items.Count() == 0)
  101.                     return;
  102.  
  103.                 if (result.defaultItemIndex > result.items.Count())
  104.                     result.defaultItemIndex = 0;
  105.                 
  106.                /* Do not alter the user input when deleting characters */
  107.                if (me.lastKeyPressed == 8 /*vk_back*/ || me.lastKeyPressed == 46 /*vk_delete*/)
  108.                    result.defaultItemIndex = -1;
  109.  
  110.                 var inputElement = document.getAnonymousNodes(me)[0].firstChild;
  111.                 
  112.                 //Time to build the new edit field value
  113.                 //First, check if the search string correspond to the current value of the field, else ignore it
  114.                 if (result.searchString != inputElement.value)
  115.                     return;
  116.  
  117.                 var item = null;
  118.                 if (result.defaultItemIndex != -1)
  119.                 {
  120.                     item = result.items.QueryElementAt(result.defaultItemIndex, Components.interfaces.nsIAutoCompleteItem);
  121.                     var match = item.value.toLowerCase();
  122.                     var entry = inputElement.value.toLowerCase();
  123.                     if (entry != match)
  124.                     {
  125.             me.ignoreInputEvent = true;
  126.                         if (match.substring(0, entry.length) == entry)
  127.                         {
  128.                             inputElement.value = inputElement.value + item.value.substring(entry.length, match.length);
  129.                             inputElement.setSelectionRange(entry.length, match.length);
  130.                             me.noDirectMatch = false;
  131.                         }
  132.                         else
  133.                         {
  134.                             inputElement.value = inputElement.value + " >> " + item.value;
  135.                             inputElement.setSelectionRange(entry.length, inputElement.value.length);
  136.                             me.noDirectMatch = true;
  137.                         }
  138.             me.ignoreInputEvent = false;
  139.                     }
  140.                 }
  141.                 
  142.                 //Now, build the popup content
  143.                 if (me.displayMenu == "false")
  144.                     return;
  145.  
  146.                 var popupset = document.getAnonymousNodes(me)[0].childNodes[1];
  147.                 var popupElement = popupset.firstChild;
  148.                 
  149.                 //First, remove all the current menu items
  150.                 for (i = popupElement.childNodes.length - 1; i >= 0 ; i --)
  151.                   popupElement.removeChild(popupElement.childNodes[i]);
  152.  
  153.                 //Then build the new menu items
  154.                 for (var i = 0; i < result.items.Count(); i ++)
  155.                 {
  156.                     item = result.items.QueryElementAt(i, Components.interfaces.nsIAutoCompleteItem);
  157.                     var menuitem = document.createElement("menuitem");
  158.                     menuitem.setAttribute('data', i);
  159.                     menuitem.setAttribute('value', item.value);
  160.                     popupElement.appendChild(menuitem);
  161. //                    dump("  match=" + item.value + "\n");
  162.                 }
  163. //                dump("  count=" + result.items.Count() + ", default=" + result.defaultItemIndex + "\n");
  164.                 
  165.                 me.privatefunc.selectedItemIndex = result.defaultItemIndex;
  166.                 if (result.defaultItemIndex != 0 || result.items.Count() != 1)
  167.                 {
  168. //                    me.privatefunc.closePopupMenu(me); //Close it first as openPopup seems to work as a toggle!
  169.                     popupset.firstChild.openPopup(document.getAnonymousNodes(me)[0].firstChild, -1, -1, "popup", "bottomleft", "topleft");
  170.                   
  171.           if (result.defaultItemIndex != -1)
  172.                     popupElement.activeChild = popupElement.childNodes[result.defaultItemIndex];
  173.         }
  174.             },
  175.  
  176.             param: this
  177.         })
  178.         ]]>
  179.         </property>
  180.  
  181.         <property name="privatefunc">
  182.         <![CDATA[
  183.         ({
  184.  
  185.             onMenuCommand: function(me, popupSetElem) {
  186.                 var inputElement = document.getAnonymousNodes(me)[0].firstChild;
  187.                 var popupElem = popupSetElem.firstChild;
  188.  
  189.                 me.ignoreInputEvent = true;
  190.  
  191.                 inputElement.value = popupElem.activeChild.getAttribute("value");
  192.                 inputElement.setSelectionRange(inputElement.value.length, inputElement.value.length);
  193.  
  194.                 needToAutocomplete = false;
  195.                 me.privatefunc.selectedItemIndex = popupElem.activeChild.getAttribute("data");
  196.  
  197.                 me.ignoreInputEvent = false;
  198.  
  199.                 return;
  200.             },
  201.  
  202.             callListener: function(me, action) {
  203.                 switch (action) {
  204.                     case 'startLookup':
  205.                         if (me.disableAutocomplete == "true")
  206.                             return;
  207.                         inputElement = document.getAnonymousNodes(me)[0].firstChild;
  208.                         if (!me.lastResults || inputElement.value != me.lastResults.searchString)
  209.                             me.autoCompleteSession.onStartLookup(inputElement.value, me.lastResults, me.autoCompleteListener);
  210.                         break;
  211.  
  212.                     case 'stopLookup':
  213.                         me.autoCompleteSession.onStopLookup();
  214.                         break;
  215.  
  216.                     case 'autoComplete':
  217.                         if (me.autoCompleteTimer) {
  218.                             clearTimeout(me.autoCompleteTimer);
  219.                             me.autoCompleteTimer = 0;
  220.                         }
  221.                         me.needToAutocomplete = false;
  222.                         if (this.disableAutocomplete == "true")
  223.                             return;
  224.                                     var inputElement = document.getAnonymousNodes(me)[0].firstChild;
  225.                         me.autoCompleteSession.onAutoComplete(inputElement.value, me.lastResults, me.autoCompleteListener);
  226.                         break;
  227.                 }
  228.             },
  229.  
  230.             finishAutoComplete: function(me, event) {
  231.                        me.privatefunc.closePopupMenu(me);
  232.                 if (me.disableAutocomplete == "true")
  233.                     return;
  234.  
  235.                 var inputElement = document.getAnonymousNodes(me)[0].firstChild;
  236.                         var value = inputElement.value;
  237.                 var entry = value.substring(0, inputElement.selectionStart) + value.substring(inputElement.selectionEnd, value.length);
  238.  
  239.                 if (me.lastResults)
  240.                 {
  241.                     if (me.lastResults.searchString == entry)
  242.                     {
  243.                         me.ignoreInputEvent = true;
  244.                         try {
  245.                             inputElement.value = me.lastResults.items.QueryElementAt(me.lastResults.defaultItemIndex, Components.interfaces.nsIAutoCompleteItem).value;
  246.                         } catch(e) {};
  247.                         inputElement.setSelectionRange(inputElement.value.length, inputElement.value.length);
  248.                         me.ignoreInputEvent = false;
  249.                         return;
  250.                     }
  251.                 }
  252.                 
  253.                 me.privatefunc.callListener(me, 'autoComplete');
  254.             },
  255.  
  256.             closePopupMenu: function(me) {
  257.                 var popup = document.getAnonymousNodes(me)[0].childNodes[1].firstChild;
  258.                 if (popup && me.menuOpen == "true")
  259.                     popup.closePopup();
  260.             },
  261.  
  262.             cleanupInputField: function(me) {
  263.                 if (me.noDirectMatch)
  264.                 {
  265.                     var inputElement = document.getAnonymousNodes(me)[0].firstChild;
  266.                     var value = inputElement.value;
  267.                     var index = value.indexOf(">> ");
  268.                     if (index >= 0)
  269.                     {
  270.             me.ignoreInputEvent = true;
  271.                         inputElement.value = value.substr(index + 3);
  272.                         inputElement.setSelectionRange(inputElement.value.length, inputElement.value.length);
  273.             me.ignoreInputEvent = false;
  274.                     }
  275.                 }
  276.             },
  277.  
  278.             keyNavigation: function(me, event, popup) {
  279.         if (me.lastResults == null)
  280.           return;
  281.  
  282.                 var inputElement = document.getAnonymousNodes(me)[0].firstChild;
  283.                 if (event.keyCode == 38 || event.keyCode == 40)
  284.                 {
  285.                     if (event.keyCode == 38)
  286.                     {
  287.                         if (me.privatefunc.selectedItemIndex <= -1)
  288.                             me.privatefunc.selectedItemIndex = me.lastResults.items.Count() - 1;
  289.                         else
  290.                             me.privatefunc.selectedItemIndex --;
  291.                     }
  292.                     else
  293.                     {
  294.                         me.privatefunc.selectedItemIndex ++;
  295.                         if (me.privatefunc.selectedItemIndex >= me.lastResults.items.Count())
  296.                             me.privatefunc.selectedItemIndex = -1
  297.                     }
  298.  
  299.           me.ignoreInputEvent = true;
  300.                     if (me.privatefunc.selectedItemIndex == -1)
  301.                         inputElement.value = me.lastResults.searchString;
  302.                     else
  303.                         inputElement.value = me.lastResults.items.QueryElementAt(me.privatefunc.selectedItemIndex, Components.interfaces.nsIAutoCompleteItem).value;
  304.                     inputElement.setSelectionRange(inputElement.value.length, inputElement.value.length);
  305.                     noDirectMatch = false;
  306.                     needToAutocomplete = false;
  307.           me.ignoreInputEvent = false;
  308.  
  309.                     if (popup)
  310.                     {
  311.             if (me.privatefunc.selectedItemIndex >= 0)
  312.               popup.activeChild = popup.childNodes[me.privatefunc.selectedItemIndex];
  313.             else
  314.               popup.activeChild = null;
  315.                     }
  316.                     return;
  317.                 }
  318.             },
  319.  
  320.       resetInput: function(me) {
  321.         me.ignoreInputEventTimer = null;
  322.         me.ignoreInputEvent = false;
  323.       },
  324.       
  325.            processInput: function(me) {
  326.                 //Stop current lookup in case it's async.
  327.                 me.privatefunc.callListener(me, 'stopLookup');
  328.                 if (me.autoCompleteTimer) {
  329.                     clearTimeout(me.autoCompleteTimer);
  330.                     me.autoCompleteTimer = 0;
  331.                 }
  332.  
  333.              if (me.ignoreInputEvent)
  334.                return;
  335.              
  336.         me.privatefunc.closePopupMenu(me);
  337.         me.lastKeyPressed = 0;
  338.  
  339.                 if (me.disableAutocomplete == "true")
  340.                     return;
  341.  
  342.                 /*We want to autocomplete only if the user is editing at the end of the text */
  343.                 var inputElement = document.getAnonymousNodes(me)[0].firstChild;
  344.                 if (inputElement.selectionEnd >= inputElement.value.length)
  345.                 {
  346.                     me.needToAutocomplete = true;
  347.                     me.autoCompleteTimer = setTimeout(me.privatefunc.callListener, me.timeout, me, 'startLookup');
  348.                 }
  349.             },
  350.  
  351.             processKeyPress: function(me, event) {
  352.                 if (me.disableAutocomplete == "true")
  353.                 {
  354.           me.privatefunc.closePopupMenu(me);
  355.                     return;
  356.                 }
  357.  
  358.                 var popup = document.getAnonymousNodes(me)[0].childNodes[1].firstChild;
  359.                  if (popup && me.menuOpen != "true")
  360.                     popup = null;
  361.  
  362.         me.lastKeyPressed = event.keyCode;
  363.                  switch (event.keyCode)
  364.                 {
  365.           case 9: /*vk_tab*/
  366.                         if (popup)
  367.               me.privatefunc.closePopupMenu(me);
  368.             return;
  369.  
  370.                     case 13 /*vk_return*/:
  371.                     if (me.autoCompleteTimer) {
  372.                         clearTimeout(me.autoCompleteTimer);
  373.                         me.autoCompleteTimer = 0;
  374.                     }
  375.                         me.privatefunc.closePopupMenu(me);
  376.                         me.privatefunc.finishAutoComplete(me, event);
  377.                         return;
  378.  
  379.                     case 27 /*vk_escape*/:
  380.                     if (me.autoCompleteTimer) {
  381.                         clearTimeout(me.autoCompleteTimer);
  382.                         me.autoCompleteTimer = 0;
  383.                     }
  384.                         if (popup) {
  385.                             me.privatefunc.closePopupMenu(me);
  386.                             event.preventDefault();
  387.                             event.preventBubble();
  388.                             return;
  389.                         }
  390.                         break;
  391.  
  392.                     case 37 /*vk_left*/:
  393.                     case 39 /*vk_right*/:
  394.                     if (me.autoCompleteTimer) {
  395.                         clearTimeout(me.autoCompleteTimer);
  396.                         me.autoCompleteTimer = 0;
  397.                     }
  398.                         if (popup)
  399.                         {
  400.                             me.privatefunc.closePopupMenu(me);
  401.                             event.preventDefault();
  402.                             event.preventBubble();
  403.                         }
  404.                         me.privatefunc.cleanupInputField(me);
  405.                         break;
  406.  
  407.                     case 38 /*vk_up*/:
  408.                     case 40 /*vk_down*/:
  409.                     if (me.autoCompleteTimer) {
  410.                         clearTimeout(me.autoCompleteTimer);
  411.                         me.autoCompleteTimer = 0;
  412.                     }
  413.                         me.privatefunc.keyNavigation(me, event, popup);
  414.                         event.preventDefault();
  415.                         event.preventBubble();
  416.             if (! popup)
  417.                           me.privatefunc.cleanupInputField(me);
  418.                         break;
  419.                 }
  420.             },
  421.  
  422.             selectedItemIndex: 0
  423.  
  424.         })
  425.         ]]>
  426.         </property>
  427.         
  428.     </implementation>
  429.  
  430.     <handlers>
  431.         <handler event="click" action="this.privatefunc.cleanupInputField(this);"/>
  432.         <handler event="dblclick" action="this.privatefunc.cleanupInputField(this);"/>
  433.         <handler event="input" action="this.privatefunc.processInput(this);"/>
  434.         <handler event="keypress" action="this.privatefunc.processKeyPress(this, event);"/>
  435.         <handler event="focus" action="this.needToAutocomplete = false; this.lastResults.searchString=''; this.ignoreInputEvent = false"/>
  436.         <handler event="blur" action="
  437.                   this.privatefunc.closePopupMenu(this);
  438.             if (this.needToAutocomplete)
  439.                 this.privatefunc.finishAutoComplete(this, event);
  440.                   this.privatefunc.cleanupInputField(this);
  441.             "/>
  442.     </handlers>
  443.  
  444. </binding> 
  445. </bindings> 
  446.