= The fingers in the nose guide to build javascript plugins for FARR. Does that mean its easy ? =
	The basic principle is to define global methods onSearchBegin in fscript.js and to return results to farr 
	with FARR.emitResult. You have to call FARR.setState(querykey,SEARCHING) before publishing any result and 
	FARR.setState(querykey,STOPPED); when you are done.

= Basic installation =
	Copy the FScript.dll to a folder in Farr/plugins, create a fscript.js file and copy the basic sample into it.
	Change the globals variables displayname, version, author, ... At this point your plugin should be listed in
	the FARR plugin list.
	OR extract FScriptSample in Farr/plugins (it is a working plugin ) and start hacking from there.

= Javascript plugin sample =	
	// plugin script :
	displayname="MyJavascriptPlugin";
	versionstring="1.0.0";
	releasedatestring="Jan 1st, 2008";
	author="Author";
	updateurl="";
	homepageurl="";
	shortdescription="MyJavascriptPlugin";
	longdescription="MyJavascriptPlugin";
	advconfigstring="MyJavascriptPlugin";
	readmestring="MyJavascriptPlugin";
	iconfilename="MyJavascriptPlugin.ico";

	aliasstr="mjp";
	regexstr="";
	regexfilterstr="";
	keywordstr="";
	scorestr="300";

	// type
	UNKNOWN=0; FILE=1; FOLDER=2; ALIAS=3; URL=4; PLUGIN=5; CLIP=5;
	// Postprocessing
	IMMEDIATE_DISPLAY=0; ADDSCORE=1; MATCH_AGAINST_SEARCH=2;
	// search state
	STOPPED=0; SEARCHING=1;

	function onSearchBegin(querykey, explicit, queryraw, querynokeyword) {    
		if(!explicit) {
			return;
		}
		
		FARR.setState(querykey,SEARCHING);															// before emitResult set state to searching
		FARR.emitResult(querykey,"Hello", "Hello", iconfilename,UNKNOWN,IMMEDIATE_DISPLAY,1000);	// emit one result
		FARR.setState(querykey,STOPPED);															// when done set state to stopped
	}

= Availables globals methods =	
	// return result to FARR
	FARR.emitResult(querykey, title, path, icon, entrytype=FILE, resultpostprocessing=2, score=300);
	// you should set state to SEARCHING before search and to STOPPED when done
	FARR.setState(querykey, s);
	// call notifyStateChange when you want to publish intermediate results (farr does not seem to update display right now, but almost... )
	FARR.notifyStateChange(querykey);
	// do some special FARR action like setting statusbar, richedit (see farr plugin action documentation )
	FARR.setStrValue(command, value);
	// get a FARR internal value :
    // - Version.FARR (2.xx.xx style)
    // - Version.FARR_PLUGINAPI (1.xx.xx style)
    // - Version.FARR_PLUGINAPI_RELEASENUM (# style) <-- empty before V3. This is what I refer to with * API Version *
	FARR.getStrValue(command, value);
	// display a message box for helping debugging (you probably won't need it :)
	FARR.debug(txt);
	// set a periodic callback (id is a number, millisecond the time before next event, pFunc a javacsript function )
	FARR.setInterval(id, millisecond, pFunc);
	// stop a periodic callback (or die :)
	FARR.killInterval(id);
    // * NEW * show the internal option dialog
    FARR.showOptions()
    // * NEW * run some command
    FARR.exec(file,parameters,currentdirectory)
    // * NEW * read an ini value in a file
    FARR.getIniValue(file,section,value,def);

