home *** CD-ROM | disk | FTP | other *** search
/ PC World 2000 December / PCWorld_2000-12_cd.bin / Komunikace / mozilla / mozilla-win32-M18-mathml-svg-xslt.exe / chrome / toolkit / content / global / autocomplete.xml < prev    next >
Extensible Markup Language  |  2000-10-04  |  17KB  |  449 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.                 for (var i = 0; i < popupElem.childNodes.length; i ++)
  189.                 {
  190.                     var menuitem = popupElem.childNodes[i];
  191.                     if (menuitem.getAttribute("menuactive") == "true")
  192.                     {
  193.             me.ignoreInputEvent = true;
  194.                         inputElement.value = menuitem.getAttribute("value");
  195.                         inputElement = document.getAnonymousNodes(me)[0].firstChild;
  196.                         inputElement.setSelectionRange(inputElement.value.length, inputElement.value.length);
  197.                         needToAutocomplete = false;
  198.                         me.privatefunc.selectedItemIndex = i;
  199.             me.ignoreInputEvent = false;
  200.                         return;
  201.                     }
  202.                 }
  203.             },
  204.  
  205.             callListener: function(me, action) {
  206.                 switch (action) {
  207.                     case 'startLookup':
  208.                         if (me.disableAutocomplete == "true")
  209.                             return;
  210.                         inputElement = document.getAnonymousNodes(me)[0].firstChild;
  211.                         if (!me.lastResults || inputElement.value != me.lastResults.searchString)
  212.                             me.autoCompleteSession.onStartLookup(inputElement.value, me.lastResults, me.autoCompleteListener);
  213.                         break;
  214.  
  215.                     case 'stopLookup':
  216.                         me.autoCompleteSession.onStopLookup();
  217.                         break;
  218.  
  219.                     case 'autoComplete':
  220.                         if (me.autoCompleteTimer) {
  221.                             clearTimeout(me.autoCompleteTimer);
  222.                             me.autoCompleteTimer = 0;
  223.                         }
  224.                         me.needToAutocomplete = false;
  225.                         if (this.disableAutocomplete == "true")
  226.                             return;
  227.                                     var inputElement = document.getAnonymousNodes(me)[0].firstChild;
  228.                         me.autoCompleteSession.onAutoComplete(inputElement.value, me.lastResults, me.autoCompleteListener);
  229.                         break;
  230.                 }
  231.             },
  232.  
  233.             finishAutoComplete: function(me, event) {
  234.                        me.privatefunc.closePopupMenu(me);
  235.                 if (me.disableAutocomplete == "true")
  236.                     return;
  237.  
  238.                 var inputElement = document.getAnonymousNodes(me)[0].firstChild;
  239.                         var value = inputElement.value;
  240.                 var entry = value.substring(0, inputElement.selectionStart) + value.substring(inputElement.selectionEnd, value.length);
  241.  
  242.                 if (me.lastResults)
  243.                 {
  244.                     if (me.lastResults.searchString == entry)
  245.                     {
  246.                         me.ignoreInputEvent = true;
  247.                         try {
  248.                             inputElement.value = me.lastResults.items.QueryElementAt(me.lastResults.defaultItemIndex, Components.interfaces.nsIAutoCompleteItem).value;
  249.                         } catch(e) {};
  250.                         inputElement.setSelectionRange(inputElement.value.length, inputElement.value.length);
  251.                         me.ignoreInputEvent = false;
  252.                         return;
  253.                     }
  254.                 }
  255.                 
  256.                 me.privatefunc.callListener(me, 'autoComplete');
  257.             },
  258.  
  259.             closePopupMenu: function(me) {
  260.                 var popup = document.getAnonymousNodes(me)[0].childNodes[1].firstChild;
  261.                 if (popup && me.menuOpen == "true")
  262.                     popup.closePopup();
  263.             },
  264.  
  265.             cleanupInputField: function(me) {
  266.                 if (me.noDirectMatch)
  267.                 {
  268.                     var inputElement = document.getAnonymousNodes(me)[0].firstChild;
  269.                     var value = inputElement.value;
  270.                     var index = value.indexOf(">> ");
  271.                     if (index >= 0)
  272.                     {
  273.             me.ignoreInputEvent = true;
  274.                         inputElement.value = value.substr(index + 3);
  275.                         inputElement.setSelectionRange(inputElement.value.length, inputElement.value.length);
  276.             me.ignoreInputEvent = false;
  277.                     }
  278.                 }
  279.             },
  280.  
  281.             keyNavigation: function(me, event, popup) {
  282.         if (me.lastResults == null)
  283.           return;
  284.  
  285.                 var inputElement = document.getAnonymousNodes(me)[0].firstChild;
  286.                 if (event.keyCode == 38 || event.keyCode == 40)
  287.                 {
  288.                     if (event.keyCode == 38)
  289.                     {
  290.                         if (me.privatefunc.selectedItemIndex <= -1)
  291.                             me.privatefunc.selectedItemIndex = me.lastResults.items.Count() - 1;
  292.                         else
  293.                             me.privatefunc.selectedItemIndex --;
  294.                     }
  295.                     else
  296.                     {
  297.                         me.privatefunc.selectedItemIndex ++;
  298.                         if (me.privatefunc.selectedItemIndex >= me.lastResults.items.Count())
  299.                             me.privatefunc.selectedItemIndex = -1
  300.                     }
  301.  
  302.           me.ignoreInputEvent = true;
  303.                     if (me.privatefunc.selectedItemIndex == -1)
  304.                         inputElement.value = me.lastResults.searchString;
  305.                     else
  306.                         inputElement.value = me.lastResults.items.QueryElementAt(me.privatefunc.selectedItemIndex, Components.interfaces.nsIAutoCompleteItem).value;
  307.                     inputElement.setSelectionRange(inputElement.value.length, inputElement.value.length);
  308.                     noDirectMatch = false;
  309.                     needToAutocomplete = false;
  310.           me.ignoreInputEvent = false;
  311.  
  312.                     if (popup)
  313.                     {
  314.             if (me.privatefunc.selectedItemIndex >= 0)
  315.               popup.activeChild = popup.childNodes[me.privatefunc.selectedItemIndex];
  316.             else
  317.               popup.activeChild = null;
  318.                     }
  319.                     return;
  320.                 }
  321.             },
  322.  
  323.       resetInput: function(me) {
  324.         me.ignoreInputEventTimer = null;
  325.         me.ignoreInputEvent = false;
  326.       },
  327.       
  328.            processInput: function(me) {
  329.                 //Stop current lookup in case it's async.
  330.                 me.privatefunc.callListener(me, 'stopLookup');
  331.                 if (me.autoCompleteTimer) {
  332.                     clearTimeout(me.autoCompleteTimer);
  333.                     me.autoCompleteTimer = 0;
  334.                 }
  335.  
  336.              if (me.ignoreInputEvent)
  337.                return;
  338.              
  339.         me.privatefunc.closePopupMenu(me);
  340.         me.lastKeyPressed = 0;
  341.  
  342.                 if (me.disableAutocomplete == "true")
  343.                     return;
  344.  
  345.                 /*We want to autocomplete only if the user is editing at the end of the text */
  346.                 var inputElement = document.getAnonymousNodes(me)[0].firstChild;
  347.                 if (inputElement.selectionEnd >= inputElement.value.length)
  348.                 {
  349.                     me.needToAutocomplete = true;
  350.                     me.autoCompleteTimer = setTimeout(me.privatefunc.callListener, me.timeout, me, 'startLookup');
  351.                 }
  352.             },
  353.  
  354.             processKeyPress: function(me, event) {
  355.                 if (me.disableAutocomplete == "true")
  356.                 {
  357.           me.privatefunc.closePopupMenu(me);
  358.                     return;
  359.                 }
  360.  
  361.                 var popup = document.getAnonymousNodes(me)[0].childNodes[1].firstChild;
  362.                  if (popup && me.menuOpen != "true")
  363.                     popup = null;
  364.  
  365.         me.lastKeyPressed = event.keyCode;
  366.                 switch (event.keyCode)
  367.                 {
  368.           case 9: /*vk_tab*/
  369.                         if (popup)
  370.               me.privatefunc.closePopupMenu(me);
  371.             return;
  372.  
  373.                     case 13 /*vk_return*/:
  374.                     if (me.autoCompleteTimer) {
  375.                         clearTimeout(me.autoCompleteTimer);
  376.                         me.autoCompleteTimer = 0;
  377.                     }
  378.                         me.privatefunc.closePopupMenu(me);
  379.                         me.privatefunc.finishAutoComplete(me, event);
  380.                         return;
  381.  
  382.                     case 27 /*vk_escape*/:
  383.                     if (me.autoCompleteTimer) {
  384.                         clearTimeout(me.autoCompleteTimer);
  385.                         me.autoCompleteTimer = 0;
  386.                     }
  387.                         if (popup) {
  388.                             me.privatefunc.closePopupMenu(me);
  389.                             event.preventDefault();
  390.                             event.preventBubble();
  391.                             return;
  392.                         }
  393.                         break;
  394.  
  395.                     case 37 /*vk_left*/:
  396.                     case 39 /*vk_right*/:
  397.                     if (me.autoCompleteTimer) {
  398.                         clearTimeout(me.autoCompleteTimer);
  399.                         me.autoCompleteTimer = 0;
  400.                     }
  401.                         if (popup)
  402.                         {
  403.                             me.privatefunc.closePopupMenu(me);
  404.                             event.preventDefault();
  405.                             event.preventBubble();
  406.                         }
  407.                         me.privatefunc.cleanupInputField(me);
  408.                         break;
  409.  
  410.                     case 38 /*vk_up*/:
  411.                     case 40 /*vk_down*/:
  412.                     if (me.autoCompleteTimer) {
  413.                         clearTimeout(me.autoCompleteTimer);
  414.                         me.autoCompleteTimer = 0;
  415.                     }
  416.                         me.privatefunc.keyNavigation(me, event, popup);
  417.                         event.preventDefault();
  418.                         event.preventBubble();
  419.             if (! popup)
  420.                           me.privatefunc.cleanupInputField(me);
  421.                         break;
  422.                 }
  423.             },
  424.  
  425.             selectedItemIndex: 0
  426.  
  427.         })
  428.         ]]>
  429.         </property>
  430.         
  431.     </implementation>
  432.  
  433.     <handlers>
  434.         <handler event="click" action="this.privatefunc.cleanupInputField(this);"/>
  435.         <handler event="dblclick" action="this.privatefunc.cleanupInputField(this);"/>
  436.         <handler event="input" action="this.privatefunc.processInput(this);"/>
  437.         <handler event="keypress" action="this.privatefunc.processKeyPress(this, event);"/>
  438.         <handler event="focus" action="this.needToAutocomplete = false; this.lastResults.searchString=''; this.ignoreInputEvent = false"/>
  439.         <handler event="blur" action="
  440.                   this.privatefunc.closePopupMenu(this);
  441.             if (this.needToAutocomplete)
  442.                 this.privatefunc.finishAutoComplete(this, event);
  443.                   this.privatefunc.cleanupInputField(this);
  444.             "/>
  445.     </handlers>
  446.  
  447. </binding> 
  448. </bindings> 
  449.