<?xml version="1.0"?>
<!--
	A combination of Mozilla's textarea, timed-textbox, input-box, and
	input-box-spell bindings, with the timed-textbox's Return key
	event handler removed
	
	Note: It would be much nicer if a) Mozilla offered this natively or
	b) we just extended the timed-textbox binding directly, but since it's based
	on html:input rather than html:textarea, doing so breaks things in various
	ways (though it may be possible with some tweaking)
	
	Also note: spellcheck code here is a slightly adjusted version
	of a patch by Neil Deakin on Bugzilla that wasn't 	approved in time for
	Firefox 2.0 (https://bugzilla.mozilla.org/show_bug.cgi?id=346787).
	When there's native support for spellcheck="true" in XUL,	we'll hopefully be
	able to use that, though it'll still need to work as a timed textarea...
-->

<!DOCTYPE bindings [
  <!ENTITY % textcontextDTD SYSTEM "chrome://global/locale/textcontext.dtd" >
  %textcontextDTD;
  
  <!-- These aren't yet included in textcontext.dtd in Minefield, so we reproduce them here
  		(rather than including the massive browser.dtd) -->
  <!ENTITY spellAddToDictionary.label "Add to dictionary">
  <!ENTITY spellAddToDictionary.accesskey "o">
  <!ENTITY spellEnable.label "Spell check this field">
  <!ENTITY spellEnable.accesskey "S">
  <!ENTITY spellNoSuggestions.label "(No spelling suggestions)">
  <!ENTITY spellDictionaries.label "Languages">
  <!ENTITY spellDictionaries.accesskey "l">
  <!ENTITY spellAddDictionaries.label "Add dictionaries...">
  <!ENTITY spellAddDictionaries.accesskey "A">
]>

<bindings 	xmlns="http://www.mozilla.org/xbl"
			xmlns:html="http://www.w3.org/1999/xhtml"
			xmlns:xbl="http://www.mozilla.org/xbl"
			xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
	<binding id="timed-textarea" extends="chrome://global/content/bindings/textbox.xml#textbox">
		<implementation>
			<field name="mInputField">null</field>
			<property name="inputField" readonly="true">
				<getter><![CDATA[
				  if (!this.mInputField)
					this.mInputField = document.getAnonymousElementByAttribute(this, "anonid", "input");
				  return this.mInputField;
				]]></getter>
			</property>
		  
			<field name="_timer">null</field>
			<property name="timeout"
					onset="this.setAttribute('timeout', val); return val;"
					onget="return parseInt(this.getAttribute('timeout')) || 0;"/>
			<property name="value">
				<getter>
				  return this.inputField.value;
				</getter>
				<setter>
				  <![CDATA[
					this.inputField.value = val;
					if (this._timer)
					  clearTimeout(this._timer);
					return val;
				  ]]>
				</setter>
			</property>
			<method name="_fireCommand">
				<parameter name="me"/>
				<body>
				  <![CDATA[
					me._timer = null;
					me.doCommand();
				  ]]>
				</body>
			</method>
			
			
			<!-- Spellcheck code -->
			<field name="_spellCheckInitialized">false</field>
			<property name="spellCheckerUI" readonly="true">
				<getter><![CDATA[
				  if (!this._spellCheckInitialized) {
					this._spellCheckInitialized = true;
				
					const CI = Components.interfaces;
					if (!document instanceof CI.nsIDOMXULDocument)
					  return null;
				
					var textbox = this;
					
					if (!textbox || !textbox instanceof CI.nsIDOMXULTextBoxElement)
					  return null;
				
					try {
					  var loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"].
									 getService(CI.mozIJSSubScriptLoader);
					  loader.loadSubScript("chrome://global/content/inlineSpellCheckUI.js", this);
					  
					  if ("InlineSpellCheckerUI" in this)
						this.InlineSpellCheckerUI.init(
							textbox.inputField.QueryInterface(CI.nsIDOMNSEditableElement).editor
						);
					} catch(ex) {
						// this throws an error on window open...
					}
				  }
				
				  return this.InlineSpellCheckerUI;
				]]></getter>
			</property>
			
			<constructor>
			<![CDATA[
			  // can't initialize the spell checker in the constructor as not
			  // everything is initialized and the editor will fail to create the
			  // inline spell checker object
			  setTimeout(this._delayedInitSpellCheck, 0, this)
			  
				// oninput doesn't seem to fire on text drag
				this.inputField.addEventListener('dragdrop', function(event) {
					document.getBindingParent(event.target).doInput();
				}, false);
			]]>
			</constructor>
			
			<method name="_delayedInitSpellCheck">
				<parameter name="me"/>
				<body><![CDATA[
				  var spellui = me.spellCheckerUI;
				  if (spellui)
					spellui.enabled = true;
				]]></body>
			</method>
			
			<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>
			
			<method name="_doPopupItemEnablingSpell">
				<parameter name="popupNode"/>
				<body>
				  <![CDATA[
					var spellui = this.spellCheckerUI;
					if (!spellui || !spellui.canSpellCheck) {
					  this._setMenuItemVisibility("spell-no-suggestions", false);
					  this._setMenuItemVisibility("spell-check-enabled", false);
					  this._setMenuItemVisibility("spell-check-separator", false);
					  this._setMenuItemVisibility("spell-add-to-dictionary", false);
					  this._setMenuItemVisibility("spell-suggestions-separator", false);
					  this._setMenuItemVisibility("spell-dictionaries", false);
					  return;
					}
				
					spellui.initFromEvent(document.popupRangeParent,
										  document.popupRangeOffset);
				
					var enabled = spellui.enabled;
					document.getAnonymousElementByAttribute(this, "anonid",
					  "spell-check-enabled").setAttribute("checked", enabled);
				
					var overMisspelling = spellui.overMisspelling;
					this._setMenuItemVisibility("spell-add-to-dictionary", overMisspelling);
					this._setMenuItemVisibility("spell-suggestions-separator", overMisspelling);
				
					// suggestion list
					var suggestionsSeparator = document.getAnonymousElementByAttribute(this,
												 "anonid", "spell-add-to-dictionary");
					var numsug = spellui.addSuggestionsToMenu(popupNode, suggestionsSeparator, 5);
					this._setMenuItemVisibility("spell-no-suggestions", overMisspelling && numsug == 0);
				
					// dictionary list
					var dictmenu = document.getAnonymousElementByAttribute(this, "anonid",
									 "spell-dictionaries-menu");
					var addsep = document.getAnonymousElementByAttribute(this, "anonid",
									 "spell-language-separator");
					
					var numdicts = spellui.addDictionaryListToMenu(dictmenu, addsep);
					this._setMenuItemVisibility("spell-dictionaries", enabled);
					
					this._doPopupItemEnabling(popupNode);
				  ]]>
				</body>
			</method>
			
			<method name="_doPopupItemDisabling">
				<body><![CDATA[
				  if (this.spellCheckerUI) {
					this.spellCheckerUI.clearSuggestionsFromMenu();
					this.spellCheckerUI.clearDictionaryListFromMenu();
				  }
				]]></body>
			</method>
			
			<method name="_setMenuItemVisibility">
				<parameter name="anonid"/>
				<parameter name="visible"/>
				<body><![CDATA[
				  document.getAnonymousElementByAttribute(this, "anonid", anonid).
					hidden = ! visible;
				]]></body>
			</method>
			
			
			<method name="doTextCommand">
				<parameter name="command"/>
					<body>
					<![CDATA[
					var controller = document.commandDispatcher.getControllerForCommand(command);
					controller.doCommand(command);
					]]>
				</body>
			</method>
			
			<method name="doInput">
				<body>
				<![CDATA[
					if (this._timer) {
						clearTimeout(this._timer);
					}
					this._timer = this.timeout && setTimeout(this._fireCommand, this.timeout, this);
				]]>
				</body>
			</method>
		</implementation>
		
		
		<handlers>
			<handler event="input">
			<![CDATA[
				this.doInput();
			]]>
			</handler>
		</handlers>
		
		
		<content context="_child">
			<xul:hbox class="textbox-input-box" flex="1">
				<html:textarea class="textbox-textarea" flex="1" anonid="input"
					xbl:inherits="onfocus,onblur,xbl:text=value,disabled,tabindex,rows,cols,readonly,wrap"><children/></html:textarea>
				<xul:menupopup anonid="input-box-contextmenu"
								onpopupshowing="if (document.commandDispatcher.focusedElement != this.parentNode.firstChild) { this.parentNode.firstChild.focus(); } this.parentNode.parentNode._doPopupItemEnablingSpell(this);"
								onpopuphiding="this.parentNode.parentNode._doPopupItemDisabling(this);"
								oncommand="var cmd = event.originalTarget.getAttribute('cmd'); if(cmd) { this.parentNode.parentNode.doTextCommand(cmd); event.stopPropagation(); }">
					<xul:menuitem label="&spellNoSuggestions.label;" anonid="spell-no-suggestions" disabled="true"/>
					<xul:menuitem label="&spellAddToDictionary.label;" accesskey="&spellAddToDictionary.accesskey;" anonid="spell-add-to-dictionary"
									oncommand="this.parentNode.parentNode.parentNode.spellCheckerUI.addToDictionary();"/>
					<xul:menuseparator anonid="spell-suggestions-separator"/>
					<xul:menuitem label="&undoCmd.label;" accesskey="&undoCmd.accesskey;" cmd="cmd_undo"/>
					<xul:menuseparator/>
					<xul:menuitem label="&cutCmd.label;" accesskey="&cutCmd.accesskey;" cmd="cmd_cut"/>
					<xul:menuitem label="&copyCmd.label;" accesskey="&copyCmd.accesskey;" cmd="cmd_copy"/>
					<xul:menuitem label="&pasteCmd.label;" accesskey="&pasteCmd.accesskey;" cmd="cmd_paste"/>
					<xul:menuitem label="&deleteCmd.label;" accesskey="&deleteCmd.accesskey;" cmd="cmd_delete"/>
					<xul:menuseparator/>
					<xul:menuitem label="&selectAllCmd.label;" accesskey="&selectAllCmd.accesskey;" cmd="cmd_selectAll"/>
					<xul:menuseparator anonid="spell-check-separator"/>
					<xul:menuitem label="&spellEnable.label;" type="checkbox" accesskey="&spellEnable.accesskey;" anonid="spell-check-enabled"
									oncommand="this.parentNode.parentNode.parentNode.spellCheckerUI.toggleEnabled();"/>
					<xul:menu label="&spellDictionaries.label;" accesskey="&spellDictionaries.accesskey;" anonid="spell-dictionaries">
						<xul:menupopup anonid="spell-dictionaries-menu"
										onpopupshowing="event.stopPropagation();"
										onpopuphiding="event.stopPropagation();">
							<xul:menuseparator anonid="spell-language-separator"/>
							<xul:menuitem anonid="spell-add-dictionaries-main" label="&spellAddDictionaries.label;"
											accesskey="&spellAddDictionaries.accesskey;"
											oncommand="nsContextMenu.prototype.addDictionaries();"/>
						</xul:menupopup>
					</xul:menu>
				</xul:menupopup>
			</xul:hbox>
		  
		</content>
	</binding>
</bindings>