diff --git a/js/xpconnect/idl/xpcIJSModuleLoader.idl b/js/xpconnect/idl/xpcIJSModuleLoader.idl index 761f2809b44c..5f66b105a188 100644 --- a/js/xpconnect/idl/xpcIJSModuleLoader.idl +++ b/js/xpconnect/idl/xpcIJSModuleLoader.idl @@ -15,7 +15,7 @@ class nsAXPCNativeCallContext; [ptr] native JSObjectPtr(JSObject); -[scriptable, uuid(243d1a31-db9f-47a1-9922-55a1ad5515fb)] +[scriptable, uuid(4f94b21f-2920-4bd9-8251-5fb60fb054b2)] interface xpcIJSModuleLoader : nsISupports { /** @@ -67,4 +67,16 @@ interface xpcIJSModuleLoader : nsISupports * then this method will do nothing. */ void unload(in AUTF8String aResourceURI); + + /** + * Returns true if the js file located at 'registryLocation' location has + * been loaded previously via the import method above. Returns false + * otherwise. + * + * @param resourceURI A resource:// URI string representing the location of + * the js file to be checked if it is already loaded or not. + * @returns boolean, true if the js file has been loaded via import. false + * otherwise + */ + boolean isModuleLoaded(in AUTF8String aResourceURI); }; diff --git a/js/xpconnect/idl/xpccomponents.idl b/js/xpconnect/idl/xpccomponents.idl index 2ccf9a982d0a..2d8221598616 100644 --- a/js/xpconnect/idl/xpccomponents.idl +++ b/js/xpconnect/idl/xpccomponents.idl @@ -21,7 +21,7 @@ interface nsIStackFrame; * interface of Components.interfacesByID * (interesting stuff only reflected into JavaScript) */ -[scriptable, uuid(c99cffac-5aed-4267-ad2f-f4a4c9d4a081)] +[scriptable, uuid(f235ef76-9919-478b-aa0f-282d994ddf76)] interface nsIXPCComponents_InterfacesByID : nsISupports { }; @@ -217,6 +217,18 @@ interface nsIXPCComponents_Utils : nsISupports [implicit_jscontext,optional_argc] jsval import(in AUTF8String aResourceURI, [optional] in jsval targetObj); + /** + * Returns true if the js file located at 'registryLocation' location has + * been loaded previously via the import method above. Returns false + * otherwise. + * + * @param resourceURI A resource:// URI string representing the location of + * the js file to be checked if it is already loaded or not. + * @returns boolean, true if the js file has been loaded via import. false + * otherwise + */ + boolean isModuleLoaded(in AUTF8String aResourceURI); + /* * Unloads the JS module at 'registryLocation'. Existing references to the * module will continue to work but any subsequent import of the module will diff --git a/js/xpconnect/loader/mozJSComponentLoader.cpp b/js/xpconnect/loader/mozJSComponentLoader.cpp index 183ee9a9e30a..9bfe1eab5174 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -1210,6 +1210,27 @@ mozJSComponentLoader::ImportInto(const nsACString &aLocation, return NS_OK; } +/* boolean isModuleLoaded (in AUTF8String registryLocation); */ +NS_IMETHODIMP +mozJSComponentLoader::IsModuleLoaded(const nsACString& aLocation, + bool *retval) +{ + MOZ_ASSERT(nsContentUtils::IsCallerChrome()); + + nsresult rv; + if (!mInitialized) { + rv = ReallyInit(); + NS_ENSURE_SUCCESS(rv, rv); + } + + ComponentLoaderInfo info(aLocation); + rv = info.EnsureKey(); + NS_ENSURE_SUCCESS(rv, rv); + + *retval = !!mImports.Get(info.Key()); + return NS_OK; +} + nsresult mozJSComponentLoader::ImportInto(const nsACString &aLocation, HandleObject targetObj, diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 525aa73a7f93..9da28aaae75b 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -2724,6 +2724,18 @@ nsXPCComponents_Utils::Import(const nsACString& registryLocation, return moduleloader->Import(registryLocation, targetObj, cx, optionalArgc, retval); } +/* boolean isModuleLoaded (in AUTF8String registryLocation); + */ +NS_IMETHODIMP +nsXPCComponents_Utils::IsModuleLoaded(const nsACString& registryLocation, bool *retval) +{ + nsCOMPtr moduleloader = + do_GetService(MOZJSCOMPONENTLOADER_CONTRACTID); + if (!moduleloader) + return NS_ERROR_FAILURE; + return moduleloader->IsModuleLoaded(registryLocation, retval); +} + /* unload (in AUTF8String registryLocation); */ NS_IMETHODIMP diff --git a/js/xpconnect/tests/unit/test_isModuleLoaded.js b/js/xpconnect/tests/unit/test_isModuleLoaded.js new file mode 100644 index 000000000000..f08bf2def525 --- /dev/null +++ b/js/xpconnect/tests/unit/test_isModuleLoaded.js @@ -0,0 +1,33 @@ +const Cu = Components.utils; + +function run_test() { + // Existing module. + do_check_true(!Cu.isModuleLoaded("resource://gre/modules/devtools/LayoutHelpers.jsm"), + "isModuleLoaded returned correct value for non-loaded module"); + Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm"); + do_check_true(Cu.isModuleLoaded("resource://gre/modules/devtools/LayoutHelpers.jsm"), + "isModuleLoaded returned true after loading that module"); + Cu.unload("resource://gre/modules/devtools/LayoutHelpers.jsm"); + do_check_true(!Cu.isModuleLoaded("resource://gre/modules/devtools/LayoutHelpers.jsm"), + "isModuleLoaded returned false after unloading that module"); + + // Non-existing module + do_check_true(!Cu.isModuleLoaded("resource://gre/modules/devtools/LayoutHelpers1.jsm"), + "isModuleLoaded returned correct value for non-loaded module"); + try { + Cu.import("resource://gre/modules/devtools/LayoutHelpers1.jsm"); + do_check_true(false, + "Should have thrown while trying to load a non existing file"); + } catch (ex) {} + do_check_true(!Cu.isModuleLoaded("resource://gre/modules/devtools/LayoutHelpers1.jsm"), + "isModuleLoaded returned correct value for non-loaded module"); + + // incorrect url + try { + Cu.isModuleLoaded("resource://modules/devtools/LayoutHelpers1.jsm"); + do_check_true(false, + "Should have thrown while trying to load a non existing file"); + } catch (ex) { + do_check_true(true, "isModuleLoaded threw an exception while loading incorrect uri"); + } +} diff --git a/js/xpconnect/tests/unit/xpcshell.ini b/js/xpconnect/tests/unit/xpcshell.ini index f4b37d48a2ab..bfea4b1d0c5e 100644 --- a/js/xpconnect/tests/unit/xpcshell.ini +++ b/js/xpconnect/tests/unit/xpcshell.ini @@ -49,6 +49,7 @@ support-files = [test_file2.js] [test_import.js] [test_import_fail.js] +[test_isModuleLoaded.js] [test_js_weak_references.js] [test_reflect_parse.js] [test_localeCompare.js]