diff --git a/android/titanium/lib/js-debug.jar b/android/titanium/lib/js-debug.jar index 0aa3a790767..019c5f6593c 100644 Binary files a/android/titanium/lib/js-debug.jar and b/android/titanium/lib/js-debug.jar differ diff --git a/android/titanium/lib/js.jar b/android/titanium/lib/js.jar index 0aa3a790767..019c5f6593c 100644 Binary files a/android/titanium/lib/js.jar and b/android/titanium/lib/js.jar differ diff --git a/android/titanium/src/org/appcelerator/titanium/TiC.java b/android/titanium/src/org/appcelerator/titanium/TiC.java index 786ebdc90fd..15f43030339 100644 --- a/android/titanium/src/org/appcelerator/titanium/TiC.java +++ b/android/titanium/src/org/appcelerator/titanium/TiC.java @@ -292,6 +292,7 @@ public class TiC public static final String PROPERTY_TRANSFORM = "transform"; public static final String PROPERTY_TRUE_HEADING = "trueHeading"; public static final String PROPERTY_TYPE = "type"; + public static final String PROPERTY_URI = "uri"; public static final String PROPERTY_URL = "url"; public static final String PROPERTY_USER_LOCATION = "userLocation"; public static final String PROPERTY_VALUE = "value"; diff --git a/android/titanium/src/ti/modules/titanium/TitaniumModule.java b/android/titanium/src/ti/modules/titanium/TitaniumModule.java index e974a69fdca..7dc08c2acf0 100644 --- a/android/titanium/src/ti/modules/titanium/TitaniumModule.java +++ b/android/titanium/src/ti/modules/titanium/TitaniumModule.java @@ -27,6 +27,7 @@ import org.appcelerator.titanium.TiApplication; import org.appcelerator.titanium.TiBaseActivity; import org.appcelerator.titanium.TiBlob; +import org.appcelerator.titanium.TiC; import org.appcelerator.titanium.TiContext; import org.appcelerator.titanium.TiLaunchActivity; import org.appcelerator.titanium.io.TiBaseFile; @@ -50,7 +51,8 @@ import android.os.Handler; @Kroll.module @Kroll.topLevel({"Ti", "Titanium"}) -public class TitaniumModule extends KrollModule implements TiContext.OnLifecycleEvent, TiContext.OnServiceLifecycleEvent +public class TitaniumModule extends KrollModule + implements TiContext.OnLifecycleEvent, TiContext.OnServiceLifecycleEvent { private static final String LCAT = "TitaniumModule"; private static final boolean DBG = TiConfig.LOGD; @@ -74,7 +76,14 @@ public TitaniumModule(TiContext tiContext) @Kroll.getProperty @Kroll.method public String getUserAgent() { - return System.getProperties().getProperty("http.agent")+" Titanium/"+getVersion(); + StringBuilder builder = new StringBuilder(); + String httpAgent = System.getProperty("http.agent"); + if (httpAgent != null) { + builder.append(httpAgent); + } + builder.append(" Titanium/") + .append(getVersion()); + return builder.toString(); } @Kroll.getProperty @Kroll.method @@ -163,7 +172,15 @@ public void schedule() public void run() { if (canceled) return; - Log.d(LCAT, "calling " + (interval?"interval":"timeout") + " timer " + id + " @" + new Date().getTime()); + if (DBG) { + StringBuilder message = new StringBuilder("calling ") + .append(interval ? "interval" : "timeout") + .append(" timer ") + .append(id) + .append(" @") + .append(new Date().getTime()); + Log.d(LCAT, message.toString()); + } long start = System.currentTimeMillis(); callback.callSync(args); if (interval && !canceled) { @@ -395,8 +412,11 @@ public String localize(KrollInvocation invocation, Object args[]) } } - protected KrollModule requireNativeModule(TiContext context, String path) { - Log.d(LCAT, "Attempting to include native module: " + path); + protected KrollModule requireNativeModule(TiContext context, String path) + { + if (DBG) { + Log.d(LCAT, "Attempting to include native module: " + path); + } KrollModuleInfo info = KrollModule.getModuleInfo(path); if (info == null) return null; @@ -404,66 +424,90 @@ protected KrollModule requireNativeModule(TiContext context, String path) { } @Kroll.method @Kroll.topLevel - public KrollProxy require(KrollInvocation invocation, String path) { - - // 1. look for a TiPlus module first + public KrollProxy require(KrollInvocation invocation, String path) + { + // 1. look for a native module first // 2. then look for a cached module // 3. then attempt to load from resources TiContext ctx = invocation.getTiContext().getRootActivity().getTiContext(); KrollModule module = requireNativeModule(ctx, path); + StringBuilder builder = new StringBuilder(); + if (module != null) { KrollModuleInfo info = module.getModuleInfo(); - Log.d(LCAT, "Succesfully loaded module: " + info.getName() + "/" + info.getVersion()); + builder.append("Succesfully loaded module: ") + .append(info.getName()) + .append("/") + .append(info.getVersion()); + Log.i(LCAT, builder.toString()); return module; } - // NOTE: commonjs modules load absolute to root in Titanium - String fileUrl = "app://"+path+".js"; + // NOTE: CommonJS modules load absolute to app:// in Titanium + builder.setLength(0); + builder.append(TiC.URL_APP_PREFIX) + .append(path) + .append(".js"); + String fileUrl = builder.toString(); TiBaseFile tbf = TiFileFactory.createTitaniumFile(ctx, new String[]{ fileUrl }, false); - if (tbf!=null) - { - try - { - TiBlob blob = (TiBlob)tbf.read(); - if (blob == null) { - Log.e(LCAT, "Couldn't read required file: " + fileUrl); - return null; - } + if (tbf == null) { + //the spec says we are required to throw an exception + Context.reportError("Couldn't find module: " + path); + return null; + } - // create the common js exporter - KrollProxy proxy = new KrollProxy(ctx); - StringBuilder buf = new StringBuilder(); - buf.append("(function(exports){"); - buf.append(blob.getText()); - buf.append("return exports;"); - buf.append("})({})"); - Scriptable result = (Scriptable)ctx.evalJS(buf.toString()); - // common js modules export all functions/properties as - // properties of the special export object provided - for (Object key : result.getIds()) - { - String propName = key.toString(); - Scriptable propValue = (Scriptable)result.get(propName,result); - proxy.setProperty(propName, propValue); - } - // spec says you must have a read-only id property - we don't - // currently support readonly in kroll so this is probably OK for now - proxy.setProperty("id", path); - // uri is optional but we point it to where we loaded it - proxy.setProperty("uri",fileUrl); - return proxy; + if (DBG) { + Log.d(LCAT, "Attempting to include JS module: " + tbf.nativePath()); + } + try { + TiBlob blob = (TiBlob) tbf.read(); + if (blob == null) { + Log.e(LCAT, "Couldn't read required file: " + fileUrl); + return null; } - catch(Exception ex) - { - Log.e(LCAT,"Error loading module named: "+path,ex); - Context.throwAsScriptRuntimeEx(ex); + + // TODO: we need to switch to the Rhino native require() + // implementation, but in the meantime this will have to do + + // create the CommonJS exporter + KrollProxy proxy = new KrollProxy(ctx); + builder.setLength(0); + builder.append("(function(exports){") + .append(blob.getText()) + .append("return exports;") + .append("})({})"); + + Object result = ctx.evalJS(builder.toString()); + + if (!(result instanceof Scriptable)) { + builder.setLength(0); + builder.append("Module did not correctly return an exports object: ") + .append(path) + .append(", result: ") + .append(result); + Context.throwAsScriptRuntimeEx(new Exception(builder.toString())); return null; } - } - //the spec says we are required to throw an exception - Context.reportError("couldn't find module: "+path); - return null; + Scriptable exports = (Scriptable) result; + // CommonJS modules export all functions/properties as + // properties of the special exports object provided + for (Object key : exports.getIds()) { + String propName = key.toString(); + proxy.setProperty(propName, exports.get(propName, exports)); + } + + // spec says you must have a read-only id property - we don't + // currently support readonly in kroll so this is probably OK for now + proxy.setProperty(TiC.PROPERTY_ID, path); + // uri is optional but we point it to where we loaded it + proxy.setProperty(TiC.PROPERTY_URI, fileUrl); + return proxy; + } catch (Exception ex) { + Log.e(LCAT, "Error loading module named: " + path, ex); + Context.throwAsScriptRuntimeEx(ex); + return null; + } } @Kroll.method @@ -507,4 +551,4 @@ public KrollObject getKrollObject() } return super.getKrollObject(); } -} \ No newline at end of file +} diff --git a/drillbit/tests/includes/Resources/module.js b/drillbit/tests/includes/Resources/module.js new file mode 100644 index 00000000000..06b402a181d --- /dev/null +++ b/drillbit/tests/includes/Resources/module.js @@ -0,0 +1 @@ +exports.message = "test required module"; diff --git a/drillbit/tests/includes/includes.js b/drillbit/tests/includes/includes.js index 62b4c979f76..66227602b3c 100644 --- a/drillbit/tests/includes/includes.js +++ b/drillbit/tests/includes/includes.js @@ -35,6 +35,12 @@ describe("Ti.include tests", { Ti.include('l2/../l2/./l3/lotsofdots.js'); }).shouldNotThrowException(); valueOf(testval).shouldBeTrue(); - } + }, + simpleRequire: function() { + valueOf(require).shouldBeFunction(); + var module = require("module"); + valueOf(module).shouldBeObject(); + valueOf(module.message).shouldBe("test required module"); + } }); diff --git a/drillbit/tests/titanium.js b/drillbit/tests/titanium.js index 44b42a2972d..b84a78d4797 100644 --- a/drillbit/tests/titanium.js +++ b/drillbit/tests/titanium.js @@ -2,5 +2,9 @@ describe("Titanium module tests", { // http://jira.appcelerator.org/browse/TIMOB-4628 buildHash: function() { valueOf(Titanium.buildHash.length).shouldBe(7); + }, + userAgent: function() { + valueOf(Titanium.userAgent).shouldBeString(); + valueOf(Titanium.userAgent.indexOf("Titanium")).shouldBeNumber(); } });