home *** CD-ROM | disk | FTP | other *** search
- <?xml version="1.0"?>
-
- <!DOCTYPE window [
- <!ENTITY % textcontextDTD SYSTEM "chrome://global/locale/textcontext.dtd" >
- %textcontextDTD;
- ]>
-
- <bindings id="autocompleteBindings"
- xmlns="http://www.mozilla.org/xbl"
- xmlns:html="http://www.w3.org/1999/xhtml"
- xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-
- <binding id="autocomplete" display="xul:menu"
- extends="chrome://global/content/bindings/textbox.xml#textbox">
- <resources>
- <stylesheet src="chrome://global/content/autocomplete.css"/>
- <stylesheet src="chrome://global/skin/autocomplete.css"/>
- </resources>
-
- <content>
- <xul:hbox class="autocomplete-internal-box textbox-internal-box" flex="1">
- <xul:hbox class="autocomplete-icon-box" align="center" inherits="userAction">
- <children includes="image">
- <xul:image class="autocomplete-icon" allowevents="true"/>
- </children>
- </xul:hbox>
-
- <xul:hbox class="autocomplete-textbox-container" align="center" flex="1" allowevents="true">
- <html:input anonid="textbox" class="autocomplete-textbox textbox-input" flex="1"
- inherits="onfocus,onblur,value,type,maxlength,disabled,size,readonly,userAction"/>
- </xul:hbox>
-
- <xul:hbox class="autocomplete-history-button" inherits="open,hidden=hideHistory">
- <xul:image class="autocomplete-history-image"/>
- </xul:hbox>
- </xul:hbox>
-
- <xul:popupset anonid="popupset">
- <xul:popup ignorekeys="true" anonid="popup" class="autocomplete-result-popup" inherits="for=id,nomatch"/>
- </xul:popupset>
-
- <children includes="menupopup"/>
- </content>
-
- <implementation>
-
- <constructor><![CDATA[
- // set default property values
- this.userAction = "none";
- this.noMatch = true;
- this.ifSetAttribute("timeout", 50);
- this.ifSetAttribute("maxrows", 5);
- this.ifSetAttribute("autoFill", false);
- this.ifSetAttribute("autoFillAfterMatch", false);
- this.ifSetAttribute("showPopup", true);
- this.ifSetAttribute("minResultsForPopup", 0);
- this.ifSetAttribute("flexPopup", true);
- this.ifSetAttribute("alwaysOpenPopup", false);
- this.ifSetAttribute("disableAutocomplete", false);
- this.ifSetAttribute("forceComplete", false);
- this.ifSetAttribute("tabScrolling", false);
- this.ifSetAttribute("showCommentColumn", false);
-
- // initialize the search sessions
- this.searchSessions = this.getAttribute("searchSessions");
-
- // assure that the history popup flexes as well as the results popup
- this.setAttribute("sizetopopup", this.flexPopup);
-
- var mps = this.getElementsByTagName("menupopup");
- if (mps.length == 0)
- this.ifSetAttribute("hideHistory", true);
-
- // turn js handler attributes into functions
- var attr = this.getAttribute("ontextcommand");
- if (attr) this.ontextcommand = new Function("userAction", attr);
- attr = this.getAttribute("onerrorcommand");
- if (attr) this.onerrorcommand = new Function("errItem", attr);
- attr = this.getAttribute("ontextrevert");
- if (attr) this.ontextrevert = new Function(attr);
- attr = this.getAttribute("oninit");
- if (attr) this.oninit = new Function(attr);
-
- // hack to work around lack of bottom-up constructor calling
- if ("initialize" in this.resultsPopup)
- this.resultsPopup.initialize();
-
- this.fireInit();
- ]]></constructor>
-
- <destructor><![CDATA[
- ]]></destructor>
-
- <!-- =================== PUBLIC PROPERTIES =================== -->
-
- <property name="value"
- onset="this.ignoreInputEvent = true;
- this.mInputElt.value = val;
- this.ignoreInputEvent = false;
- return val;"
- onget="return this.mInputElt ? this.mInputElt.value : null;"/>
-
- <property name="focused"
- onget="return this.getAttribute('focused') == 'true';"/>
-
- <!-- space-delimited string of search session types to use -->
- <property name="searchSessions" onget="return this.getAttribute('searchSessions')">
- <setter><![CDATA[
- val = val ? val : "";
- var list = val.split(" ");
- this.mSessions = {};
- this.mListeners = {};
- this.mLastResults = {};
- this.mLastStatus = {};
-
- for (var i in list) {
- var name = list[i];
- if (name != "") {
- var contractid = "@mozilla.org/autocompleteSession;1?type=" + name;
- try {
- var session =
- Components.classes[contractid].getService(Components.interfaces.nsIAutoCompleteSession);
- } catch (e) {
- dump("### ERROR - unable to create search session \"" + session + "\".\n");
- break;
- }
- this.mSessions[name] = session;
- this.mListeners[name] = new (this.mAutoCompleteListener)(name);
- this.mLastResults[name] = null;
- this.mLastStatus[name] = null;
- ++this.sessionCount;
- }
- }
- ]]></setter>
- </property>
-
- <!-- the number of sessions currently in use -->
- <property name="sessionCount">0</property>
-
- <!-- number of milliseconds after a keystroke before a search begins -->
- <property name="timeout"
- onset="return this.setAttribute('timeout', val);"
- onget="var t = parseInt(this.getAttribute('timeout')); return t ? t : 0;"/>
-
- <!-- number of milliseconds after a keystroke before a search begins -->
- <property name="maxRows"
- onset="return this.setAttribute('maxrows', val);"
- onget="var t = parseInt(this.getAttribute('maxrows')); return t ? t : 0;"/>
-
- <!-- option for filling the textbox with the best match while typing
- and selecting the difference -->
- <property name="autoFill"
- onset="return this.setAttribute('autoFill', val);"
- onget="return this.getAttribute('autoFill') == 'true';"/>
-
- <!-- if the resulting match string is not at the beginning of the typed string,
- this will optionally autofill like this "bar |>> foobar|" -->
- <property name="autoFillAfterMatch"
- onset="return this.setAttribute('autoFillAfterMatch', val);"
- onget="return this.getAttribute('autoFillAfterMatch') == 'true';"/>
-
- <!-- toggles a second column in the results list which contains
- the string in the comment field of each autocomplete result -->
- <property name="showCommentColumn"
- onget=
- "return this.getAttribute('showCommentColumn') == 'true';">
- <setter><![CDATA[
-
- var currentState = this.getAttribute('showCommentColumn');
-
- // if comment column has been switched from off to on
- //
- if (val && (currentState == 'false')) {
-
- // reset the flex on the value column and add the comment column
- //
- document.getElementById("value").setAttribute("flex", 2);
- this.resultsPopup.addColumn({id: "comment", flex: 1});
-
- // if comment column has been switched from on to off
- //
- } else if (!val && (currentState == 'true')) {
-
- // reset the flex on the value column and add the comment column
- //
- document.getElementById("value").setAttribute("flex", 1);
- this.resultsPopup.removeColumn('comment');
- }
-
- // save and return the current state
- //
- return this.setAttribute('showCommentColumn', val);
- ]]></setter>
- </property>
-
-
- <!-- option for completing to the default result whenever the user hits
- enter or the textbox loses focus -->
- <property name="forceComplete"
- onset="return this.setAttribute('forceComplete', val);"
- onget="return this.getAttribute('forceComplete') == 'true';"/>
-
- <!-- option to show the popup containing the results -->
- <property name="showPopup"
- onset="return this.setAttribute('showPopup', val);"
- onget="return this.getAttribute('showPopup') == 'true';"/>
-
- <!-- option to keep the popup open while typing, even when there are no matches -->
- <property name="alwaysOpenPopup"
- onset="return this.setAttribute('alwaysOpenPopup', val);"
- onget="return this.getAttribute('alwaysOpenPopup') == 'true';"/>
-
- <!-- option to size the popup to fit the width of the entire widget -->
- <property name="flexPopup"
- onset="this.setAttribute('sizetopopup', val); return this.setAttribute('flexPopup', val);"
- onget="return this.getAttribute('flexPopup') == 'true';"/>
-
- <!-- option to allow scrolling through the list via the tab key, rather than
- tab moving focus out of the textbox -->
- <property name="tabScrolling"
- onset="return this.setAttribute('tabScrolling', val);"
- onget="return this.getAttribute('tabScrolling') == 'true';"/>
-
- <!-- option to turn off autocomplete -->
- <property name="disableAutocomplete"
- onset="return this.setAttribute('disableAutocomplete', val);"
- onget="return this.getAttribute('disableAutocomplete') == 'true';"/>
-
- <!-- option to hide the history menubutton -->
- <property name="hideHistory"
- onset="this.setAttribute('hideHistory', val);"
- onget="return this.getAttribute('hideHistory') == 'true';"/>
-
- <property name="minResultsForPopup"
- onset="return this.setAttribute('minResultsForPopup', val);"
- onget="var t = parseInt(this.getAttribute('minResultsForPopup')); return t ? t : 0;"/>
-
- <!-- state which indicates the current action being performed by the user.
- Possible values are : none, typing, scrolling -->
- <property name="userAction"
- onset="return this.setAttribute('userAction', val);"
- onget="return this.getAttribute('userAction');"/>
-
- <!-- state which indicates if the last search had no matches -->
- <property name="noMatch">true</property>
-
- <!-- state which indicates a search is currently happening -->
- <property name="isSearching">false</property>
-
- <!-- state which indicates a search timeout is current waiting -->
- <property name="isWaiting"
- onget="return this.mAutoCompleteTimer != 0;"/>
-
- <!-- reference to the results popup element -->
- <property name="resultsPopup"><![CDATA[
- var elt = document.getAnonymousElementByAttribute(this, "anonid", "popup");
- elt.__AUTOCOMPLETE_BOX__ = this;
- elt;
- ]]></property>
-
- <!-- =================== PRIVATE PROPERTIES =================== -->
-
- <property name="mSessions">null</property>
- <property name="mListeners">null</property>
- <property name="mLastResults">null</property>
- <property name="mLastStatus">null</property>
- <property name="mLastKeyCode">null</property>
- <property name="mAutoCompleteTimer">0</property>
- <property name="mMenuOpen">false</property>
- <property name="mFireAfterSearch">false</property>
- <property name="mFinishAfterSearch">false</property>
- <property name="mNeedToFinish">false</property>
- <property name="mNeedToComplete">false</property>
- <property name="mTransientValue">false</property>
- <property name="mView">null</property>
- <property name="currentSearchString">null</property>
- <property name="ignoreInputEvent">false</property>
- <property name="oninit">null</property>
- <property name="ontextcommand">null</property>
- <property name="ontextrevert">null</property>
- <property name="onerrorcommand">null</property>
- <field name="mDefaultMatchFilled">false</field>
-
- <property name="mAutoCompleteListener"><![CDATA[
- var listener = function(aSession) { this.sessionName = aSession };
- listener.prototype = {
- param: this,
- sessionName: null,
- onAutoComplete: function(aResults, aStatus)
- {
- this.param.processResults(this.sessionName, aResults, aStatus);
- }
- };
- listener;
- ]]></property>
-
- <property name="mPopupSetElt"><![CDATA[
- var elt = document.getAnonymousElementByAttribute(this, "anonid", "popupset");
- elt.__AUTOCOMPLETE_BOX__ = this;
- elt;
- ]]></property>
-
- <property name="mInputElt"><![CDATA[
- document.getAnonymousElementByAttribute(this, "anonid", "textbox");
- ]]></property>
-
- <!-- =================== PUBLIC METHODS =================== -->
-
- <!-- get the result object from the autocomplete results from a specific session -->
- <method name="getResultAt">
- <parameter name="aIndex"/>
- <body><![CDATA[
- var obj = this.convertIndexToSession(aIndex);
- if (obj && this.mLastResults[obj.session]) {
- var nsIAutoCompleteItem = Components.interfaces.nsIAutoCompleteItem;
- if (obj.index >= 0) {
- var item = this.mLastResults[obj.session].items.QueryElementAt(obj.index, nsIAutoCompleteItem);
- return item;
- }
- }
- return null;
- ]]></body>
- </method>
-
- <!-- get the autocomplete session status returned by the session
- that a given item came from -->
- <method name="getSessionStatusAt">
- <parameter name="aIndex"/>
- <body><![CDATA[
- var obj = this.convertIndexToSession(aIndex);
- return obj ? this.mLastStatus[obj.session] : null;
- ]]></body>
- </method>
-
-
- <!-- get a value from the autocomplete results as a string via an absolute index-->
- <method name="getResultValueAt">
- <parameter name="aIndex"/>
- <body><![CDATA[
- var obj = this.convertIndexToSession(aIndex);
- return obj ? this.getSessionValueAt(obj.session, obj.index) : null;
- ]]></body>
- </method>
-
- <!-- get the result object from the autocomplete results from a specific session -->
- <method name="getSessionResultAt">
- <parameter name="aSession"/>
- <parameter name="aIndex"/>
- <body><![CDATA[
- var session = this.mLastResults[aSession];
- if (session) {
- var item = session.items.QueryElementAt(aIndex, Components.interfaces.nsIAutoCompleteItem);
- return item;
- }
- return null;
- ]]></body>
- </method>
-
- <!-- get a value from the autocomplete results as a string from a specific session -->
- <method name="getSessionValueAt">
- <parameter name="aSession"/>
- <parameter name="aIndex"/>
- <body><![CDATA[
- var result = this.getSessionResultAt(aSession, aIndex);
- if (result)
- return result.value;
- return null;
- ]]></body>
- </method>
-
- <!-- get the total number of results in a specific session or overall if session is null-->
- <method name="getResultCount">
- <parameter name="aSession"/>
- <body><![CDATA[
- return this.view.rowCount;
- ]]></body>
- </method>
-
- <!-- get a session object by index -->
- <method name="getSession">
- <parameter name="aIndex"/>
- <body><![CDATA[
- var idx = 0;
- for (var name in this.mSessions) {
- if (idx == aIndex)
- return this.mSessions[name];
- ++idx;
- }
- return null;
- ]]></body>
- </method>
-
- <!-- get a session object by name -->
- <method name="getSessionByName">
- <parameter name="aSessionName"/>
- <body><![CDATA[
- return this.mSessions[aSessionName];
- ]]></body>
- </method>
-
- <!-- add a session by reference -->
- <method name="addSession">
- <parameter name="aSession"/>
- <body><![CDATA[
- ++this.sessionCount;
- var name = "anon_"+this.sessionCount;
- this.mSessions[name] = aSession;
- this.mListeners[name] = new (this.mAutoCompleteListener)(name);
- this.mLastResults[name] = null;
- this.mLastStatus[name] = null;
- ]]></body>
- </method>
-
- <!-- remove a session by reference -->
- <method name="removeSession">
- <parameter name="aSession"/>
- <body><![CDATA[
- for (var name in this.mSessions) {
- if (this.mSessions[name] == aSession) {
- delete this.mSessions[name];
- delete this.mListeners[name];
- delete this.mLastResults[name];
- delete this.mLastStatus[name];
- --this.sessionCount;
- break;
- }
- }
- ]]></body>
- </method>
-
- <!-- make this widget listen to all of the same autocomplete sessions
- from another autocomplete widget -->
- <method name="syncSessions">
- <parameter name="aCopyFrom"/>
- <body><![CDATA[
- this.sessionCount = aCopyFrom.sessionCount;
- this.mSessions = {};
- this.mListeners = {};
- this.mLastResults = {};
- this.mLastStatus = {};
- for (var name in aCopyFrom.mSessions) {
- this.mSessions[name] = aCopyFrom.mSessions[name];
- this.mListeners[name] = new (this.mAutoCompleteListener)(name);
- this.mLastResults[name] = null;
- this.mLastStatus[name] = null;
- }
- ]]></body>
- </method>
-
- <!-- get the first session that has results -->
- <method name="getDefaultSession">
- <body><![CDATA[
- for (var name in this.mLastResults) {
- var results = this.mLastResults[name];
- if (results && results.items.Count() > 0)
- return name;
- }
- return null;
- ]]></body>
- </method>
-
- <!-- empty the cached result data and empty the results popup -->
- <method name="clearResults">
- <parameter name="aInvalidate"/>
- <body><![CDATA[
- this.clearResultData();
- this.clearResultElements(aInvalidate);
- ]]></body>
- </method>
-
- <!-- =================== PRIVATE METHODS =================== -->
-
- <!-- ::::::::::::: session searching ::::::::::::: -->
-
- <!-- -->
- <method name="callListener">
- <parameter name="me"/>
- <parameter name="aAction"/>
- <body><![CDATA[
- // bail if the binding was detached or the element removed from
- // document during the timeout
- if (!("startLookup" in me) || !me.ownerDocument || !me.parentNode)
- return;
-
- me.clearTimer();
-
- if (me.disableAutocomplete)
- return;
-
- switch (aAction) {
- case "startLookup":
- me.startLookup();
- break;
-
- case "stopLookup":
- me.stopLookup();
- break;
-
- case "autoComplete":
- me.autoComplete();
- break;
- }
- ]]></body>
- </method>
-
- <!-- -->
- <method name="startLookup">
- <body><![CDATA[
- var str = this.value;
- this.lastSearchString = this.currentSearchString;
- this.currentSearchString = str;
-
- this.isSearching = true;
- this.mSessionReturns = this.sessionCount;
- this.mFailureCount = 0;
- this.mFailureItems = 0;
- this.mDefaultMatchFilled = false; // clear out our prefill state.
-
- // tell each session to start searching...
- for (var name in this.mSessions)
- this.mSessions[name].onStartLookup(str, this.mLastResults[name], this.mListeners[name]);
- ]]></body>
- </method>
-
- <!-- -->
- <method name="stopLookup">
- <body><![CDATA[
- for (var name in this.mSessions)
- this.mSessions[name].onStopLookup();
- ]]></body>
- </method>
-
- <!-- -->
- <method name="autoComplete">
- <body><![CDATA[
- for (var name in this.mSessions)
- this.mSessions[name].onAutoComplete(this.value,
- this.mLastResults[name],
- this.mListeners[name]);
- ]]></body>
- </method>
-
- <!-- -->
- <method name="processResults">
- <parameter name="aSessionName"/>
- <parameter name="aResults"/>
- <parameter name="aStatus"/>
- <body><![CDATA[
- if (this.disableAutocomplete)
- return;
-
- --this.mSessionReturns;
-
- var firstReturn = this.mSessionReturns == (this.sessionCount-1) - this.mFailureCount;
-
- if (firstReturn)
- this.clearResults(false); // clear results, but don't repaint yet
-
- this.mLastStatus[aSessionName] = aStatus;
-
- // check the many criteria for failure
- if (aStatus == Components.interfaces.nsIAutoCompleteStatus.failed ||
- aStatus == Components.interfaces.nsIAutoCompleteStatus.ignored ||
- aStatus == Components.interfaces.nsIAutoCompleteStatus.noMatch ||
- aResults == null ||
- aResults.items.Count() == 0 ||
- aResults.searchString != this.currentSearchString)
- {
- this.mLastResults[aSessionName] = null;
- this.searchFailed();
- return;
- } else if (aStatus ==
- Components.interfaces.nsIAutoCompleteStatus.failureItems){
- ++this.mFailureItems;
- }
-
- this.mLastResults[aSessionName] = aResults;
-
- this.autoFillInput(aSessionName, aResults, false);
-
- // always call openResultPopup...we may not have opened it
- // if a previous search session didn't return enough search results.
- // it's smart and doesn't try to open itself multiple times...
- // be sure to add our result elements before calling openResultPopuup as we need
- // to know the total # of results found so far.
- this.addResultElements(aSessionName, aResults);
- this.openResultPopup();
-
- // if this is the last session to return...
- if (this.mSessionReturns == 0)
- this.postSearchCleanup();
-
- ]]></body>
- </method>
-
- <!-- called each time a search fails, except when failure items need
- to be displayed. If all searches have failed, clear the list
- and close the popup -->
- <method name="searchFailed">
- <body><![CDATA[
- // if it's the last session to return, time to clean up...
- if (this.mSessionReturns == 0)
- this.postSearchCleanup();
-
- ++this.mFailureCount;
-
- // if all searches are done and they all failed...
- if (this.mSessionReturns == 0 && this.mFailureCount == this.sessionCount) {
- if (this.alwaysOpenPopup) {
- this.clearResults(true); // clear data and repaint empty
-
- if (this.value) {
- this.openResultPopup();
- } else
- this.closeResultPopup();
- } else
- this.closeResultPopup();
- }
- ]]></body>
- </method>
-
- <!-- does some stuff after a search is done (success or failure) -->
- <method name="postSearchCleanup">
- <body><![CDATA[
- this.isSearching = false;
-
- // figure out if there are no matches in all search sessions
- var failed = true;
- for (var name in this.mSessions) {
- if (this.mLastResults[name])
- failed = this.mLastResults[name].items.Count() < 1;
- if (!failed)
- break;
- }
- this.noMatch = failed;
- this.setAttribute("nomatch", this.noMatch);
-
- // if we have processed all of our searches, and none of them gave us a default index,
- // then we should try to auto fill the input field with the first match.
- // note: autoFillInput is smart enough to kick out if we've already prefilled something...
- if (!this.noMatch) {
- var defaultSession = this.getDefaultSession();
- if (defaultSession)
- this.autoFillInput(defaultSession, this.mLastResults[defaultSession], true);
- }
-
- if (this.mFinishAfterSearch)
- this.finishAutoComplete(false, this.mFireAfterSearch);
- ]]></body>
- </method>
-
- <!-- when the focus exits the widget or user hits return,
- determine what value to leave in the textbox -->
- <method name="finishAutoComplete">
- <parameter name="aForceComplete"/>
- <parameter name="aFireTextCommand"/>
- <body><![CDATA[
- this.mFinishAfterSearch = false;
- this.mFireAfterSearch = false;
- if (this.mNeedToFinish && !this.disableAutocomplete) {
- // if a search is happening at this juncture, bail out of this function
- // and let the search finish, and tell it to come back here when it's done
- if (this.isSearching || this.isWaiting) {
- this.mFinishAfterSearch = true;
- this.mFireAfterSearch = aFireTextCommand;
- return;
- }
-
- this.mNeedToFinish = false;
-
- // set textbox value to either override value, or default search result
- var val = this.resultsPopup.getOverrideValue();
- if (val) {
- this.value = val;
- } else if (this.mTransientValue) {
- // do nothing
- } else if (this.forceComplete && (this.mNeedToComplete || aForceComplete)) {
- var defaultSession = this.getDefaultSession();
-
- // we want to use the default item index for the first session which gave us a valid
- // default item index...
-
- for (var name in this.mLastResults) {
- var results = this.mLastResults[name];
- if (results && results.items.Count() > 0 && results.defaultItemIndex != -1)
- {
- defaultSession = name;
- break;
- }
- }
-
- if (defaultSession) {
- var results = this.mLastResults[defaultSession];
- if (results && !this.noMatch)
- if (results.defaultItemIndex != -1)
- this.value = this.getSessionValueAt(defaultSession, results.defaultItemIndex);
- else
- this.value = this.getSessionValueAt(defaultSession, 0); // preselect the first one...
- }
- }
-
- this.closeResultPopup();
- }
-
- this.mNeedToComplete = false;
- this.currentSearchString = "";
- this.clearTimer();
-
- if (aFireTextCommand)
- this.fireTextCommand(this.userAction);
- ]]></body>
- </method>
-
- <!-- when the user clicks an entry in the autocomplete popup -->
- <method name="onResultClick">
- <body><![CDATA[
- // set textbox value to either override value, or the clicked result
- var errItem=null;
- var val = this.resultsPopup.getOverrideValue();
- if (val)
- this.value = val;
- else if (this.resultsPopup.selectedIndex != null &&
- !this.noMatch) {
- if (this.getSessionStatusAt(this.resultsPopup.selectedIndex) ==
- Components.interfaces.nsIAutoCompleteStatus.failureItems) {
- this.value = this.currentSearchString;
- this.mTransientValue = true;
- errItem = this.getResultAt(this.resultsPopup.selectedIndex);
- } else {
- this.value = this.getResultValueAt(
- this.resultsPopup.selectedIndex);
- }
- }
-
- this.mNeedToFinish = false;
- this.mNeedToComplete = false;
-
- this.closeResultPopup();
-
- this.currentSearchString = "";
-
- if (errItem) {
- this.fireErrorCommand(errItem);
- }
- this.fireTextCommand("clicking");
- ]]></body>
- </method>
-
- <!-- when the user hits escape, revert the previously typed value in the textbox -->
- <method name="undoAutoComplete">
- <body><![CDATA[
- var val = this.currentSearchString;
-
- var ok = this.fireTextRevert();
- if ((ok || ok == undefined) && val)
- this.value = val;
-
- this.userAction = "typing";
-
- this.currentSearchString = "";
- this.mNeedToComplete = false;
- ]]></body>
- </method>
-
- <!-- convert an absolute result index into a session name/index pair -->
- <method name="convertIndexToSession">
- <parameter name="aIndex"/>
- <body><![CDATA[
- var idx = 0;
- for (var name in this.mLastResults) {
- if (this.mLastResults[name]) {
- if ((idx+this.mLastResults[name].items.Count())-1 >= aIndex) {
- return {session: name, index: aIndex-idx};
- }
- idx += this.mLastResults[name].items.Count();
- }
- }
- return null;
- ]]></body>
- </method>
-
- <!-- ::::::::::::: user input handling ::::::::::::: -->
-
- <!-- -->
- <method name="processInput">
- <body><![CDATA[
- // stop current lookup in case it's async.
- this.stopLookup();
- // stop the queued up lookup on a timer
- this.clearTimer();
-
- if (this.ignoreInputEvent)
- return;
-
- if (this.disableAutocomplete)
- return;
-
- this.userAction = "typing";
- this.mNeedToFinish = true;
- this.mTransientValue = false;
- this.mNeedToComplete = true;
-
- this.resultsPopup.selectedIndex = null;
-
- // We want to autocomplete only if the user is editing at the end of the text
- if (this.mInputElt.selectionEnd >= this.value.length)
- this.mAutoCompleteTimer = setTimeout(this.callListener, this.timeout, this, "startLookup");
- else
- this.noMatch = true;
- ]]></body>
- </method>
-
- <!-- -->
- <method name="processKeyPress">
- <parameter name="aEvent"/>
- <body><![CDATA[
- this.mLastKeyCode = aEvent.keyCode;
-
- var killEvent = false;
-
- switch (aEvent.keyCode) {
- case KeyEvent.DOM_VK_TAB:
- if (this.tabScrolling) {
- // don't kill this event if alt-tab or ctrl-tab is hit
- if (!aEvent.altKey && !aEvent.ctrlKey) {
- killEvent = this.mMenuOpen;
- if (killEvent)
- this.keyNavigation(aEvent);
- }
- }
- break;
-
- case KeyEvent.DOM_VK_RETURN:
-
- // if this is a failure item, save it for fireErrorCommand
- var errItem = null;
- if (this.resultsPopup.selectedIndex != null &&
- this.getSessionStatusAt(this.resultsPopup.selectedIndex) ==
- Components.interfaces.nsIAutoCompleteStatus.failureItems) {
- errItem = this.getResultAt(this.resultsPopup.selectedIndex);
- }
-
- killEvent = this.mMenuOpen;
- this.finishAutoComplete(true, true);
- this.closeResultPopup();
- if (errItem) {
- this.fireErrorCommand(errItem);
- }
- break;
-
- case KeyEvent.DOM_VK_ESCAPE:
- this.clearTimer();
- killEvent = this.mMenuOpen;
- this.undoAutoComplete();
- this.closeResultPopup();
- break;
-
- case KeyEvent.DOM_VK_LEFT:
- case KeyEvent.DOM_VK_RIGHT:
- this.clearTimer();
- this.closeResultPopup();
- break;
-
- case KeyEvent.DOM_VK_PAGE_UP:
- case KeyEvent.DOM_VK_PAGE_DOWN:
- case KeyEvent.DOM_VK_UP:
- case KeyEvent.DOM_VK_DOWN:
- this.clearTimer();
- killEvent = true;
- this.keyNavigation(aEvent);
- break;
- }
-
- if (killEvent) {
- aEvent.preventDefault();
- aEvent.preventBubble();
- }
-
- return true;
- ]]></body>
- </method>
-
- <!-- -->
- <method name="keyNavigation">
- <parameter name="aEvent"/>
- <body><![CDATA[
- var k = aEvent.keyCode;
- if (k == KeyEvent.DOM_VK_TAB ||
- k == KeyEvent.DOM_VK_UP || k == KeyEvent.DOM_VK_DOWN ||
- k == KeyEvent.DOM_VK_PAGE_UP || k == KeyEvent.DOM_VK_PAGE_DOWN)
- {
- // up/down keys while menu is closed will open menu
- if (!this.mMenuOpen && (this.view.rowCount > 0 || this.alwaysOpenPopup)) {
- this.openResultPopup();
- return;
- }
-
- this.userAction = "scrolling";
- this.mNeedToComplete = false;
-
- var dir = k == KeyEvent.DOM_VK_DOWN ||
- k == KeyEvent.DOM_VK_PAGE_DOWN ||
- (k == KeyEvent.DOM_VK_TAB && !aEvent.shiftKey) ? 1 : -1;
- var amt = k == KeyEvent.DOM_VK_PAGE_UP ||
- k == KeyEvent.DOM_VK_PAGE_DOWN ? this.resultsPopup.pageCount-1 : 1;
- var selected = this.resultsPopup.selectBy(dir, amt);
-
- // determine which value to place in the textbox
- this.ignoreInputEvent = true;
- if (selected != null) {
- if (this.getSessionStatusAt(selected) ==
- Components.interfaces.nsIAutoCompleteStatus.failureItems) {
- this.value = this.currentSearchString;
- } else {
- this.value = this.getResultValueAt(selected);
- }
- this.mTransientValue = true;
- } else {
- this.value = this.currentSearchString;
- this.mTransientValue = false;
- }
-
- // move cursor to the end
- this.mInputElt.setSelectionRange(this.value.length, this.value.length);
- this.ignoreInputEvent = false;
- }
- ]]></body>
- </method>
-
- <!-- while the user is typing, fill the textbox with the "default" value
- if one can be assumed, and select the end of the text -->
- <method name="autoFillInput">
- <parameter name="aSessionName"/>
- <parameter name="aResults"/>
- <parameter name="aUseFirstMatchIfNoDefault"/>
- <body><![CDATA[
- if (this.mDefaultMatchFilled) return;
-
- if (!this.mFinishAfterSearch && this.autoFill &&
- this.mLastKeyCode != KeyEvent.DOM_VK_BACK_SPACE &&
- this.mLastKeyCode != KeyEvent.DOM_VK_DELETE) {
- var indexToUse = aResults.defaultItemIndex;
- if (aUseFirstMatchIfNoDefault && indexToUse == -1)
- indexToUse = 0;
-
- if (indexToUse != -1) {
- var resultValue = this.getSessionValueAt(aSessionName, indexToUse);
- var match = resultValue.toLowerCase();
- var entry = this.currentSearchString.toLowerCase();
- this.ignoreInputEvent = true;
- if (match.indexOf(entry) == 0) {
- var endPoint = this.value.length;
- this.value = this.value + resultValue.substr(endPoint);
- this.mInputElt.setSelectionRange(endPoint, this.value.length);
- } else {
- if (this.autoFillAfterMatch) {
- this.value = this.value + " >> " + resultValue;
- this.mInputElt.setSelectionRange(entry.length, this.value.length);
- } else {
- var postIndex = resultValue.indexOf(this.value);
- if (postIndex >= 0) {
- var startPt = this.value.length;
- this.value = this.value + resultValue.substr(startPt+postIndex);
- this.mInputElt.setSelectionRange(startPt, this.value.length);
- }
- }
- }
- this.mNeedToComplete = true;
- this.ignoreInputEvent = false;
- this.mDefaultMatchFilled = true;
- }
- }
- ]]></body>
- </method>
-
- <!-- ::::::::::::: popup and outliner ::::::::::::: -->
-
- <!-- -->
- <method name="openResultPopup">
- <body><![CDATA[
- if (!this.mMenuOpen && this.showPopup && this.focused &&
- (this.getResultCount("") >= this.minResultsForPopup
- || this.mFailureItems)) {
- if (this.flexPopup) {
- var w = this.boxObject.width;
- if (w != this.resultsPopup.boxObject.width)
- this.resultsPopup.setAttribute("width", w);
- }
-
- this.resultsPopup.openPopup(this, -1, -1, "popup", "bottomleft", "topleft");
- this.mMenuOpen = true;
- }
- ]]></body>
- </method>
-
- <!-- -->
- <method name="closeResultPopup">
- <body><![CDATA[
- if (this.resultsPopup && this.mMenuOpen) {
- this.resultsPopup.closePopup();
- this.mMenuOpen = false;
- }
- ]]></body>
- </method>
-
- <!-- -->
- <method name="addResultElements">
- <parameter name="aSessionName"/>
- <parameter name="aResults"/>
- <body><![CDATA[
- if (this.focused) {
- this.view.addResults(aResults);
- this.resultsPopup.adjustHeight();
- }
- ]]></body>
- </method>
-
- <!-- -->
- <method name="clearResultElements">
- <parameter name="aInvalidate"/>
- <body><![CDATA[
- this.view.clearResults(aInvalidate);
- if (aInvalidate)
- this.resultsPopup.adjustHeight();
-
- this.noMatch = true;
- ]]></body>
- </method>
-
- <!-- -->
- <method name="clearResultData">
- <body><![CDATA[
- for (var name in this.mSessions) {
- this.mLastResults[name] = null;
- this.mLastStatus[name] = null;
- }
- ]]></body>
- </method>
-
- <!-- ::::::::::::: miscellaneous ::::::::::::: -->
-
- <!-- -->
- <method name="ifSetAttribute">
- <parameter name="aAttr"/>
- <parameter name="aVal"/>
- <body><![CDATA[
- if (this.getAttribute(aAttr) == "")
- this.setAttribute(aAttr, aVal);
- ]]></body>
- </method>
-
- <!-- -->
- <method name="clearTimer">
- <parameter name=""/>
- <body><![CDATA[
- if (this.mAutoCompleteTimer) {
- clearTimeout(this.mAutoCompleteTimer);
- this.mAutoCompleteTimer = 0;
- }
- ]]></body>
- </method>
-
- <!-- ::::::::::::: event dispatching ::::::::::::: -->
-
- <!-- execute the external init handler -->
- <method name="fireInit">
- <body><![CDATA[
- return this.oninit ? this.oninit() : null;
- ]]></body>
- </method>
-
- <!-- execute the external command handler -->
- <method name="fireTextCommand">
- <parameter name="aUserAction"/>
- <body><![CDATA[
- return this.ontextcommand ? this.ontextcommand(aUserAction) : null;
- ]]></body>
- </method>
-
- <!-- execute the external command handler -->
- <method name="fireErrorCommand">
- <parameter name="aErrorItem"/>
- <body><![CDATA[
- return this.onerrorcommand ? this.onerrorcommand(aErrorItem) : null;
- ]]></body>
- </method>
-
- <!-- execute the external command handler -->
- <method name="fireTextRevert">
- <body><![CDATA[
- return this.ontextrevert ? this.ontextrevert() : null;
- ]]></body>
- </method>
-
- <!-- =================== OUTLINER VIEW =================== -->
-
- <property name="view"><![CDATA[
- ({
- mTextbox: this,
- mOutliner: null,
- mBoxObject: null,
- mResults: [],
- mRowCount: 0,
- mSelectedIndex: null,
-
- get outlinerBoxObject()
- {
- return this.mOutliner;
- },
-
- set selectedIndex(aRow)
- {
- if (!this.mBoxObject)
- return;
-
- if (this.mSelectedIndex != null)
- this.mBoxObject.invalidateRow(this.mSelectedIndex);
-
- this.mSelectedIndex = aRow;
-
- this.mBoxObject.invalidateRow(aRow);
-
- if (aRow != null)
- this.mBoxObject.ensureRowIsVisible(aRow);
- },
-
- get selectedIndex()
- {
- return this.mSelectedIndex;
- },
-
- clearResults: function(aInvalidate)
- {
- this.mRowCount = 0;
- this.mResults = [];
-
- if (aInvalidate && this.mOutliner)
- this.mOutliner.invalidate();
- },
-
- addResults: function(aResults)
- {
- this.mResults.push(aResults);
- var oldCount = this.mRowCount;
- this.mRowCount += aResults.items.Count();
-
- if (this.mOutliner)
- this.mOutliner.rowCountChanged(oldCount, this.mRowCount);
- },
-
- createAtom: function(aVal)
- {
- try {
- var i = Components.interfaces.nsIAtomService;
- var svc = Components.classes["@mozilla.org/atom-service;1"].getService(i);
- return svc.getAtom(aVal);
- } catch(ex) { }
- return null; // XXX equivalent to falling off the end?
- },
-
- //////////////////////////////////////////////////////////
- // nsIOutlinerView interface
-
- get rowCount() {
- return this.mRowCount;
- },
-
- // implementing these results in a crash
- // get selection() {},
- // set selection(aVal) { },
-
- setOutliner: function(aOutliner)
- {
- this.mOutliner = aOutliner;
-
- if (aOutliner) {
- this.mBoxObject = this.mTextbox.resultsPopup.outliner.outlinerBoxObject;
-
- // cache atoms for pseudoelement properties
- this.mAtomSelected = this.createAtom("menuactive")
- }
- },
-
- getCellText: function(aRow, aColId)
- {
- var result = this.mTextbox.getResultAt(aRow);
- if (!result) return "";
- return aColId == "value" ? result.value : (aColId == "comment" ? result.comment : "");
- },
-
- getRowProperties: function(aIndex, aProperties)
- {
- if (aIndex == this.mSelectedIndex)
- aProperties.AppendElement(this.mAtomSelected);
- },
-
- getCellProperties: function(aIndex, aColId, aProperties)
- {
- this.getRowProperties(aIndex, aProperties);
-
- // for the value column, append nsIAutoCompleteItem::className
- // to the property list so that we can style this column
- // using that property
- try {
- if (aColId == "value") {
- var className = this.mTextbox.getResultAt(aIndex).className;
- if ( className != "" ) {
- aProperties.AppendElement(this.createAtom(className));
- }
- }
- } catch (ex) {
- // the ability to style here is a frill, so don't abort
- // if there's a problem
- }
- },
-
- getColumnProperties: function(aColId, aColElt, aProperties)
- {
- },
-
- getParentIndex: function(aRowIndex) { },
- hasNextSibling: function(aRowIndex, aAfterIndex) { },
- getLevel: function(aIndex) {},
- isContainer: function(aIndex) {},
- isContainerOpen: function(aIndex) {},
- isContainerEmpty: function(aIndex) {},
- toggleOpenState: function(aIndex) {},
- selectionChanged: function() {},
- cycleHeader: function(aColId, aElt) {},
- cycleCell: function(aRow, aColId) {},
- isEditable: function(aRow, aColId) {},
- setCellText: function(aRow, aColId, aValue) {},
- performAction: function(aAction) {},
- performActionOnRow: function(aAction, aRow) {},
- performActionOnCell: function(aAction, aRow, aColId) {}
- });
- ]]></property>
-
- </implementation>
-
- <handlers>
- <handler event="input"
- action="this.processInput();"/>
-
- <handler event="keypress" phase="capturing"
- action="return this.processKeyPress(event);"/>
-
- <handler event="focus" phase="capturing"
- action="this.userAction = 'typing';"/>
-
- <handler event="blur" phase="capturing"
- action="this.userAction = 'none'; this.finishAutoComplete(false, false);"/>
- </handlers>
- </binding>
-
- <binding id="autocomplete-result-popup" extends="chrome://global/content/bindings/popup.xml#popup">
- <resources>
- <stylesheet src="chrome://global/content/autocomplete.css"/>
- <stylesheet src="chrome://global/skin/autocomplete.css"/>
- </resources>
-
- <content>
- <xul:hbox class="autocomplete-result-box" flex="1">
- <xul:outliner anonid="outliner" class="autocomplete-outliner" flex="1">
- <xul:outlinerbody anonid="outlinerbody" class="autocomplete-outlinerbody" flex="1"/>
- </xul:outliner>
- </xul:hbox>
- </content>
-
- <implementation>
- <constructor><![CDATA[
- if (this.textbox && this.textbox.view)
- this.initialize();
- ]]></constructor>
-
- <property name="textbox"
- onget="return '__AUTOCOMPLETE_BOX__' in this ? this.__AUTOCOMPLETE_BOX__ : null;"/>
-
- <property name="outliner">
- document.getAnonymousElementByAttribute(this, "anonid", "outliner");
- </property>
-
- <property name="outlinerbody">
- document.getAnonymousElementByAttribute(this, "anonid", "outlinerbody");
- </property>
-
- <property name="view" onget="return this.mView;">
- <setter><![CDATA[
- this.mView = val;
- var bx = this.outliner.boxObject;
- bx = bx.QueryInterface(Components.interfaces.nsIOutlinerBoxObject);
- bx.view = val;
- ]]></setter>
- </property>
-
- <property name="pageCount"
- onget="return this.outliner.outlinerBoxObject.getPageCount();"/>
-
- <property name="selectedIndex"
- onget="return this.textbox.view.selectedIndex"
- onset="this.textbox.view.selectedIndex = val; return val;"/>
-
- <property name="mLastRows">0</property>
-
- <method name="initialize">
- <body><![CDATA[
- this.outliner.__AUTOCOMPLETE_BOX__ = this.textbox;
- this.outlinerbody.__AUTOCOMPLETE_BOX__ = this.textbox;
-
- this._selectedIndex = null;
-
- this.initColumns();
- this.view = this.textbox.view;
- ]]></body>
- </method>
-
- <!-- initialize the columns in the outliner -->
- <method name="initColumns">
- <body><![CDATA[
- if (this.textbox.showCommentColumn) {
- this.addColumn({id: "value", flex: 2});
- this.addColumn({id: "comment", flex: 1});
- } else
- this.addColumn({id: "value", flex: 1});
- ]]></body>
- </method>
-
- <method name="addColumn">
- <parameter name="aAttrs"/>
- <body><![CDATA[
- var col = document.createElement("outlinercol");
- col.setAttribute("class", "autocomplete-outlinercol");
- for (var name in aAttrs)
- col.setAttribute(name, aAttrs[name]);
- this.outliner.appendChild(col);
- return col;
- ]]></body>
- </method>
-
- <!-- remove a single column from the outliner, specified by
- element id -->
- <method name="removeColumn">
- <parameter name="aColId"/>
- <body><![CDATA[
- return this.outliner.removeChild(document.getElementById(aColId));
- ]]></body>
- </method>
-
- <method name="adjustHeight">
- <body><![CDATA[
- // detect the desired height of the outliner
- var bx = this.outliner.outlinerBoxObject;
- var view = this.textbox.view;
- var rows = this.textbox.maxRows;
- if (!view.rowCount || (rows && view.rowCount < rows))
- rows = view.rowCount;
-
- var height = rows * bx.rowHeight;
-
- this.outliner.setAttribute("height", height);
- this.outliner.setAttribute("hidescrollbar", view.rowCount <= rows);
-
- // XXX horrible hack to workaround for bug 86551
- // outliner will refuse to recognize initial height of 0 unless
- // we force frame reconstruction via setting the style attribute
- if (!("__firstPaint__" in this)) {
- this.__firstPaint__ = true;
- this.outliner.setAttribute("style", this.outliner.getAttribute("style"));
- }
- ]]></body>
- </method>
-
- <method name="selectBy">
- <parameter name="aDir"/>
- <parameter name="aAmount"/>
- <body><![CDATA[
- try {
- var bx = this.outliner.outlinerBoxObject;
- var view = bx.view;
- this.selectedIndex = this.getNextIndex(aDir, aAmount, this.selectedIndex, view.rowCount-1);
-
- return this.selectedIndex;
- } catch (ex) {
- // do nothing - occasionally timer-related js errors happen here
- // e.g. "this.selectedIndex has no properties", when you type fast and hit a
- // navigation key before this popup has opened
- return null;
- }
- ]]></body>
- </method>
-
- <method name="getNextIndex">
- <parameter name="aDir"/>
- <parameter name="aAmount"/>
- <parameter name="aIndex"/>
- <parameter name="aMaxRow"/>
- <body><![CDATA[
- if (aMaxRow < 0)
- return null;
-
- var newIdx = aIndex + aDir*aAmount;
- if (aDir < 0 && aIndex == null || newIdx > aMaxRow && aIndex != aMaxRow)
- newIdx = aMaxRow;
- else if (aDir > 0 && aIndex == null || newIdx < 0 && aIndex != 0)
- newIdx = 0;
-
- if (newIdx < 0 && aIndex == 0 || newIdx > aMaxRow && aIndex == aMaxRow)
- aIndex = null;
- else
- aIndex = newIdx;
-
- return aIndex;
- ]]></body>
- </method>
-
- <!-- This method is meant to be overriden by bindings extending this one. When the
- user selects an item from the list by hitting enter or clicking, this method
- can set the value of the textbox to a different value if it wants to. -->
- <method name="getOverrideValue">
- <body><![CDATA[
- return null;
- ]]></body>
- </method>
-
- </implementation>
-
- <handlers>
- <handler event="popupshowing">
- this.textbox.mMenuOpen = true;
- </handler>
-
- <handler event="popuphiding">
- this.textbox.mMenuOpen = false;
- this.selectedIndex = null;
- </handler>
- </handlers>
- </binding>
-
- <binding id="autocomplete-outliner" extends="chrome://global/content/bindings/outliner.xml#outliner">
- <resources>
- <stylesheet src="chrome://global/content/autocomplete.css"/>
- <stylesheet src="chrome://global/skin/autocomplete.css"/>
- </resources>
-
- <content>
- <xul:vbox flex="1">
- <xul:hbox class="autocomplete-outliner-cols">
- <children includes="outlinercol"/>
- </xul:hbox>
- <xul:outlinerrows class="autocomplete-outlinerrows outliner-rows" inherits="hidescrollbar" flex="1">
- <children/>
- </xul:outlinerrows>
- </xul:vbox>
- </content>
-
- <implementation>
- <property name="textbox"
- onget="return this.__AUTOCOMPLETE_BOX__;"/>
- </implementation>
- </binding>
-
- <binding id="autocomplete-outlinerbody">
- <resources>
- <stylesheet src="chrome://global/content/autocomplete.css"/>
- <stylesheet src="chrome://global/skin/autocomplete.css"/>
- </resources>
-
- <implementation>
- <property name="textbox"
- onget="return this.__AUTOCOMPLETE_BOX__;"/>
-
- <property name="mLastMoveTime">new Date()</property>
-
- <method name="getHoverCell">
- <parameter name="aEvent"/>
- <body><![CDATA[
- var obox = this.textbox.view.outlinerBoxObject;
- var pbox = this.textbox.resultsPopup.boxObject;
-
- var row = {}; var col = {}; var obj = {};
- var x = aEvent.screenX-pbox.screenX + this.boxObject.x;
- var y = aEvent.screenY-pbox.screenY + this.boxObject.y;
- obox.getCellAt(x-1, y-1, row, col, obj);
- if (row.value >= 0 && row.value < this.textbox.view.rowCount)
- return {row: row.value, column: col.value};
- else
- return null;
- ]]></body>
- </method>
- </implementation>
-
- <handlers>
- <handler event="mouseout" action="this.textbox.view.selectedIndex = null;"/>
- <handler event="mouseup" action="this.textbox.onResultClick();"/>
-
- <handler event="mousemove"><![CDATA[
- if (new Date() - this.mLastMoveTime > 30) {
- var rc = this.getHoverCell(event);
- if (rc && rc.row != this.textbox.view.selectedIndex)
- this.textbox.view.selectedIndex = rc.row;
- this.mLastMoveTime = new Date();
- }
- ]]></handler>
- </handlers>
- </binding>
-
- <binding id="autocomplete-outlinerrows">
- <resources>
- <stylesheet src="chrome://global/content/autocomplete.css"/>
- <stylesheet src="chrome://global/skin/autocomplete.css"/>
- </resources>
-
- <content onmousedown="event.preventDefault()">
- <xul:hbox flex="1" class="outliner-bodybox">
- <children/>
- </xul:hbox>
- <xul:scrollbar inherits="hidescrollbar" orient="vertical" class="outliner-scrollbar"/>
- </content>
- </binding>
-
- <binding id="autocomplete-outlinercol">
- <resources>
- <stylesheet src="chrome://global/content/autocomplete.css"/>
- <stylesheet src="chrome://global/skin/autocomplete.css"/>
- </resources>
- </binding>
-
- <binding id="autocomplete-history-popup" extends="chrome://global/content/bindings/popup.xml#popup">
- <resources>
- <stylesheet src="chrome://global/content/autocomplete.css"/>
- <stylesheet src="chrome://global/skin/autocomplete.css"/>
- </resources>
-
- <content>
- <xul:vbox class="autocomplete-result-box autocomplete-history-box" flex="1">
- <children/>
- </xul:vbox>
- </content>
- </binding>
-
- <binding id="autocomplete-internal-box">
- <content context="_child">
- <children/>
- <xul:menupopup onpopupshowing="this.parentNode.focus(); this.parentNode.doPopupItemEnabling(this);">
- <xul:menuitem label="&undoCmd.label;" accesskey="&undoCmd.accesskey;" cmd="cmd_undo"
- oncommand="var controller = document.commandDispatcher.getControllerForCommand('cmd_undo');
- controller.doCommand('cmd_undo');"/>
- <xul:menuseparator/>
- <xul:menuitem label="&cutCmd.label;" accesskey="&cutCmd.accesskey;" cmd="cmd_cut"
- oncommand="var controller = document.commandDispatcher.getControllerForCommand('cmd_cut');
- controller.doCommand('cmd_cut');"/>
- <xul:menuitem label="©Cmd.label;" accesskey="©Cmd.accesskey;" cmd="cmd_copy"
- oncommand="var controller = document.commandDispatcher.getControllerForCommand('cmd_copy');
- controller.doCommand('cmd_copy');"/>
- <xul:menuitem label="&pasteCmd.label;" accesskey="&pasteCmd.accesskey;" cmd="cmd_paste"
- oncommand="var controller = document.commandDispatcher.getControllerForCommand('cmd_paste');
- controller.doCommand('cmd_paste');"/>
- <xul:menuitem label="&deleteCmd.label;" accesskey="&deleteCmd.accesskey;" cmd="cmd_delete"
- oncommand="var controller = document.commandDispatcher.getControllerForCommand('cmd_delete');
- controller.doCommand('cmd_delete');"/>
- <xul:menuseparator/>
- <xul:menuitem label="&selectAllCmd.label;" accesskey="&selectAllCmd.accesskey;" cmd="cmd_selectAll"
- oncommand="var controller = document.commandDispatcher.getControllerForCommand('cmd_selectAll');
- controller.doCommand('cmd_selectAll');"/>
- </xul:menupopup>
- </content>
-
- <implementation>
- <method name="doPopupItemEnabling">
- <parameter name="popupNode"/>
- <body>
- <![CDATA[
- var children = popupNode.childNodes;
- for (var i = 0; i < children.length; i++) {
- var command = children[i].getAttribute("cmd");
- if (command) {
- var controller = document.commandDispatcher.getControllerForCommand(command);
- var enabled = controller.isCommandEnabled(command);
- if (enabled)
- children[i].removeAttribute("disabled");
- else
- children[i].setAttribute("disabled", "true");
- }
- }
- ]]>
- </body>
- </method>
- </implementation>
- </binding>
-
- </bindings>
-
-