= Available callbacks =
	The javascript SDK will call you on the following global functions.
	You don't have to define them. If you don't need them you don't need to define them.
	Be lazy... Define only the ones you need.
	
	// called when the plugin start. Initialisations can be done here. If you need the directory of the plugin you can get it here.
	onInit(currentDirectory)
	// onSearchBegin is called whenever a search begin.
	// - querykey is the key of the search, you must specify it unchanged when calling FARR.emitResult, FARR.setState or FARR.notifyStateChange
	// - explicit is true if the alias match.
	// - queryraw is the query with alias
	// - querynokeyword is the query without alias
    // - * Version.FARR_PLUGINAPI_RELEASENUM >= 3 * : modifierstring
    // - * Version.FARR_PLUGINAPI_RELEASENUM >= 3 * : triggermethod
	onSearchBegin(querykey, explicit, queryraw, querynokeyword)
	// onRegexSearchMatch is called whever a search match the regexfilter (this is useful if you want that FARR filter your results based on another part than the end of the query )
	// - querykey is the key of the search, you must specify it unchanged when calling FARR.emitResult, FARR.setState or FARR.notifyStateChange
	// - queryraw is the query with alias
	// - querynokeyword is the query without alias
    // - * NEW : API Version >= 3 * : modifierstring
    // - * NEW : API Version >= 3 * : triggermethod
	// notes : onRegexSearchMatch is always explicit
	onRegexSearchMatch(querykey, queryraw, querynokeyword)
	// define onProcessTrigger if you want to do something special on a result
    // - returning true mean you handled the action (FARR will not launch default action )
    // - returning 1 mean you handled the action (FARR will not launch default action )
    // - returning 2 mean close the FARR window
	onProcessTrigger(title,path)
	// define onOptionsChanged to know when the internal options have completed
	onOptionsChanged()
	// define onDoAdvConfig to show your custom options UI when the advanced options button is pressed * experimental *
	onDoAdvConfig()
	// * NEW * onReceiveKey is called when a special key like enter is pressed in memo mode. (entered with setStrValue("window.richeditmode", "text" )
	onReceiveKey(Key, altpressed, controlpressed, shiftpressed)
	// * NEW * onIdleTime is called when more than 500ms idle elapsed in memo mode
	onIdleTime(idleTime)
    // * NEW * called when FARR set a value
    onSetStrValue
    // * NEW * called when FARR want a value from the plugin
    onGetStrValue

= Defining options =
	You can define a very simple option dialog by writing a options.xml file in the plugin directory.
	It must have a root node named options and a list of node with the attributes 'label' and 'value'.
	The Javascript SDK will generate a dialog with a label and a edit field for each node.
	
    !! To plugins developers : be very careful to not zip your option file with logins informations

	<options>
	<username label='Username :' value=''/>
	<password label='Password :' value=''/>
	</options>
	
	When the user press OK, the Javascript SDK will save options.xml to the disk and call you on onOptionChanged. 
	You can then reload options.xml and read values.
	
	function onInit(currentDirectory) { g_currentDirectory=currentDirectory; }
	function onOptionsChanged() { options.load(currentDirectory+"\\options.xml"); ... }
	
	I used it in the Delicious plugin. You should look at if you want to do that.

= Commands callables by plugin =
    launch, LAUNCHFILENAME (launch can be use to run command too like : htmlviewurl, dosearch ? )
    statusbar, TEXTTOSETONSTATUSBAR
    setsearch, TEXTTOSETINSEARCHEDIT
    setsearchnogo, TEXTTOSETINSEARCHEDIT
    stopsearch
    window.hide
    window.show
    window.toggle
    window.richeditmode, TEXTOPUTINRICHEDITWINDOW
    window.richeditheight, HEIGHTOFWINDOW
    window.richeditwidth, WIDTHOFWINDOW
    setshowallmode
    exit
    reporterror, ERRORTEXTTOREPORTINPLUGINLOG
    clipboard
    DisplayAlertMessage, TITLEnTEXT FOR ALERT BOX
    DisplayAlertMessageNoTimeout, TITLEnTEXT FOR ALERT BOX
    DisplayBalloonMessage,TITLEnTEXT FOR BALLOON TEXT
    

= Debugging =
	Debugging can be improved by installing the microsoft javascript debugger and setting the DWORDs :
	HKEY_CURRENT_USER\Software\Microsoft\Windows Script\Settings\JITDebug=1
	HKEY_CURRENT_USER\Software\Microsoft\Windows Script Host\Settings\JITDebug=1
	in the registry base.

= Useful objects =
	MSXML2.DOMDocument : to read xml
	MSXML2.XMLHttpRequest : to make requests
	WScript.Shell : to run programs and other things
	Scripting.FileSystemObject : to read and write files

= Advanced explications =
== Query Key ==
	The querykey is the mean to say to the Javascript SDK which request you are currently responding to.
	This is a number that change at each request. You must give it back unchanged when calling emitResult 
	or setState. This allow results to not mix between differents request.
	This is useful when you plugin does asynchronous search (like network requests ).
	You don't have to really care about it : just give it back unchanged to the methods that need it.
	The programmer decide you have to just to bug you. It can't be that easy :)
