package com.abmash.api.browser;
import java.io.InputStream;
import com.abmash.api.Browser;
import com.abmash.core.browser.JavaScriptResult;
import com.abmash.core.browser.interaction.JavaScriptExecution;
import com.abmash.core.tools.IOTools;
/**
* Execute or evaluate custom JavaScript, used by calling {@link Browser#javaScript(String, Object...)}.
* <p>
* Executing a script returns either true if the result was non-false, or false if it was empty.
* Evaluating a script returns the return value of the script.
* <p>
* JavaScript can be executed or evaluated synchronously or asynchronously. The parameter is optional
* and can be used to execute the script on a specific object instead of the whole document.
* <ul>
* <li>{@link JavaScript#evaluate(Browser, Object...)} evaluates the script synchronously</li>
* <li>{@link JavaScript#evaluateAsync(Browser, Object...)} evaluates the script asynchronously</li>
* <ul>
* <p>
* @author Alper Ortac
*/
public class JavaScript {
private String script;
/**
* Constructs new BrowserJavaScript instance for running JavaScript.
*
* @param script the JavaScript to execute or evaluate
*/
public JavaScript(String script) {
this.script = script;
// load prerequisites
// TODO cache the string
// TODO custom prerequisites
}
/**
* Constructs new BrowserJavaScript instance for running JavaScript.
*
* @param script the JavaScript to execute or evaluate
* @param isFile if true, the script parameter is taken as JavaScript filename which contains the script
*/
public JavaScript(String script, Boolean isFile) {
this(isFile ? getJsFromFile(script) : script);
}
/**
* Evaluates JavaScript synchronously.
*
* @param browser <code>Browser</code> instance to work with
* @param args optional list of objects which are passed to the script as arguments, accessable with arguments[0] etc.
* @return returned value of executed script
*/
public JavaScriptResult evaluate(Browser browser, Object... args) {
loadPrerequisites(browser);
JavaScriptExecution js = new JavaScriptExecution(browser, script, true, args);
js.execute();
return js.getResult();
}
/**
* Evaluates JavaScript asynchronously.
*
* @param browser <code>Browser</code> instance to work with
* @param args optional list of objects which are passed to the script as arguments, accessable with arguments[0] etc.
* @return returned value of executed script
*/
public JavaScriptResult evaluateAsync(Browser browser, Object... args) {
loadPrerequisites(browser);
JavaScriptExecution js = new JavaScriptExecution(browser, script, false, args);
js.execute();
return js.getResult();
}
private void loadPrerequisites(Browser browser) {
String prerequisiteScripts = "";
// load jquery
prerequisiteScripts += "if(typeof jQuery == 'undefined') {\n" + getJsFromFile("jquery.min") + "\n}\n";
// don't collide with other frameworks (i.e. Prototype)
prerequisiteScripts += "if(typeof jQuery.noConflict != 'undefined') { jQuery.noConflict(); }\n";
// don't load custom scripts each time, only once and if it's needed
prerequisiteScripts += "if(typeof abmashCustomScripts == 'undefined') {\n";
prerequisiteScripts += "abmashCustomScripts = { 'loaded': true };\n";
// Prototypes for base objects
prerequisiteScripts += getJsFromFile("javascript-prototypes");
// xpath support for jquery
// Usage in JavaScript:
// var paragraphs = jQuery().xpath('//p');
prerequisiteScripts += getJsFromFile("jquery.xpath");
// get unique css selector from elements in jQuery
// Usage in JavaScript:
// var path = $('#foo').getPath();
prerequisiteScripts += getJsFromFile("jquery-getpath");
// custom attribute selector which is case insensitive in jQuery
// Usage in JavaScript:
// var addressElements = jQuery('div').textMatch('CONTAINS', 'AdDresS')');
// var searchInputs = jQuery('input').attrMatch('CONTAINS', 'value', "SUbmIT")');
prerequisiteScripts += getJsFromFile("jquery-caseinsensitive");
// custom attribute names getter
// Usage in JavaScript:
// var attributes = jQuery('div#header').getAttributeNames();
prerequisiteScripts += getJsFromFile("jquery-attributes");
// abmash control scripts
prerequisiteScripts += getJsFromFile("abmash-control");
// custom visual closeness/direction selector in jQuery
// Usage in JavaScript:
// divs = jQuery('div:above(jQuery("selector"))');
// divs = jQuery('div:below(jQuery("selector"))');
// divs = jQuery('div:leftTo(jQuery("selector"))');
// divs = jQuery('div:rightTo(jQuery("selector"))');
// Parameters:
// selector: any jQuery object
prerequisiteScripts += getJsFromFile("abmash-visual");
// abmash image processing
prerequisiteScripts += getJsFromFile("abmash-image");
prerequisiteScripts += "}\n";
// execute all needed scripts at once
(new JavaScriptExecution(browser, prerequisiteScripts, true)).execute();
}
private static String getJsFromFile(String filename) {
InputStream stream = JavaScript.class.getResourceAsStream("/js/" + filename + ".js");
return IOTools.convertStreamToString(stream) + "\n";
}
}