You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by lo...@apache.org on 2013/05/07 17:24:22 UTC

[17/51] [partial] [BlackBerry10] Added support for new platform

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/framework/lib/policy/whitelist.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/framework/lib/policy/whitelist.js b/lib/cordova-blackberry/blackberry10/framework/lib/policy/whitelist.js
new file mode 100644
index 0000000..dcfbc3c
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/framework/lib/policy/whitelist.js
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2010-2011 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var WebFolderAccess = require("./folderAccess").WebFolderAccess,
+    util = require("../utils");
+
+function _isLocalAccess(access) {
+    return access && access.uri === "WIDGET_LOCAL";
+}
+
+function _isMatch(access, requestURI) {
+    // Look for local first
+    if (_isLocalAccess(access)) {
+        // Local access always allowed
+        //THIS USED TO RETURN TRUE FOR FILE ACCESS
+        //I HAVE TURNED IT OFF BECAUSE IT MAKES NO SENSE THAT LOCAL ACCESS ALWAYS MATCHES FILE ACCESS
+        return (util.isLocalURI(requestURI));
+    } else if (util.isDataURI(requestURI)) {
+        // Check for data url
+        // data urls are allowed
+        return true;
+    }
+
+    // Based on widgets 1.0 (access control)
+    // http://www.w3.org/TR/2009/WD-widgets-access-20090618/#rfc3987
+    var refURI = util.parseUri(access.uri),
+        allowSub = access.allowSubDomain;
+
+    if (!requestURI.path) {
+        requestURI.path = "/";
+    }
+
+    // Start comparison based on widget spec.
+    // 1. Compare scheme
+    if (refURI.scheme.toLowerCase() !== requestURI.scheme.toLowerCase()) {
+        return false;
+    }
+
+    // 2. Compare host - if subdoman is false, host must match exactly
+    // (referenceURI MUST HAVE host specified - not null.)
+    // Special Case: Ignore this condition if we are dealing with file://
+    if (!requestURI.authority && !util.isFileURI(requestURI)) {
+        return false;
+    }
+
+    if (!allowSub && refURI.host.toLowerCase() !== requestURI.host.toLowerCase()) {
+        return false;
+    }
+
+    // 3. Compare host - if subdomain is true, check for subdomain or match
+    if (allowSub && !util.endsWith(requestURI.host.toLowerCase(), "." + refURI.host.toLowerCase()) &&
+        requestURI.host.toLowerCase() !== refURI.host.toLowerCase()) {
+        return false;
+    }
+
+    // 4. Compare port
+    if (refURI.port && refURI.port !== requestURI.port) {
+        return false;
+    }
+
+    // 5.  Compare path+query
+    if (!util.startsWith(requestURI.path.toLowerCase(), refURI.path.toLowerCase()) && refURI.query !== "*") {
+        return false;
+    }
+
+    return true;
+}
+
+function _getAccessForPathAndQuery(folderAccess, path, query) {
+    if (folderAccess) {
+        if (!query) {
+            return folderAccess.getAccess(path);
+        } else {
+            return folderAccess.getAccess(path + "?" + query);
+        }
+    }
+
+    return null;
+}
+
+function AccessManager(config) {
+    config = config || require("../config");
+
+    this._accessList = config.accessList;
+    this._hasGlobalAccess = config.hasMultiAccess;
+    this._authorityCollection = null;
+    this._localAccess = null;
+}
+
+AccessManager.prototype.getFolderAccess = function (scheme, authority) {
+    var key = scheme + "://" + authority;
+    key = key.toLowerCase();
+
+    if (this._authorityCollection.hasOwnProperty(key)) {
+        return this._authorityCollection[key];
+    }
+
+    return null;
+};
+
+AccessManager.prototype.putFolderAccess = function (scheme, authority, folderAccess) {
+    var key = scheme + "://" + authority;
+    key = key.toLowerCase();
+    this._authorityCollection[key] = folderAccess;
+};
+
+AccessManager.prototype.initializeAuthCollection = function () {
+    var folderAccess, currentURI, that = this;
+
+    if (!this._authorityCollection) {
+        this._authorityCollection = {};
+
+        if (this._accessList) {
+            this._accessList.forEach(function (access) {
+                if (_isLocalAccess(access)) {
+                    that._localAccess = access;
+                } else {
+                    currentURI = util.parseUri(access.uri);
+
+                    // Check the authority collection to see if the authority item
+                    // we want already exists
+                    folderAccess = that.getFolderAccess(currentURI.scheme, currentURI.authority) || new WebFolderAccess();
+
+                    // Add folder path access to the authority item
+                    if (!currentURI.query) {
+                        folderAccess.addAccess(currentURI.path, access);
+                    } else {
+                        folderAccess.addAccess(currentURI.path + "?" + currentURI.query, access);
+                    }
+
+                    that.putFolderAccess(currentURI.scheme, currentURI.authority, folderAccess);
+                }
+            });
+        }
+    }
+};
+
+AccessManager.prototype.authorityCheck = function (port, scheme, authority) {
+    var originalAuthority = authority;
+
+    if (port) {
+        // If authority has a specific port, and the collection does not have an access matches
+        // the exact authority, strip port from authority to see if there is a match
+        if (!this.getFolderAccess(scheme, authority)) {
+            authority = authority.slice(0, authority.lastIndexOf(":"));
+            authority = this.authorityCheck("", scheme, authority);
+        }
+
+        //If no successful match was found without the port, reset the authority and try with it
+        if (!this.getFolderAccess(scheme, authority)) {
+            authority = originalAuthority;
+        }
+    }
+
+    if (authority.indexOf(".") === -1) {
+        // If authority is computer name, must have exact match in collection
+        if (!this.getFolderAccess(scheme, authority)) {
+            return "";
+        }
+
+        return authority;
+    }
+
+    while (authority && !this.getFolderAccess(scheme, authority)) {
+        if (authority.indexOf(".") === -1) {
+            return "";
+        }
+        authority = authority.substring(authority.indexOf(".") + 1);
+    }
+
+    return authority;
+};
+
+AccessManager.prototype.getFromFolderAccess = function (folderAccess, requestURI) {
+    var fetchedAccess = null,
+        scheme = requestURI.scheme,
+        authority = requestURI.authority,
+        path = requestURI.path,
+        query = requestURI.query,
+        prevAuthority;
+
+    if (!path) {
+        fetchedAccess = folderAccess.getAccess("/");
+    } else {
+        fetchedAccess = _getAccessForPathAndQuery(folderAccess, path, query);
+    }
+
+    // Make sure we've got the right one
+    while (!fetchedAccess || !_isMatch(fetchedAccess, requestURI)) {
+        // There was an auth url that matched, but didnt match the folder structure
+        // Try the next level up
+        prevAuthority = authority;
+        authority = authority.substring(authority.indexOf(".") + 1);
+        //If authority hasn't changed, then this loop will continue endlessly because nothing else has changed
+        //This will happen when an element has the same authority but no folder access.
+        if (prevAuthority === authority) {
+            return null;
+        }
+
+        // Check for an authority string that has an existing key
+        authority = this.authorityCheck(requestURI.port, scheme, authority);
+        if (!authority) {
+            return null;
+        }
+
+        // Retrieve access set for the specified authority
+        folderAccess = this.getFolderAccess(scheme, authority);
+
+        // Special case: no access element was found for a file protocol request.
+        // This is added since file protocol was allowed through the above check
+        if (scheme === "file" && !folderAccess) {
+            return null;
+        }
+
+        fetchedAccess = _getAccessForPathAndQuery(folderAccess, path, query);
+    }
+
+    return fetchedAccess;
+};
+
+AccessManager.prototype.getAccessByUrl = function (url) {
+    var requestURI = util.parseUri(url),
+        authority = requestURI.authority,
+        scheme = requestURI.scheme,
+        folderAccess,
+        fetchedAccess;
+
+    if (util.isAbsoluteURI(requestURI)) {
+        // Initialize authority collection if it does not yet exist
+        this.initializeAuthCollection();
+
+        // Start with the full authority path and check if an access exists for that path
+        // If it does not exist, remove the first section of the authority path and try again
+
+        // Check for an authority string that has an existing key
+        // Special case: Allow file, and local protocol to proceed without an authority
+        authority = this.authorityCheck(requestURI.port, scheme, authority);
+        if (!authority && !(scheme === "file" || scheme === "local" || scheme === "data")) {
+            return null;
+        }
+        // Retrieve access set for the specified authority
+        folderAccess = this.getFolderAccess(scheme, authority);
+
+        // Special case: no access was found for a file protocol request
+        // This is added since file protocol was allowed through the above check
+        if (scheme === "file" && !folderAccess) {
+            return null;
+        } else if (scheme === "local" && !folderAccess) {
+            // If no access element is found with local URI, use local access for this request
+            return this._localAccess;
+        } else if (scheme === "data") {
+            // Always allow data-uris
+            return true;
+        }
+
+        fetchedAccess = this.getFromFolderAccess(folderAccess, requestURI);
+
+        if (fetchedAccess) {
+            return fetchedAccess;
+        } else if (this._localAccess && _isMatch(this._localAccess, requestURI)) {
+            // If we cannot find a more specific access for this local URI, use local access
+            return this._localAccess;
+        } else if (folderAccess && _isMatch(folderAccess, requestURI)) {
+            return folderAccess;
+        }
+    }
+
+    return null;
+};
+
+AccessManager.prototype.hasGlobalAccess = function () {
+    return this._hasGlobalAccess;
+};
+
+function Whitelist(config) {
+    this._mgr = new AccessManager(config);
+}
+
+Whitelist.prototype.getFeaturesForUrl = function (url) {
+    var access = this._mgr.getAccessByUrl(url),
+        featureIds = [];
+
+    if (access && access.features) {
+        access.features.forEach(function (elem) {
+            featureIds.push(elem.id);
+        });
+    }
+
+    return featureIds;
+};
+
+Whitelist.prototype.isFeatureAllowed = function (url, feature) {
+    var features = this.getFeaturesForUrl(url);
+
+    return !!features && features.reduce(function (found, current) {
+        return found || current === feature;
+    }, false);
+};
+
+Whitelist.prototype.isAccessAllowed = function (url, isXHR) {
+    return (this._mgr.hasGlobalAccess() && !isXHR) || !!this._mgr.getAccessByUrl(url);
+};
+
+exports.Whitelist = Whitelist;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/framework/lib/server.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/framework/lib/server.js b/lib/cordova-blackberry/blackberry10/framework/lib/server.js
new file mode 100644
index 0000000..15b95b0
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/framework/lib/server.js
@@ -0,0 +1,121 @@
+/*
+ *  Copyright 2012 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var DEFAULT_SERVICE = "default",
+    DEFAULT_ACTION = "exec";
+
+function rebuildRequest(req) {
+    var originalURL = req.params.service + "/" +
+            req.params.action +
+            (req.params.ext ? "/" + req.params.ext  : "") +
+            (req.params.method ? "/" + req.params.method : "") +
+            (req.params.args ? "?" + req.params.args : ""),
+        tokens = originalURL.split('/'),
+        //Handle the case where the method is multi-level
+        finalToken = (tokens[1] && tokens.length > 2) ? tokens.slice(1).join('/') : tokens[1],
+        args = null;
+
+    // set args
+    if (finalToken && finalToken.indexOf("?") >= 0) {
+        // Re-split args
+        args = finalToken.split("?")[1];
+    }
+
+    return {
+        params : {
+            service : DEFAULT_SERVICE,
+            action : DEFAULT_ACTION,
+            ext : tokens[0],
+            method : (finalToken && finalToken.indexOf("?") >= 0) ? finalToken.split("?")[0] : finalToken,
+            args : args
+        },
+        body : req.body,
+        origin : req.origin
+    };
+}
+
+function parseArgs(req) {
+    var args = null,
+        params;
+    // set args
+    if (req.params.args && typeof req.params.args === "string") {
+        // GET querystring to json
+        params = req.params.args.split("&");
+        if (params) {
+            args = {};
+            params.forEach(function (param) {
+                var parts = param.split("=");
+                args[parts[0]] = parts[1];
+            });
+        }
+    } else {
+        // POST body to json
+        if (req.body) {
+            args = JSON.parse(req.body);
+        }
+    }
+    req.params.args = args;
+}
+
+module.exports = {
+    handle: function (req, res, sourceWebview, config) {
+        try {
+            var pluginName = "lib/plugins/" + req.params.service,
+                plugin;
+
+            if (frameworkModules.indexOf(pluginName + ".js") === -1) {
+                pluginName = "lib/plugins/" + DEFAULT_SERVICE;
+                req = rebuildRequest(req);
+            }
+
+            parseArgs(req);
+
+            //Updating because some versions of node only work with relative paths
+            pluginName = pluginName.replace('lib', '.');
+
+            plugin = require("./utils").loadModule(pluginName);
+
+            plugin[req.params.action](req,
+            function (result) {
+                res.send(200, encodeURIComponent(JSON.stringify({
+                    code: 42,
+                    data: result
+                })));
+            },
+            function (code, error, httpCode) {
+                if (!httpCode) {
+                    httpCode = 200;
+                }
+
+                res.send(httpCode, encodeURIComponent(JSON.stringify({
+                    code: Math.abs(code) * -1 || -1,
+                    data: null,
+                    msg: error
+                })));
+            },
+            req.params.args,
+            {
+                "request": req,
+                "response": res,
+                "webview": sourceWebview,
+                "config": config
+            });
+        } catch (e) {
+            console.error(e);
+            res.send(404, "can't find the stuff");
+        }
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/framework/lib/utils.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/framework/lib/utils.js b/lib/cordova-blackberry/blackberry10/framework/lib/utils.js
new file mode 100644
index 0000000..4ab008a
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/framework/lib/utils.js
@@ -0,0 +1,549 @@
+/*
+ *  Copyright 2012 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var self,
+    exception = require('./exception');
+
+function S4() {
+    return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+}
+
+self = module.exports = {
+    validateNumberOfArguments: function (lowerBound, upperBound, numberOfArguments, customExceptionType, customExceptionMessage, customExceptionObject) {
+
+        customExceptionMessage = customExceptionMessage || "";
+
+        if (arguments.length < 3 || arguments.length > 6) {
+            exception.raise(exception.types.Argument, "Wrong number of arguments when calling: validateNumberOfArguments()");
+        }
+
+        if (isNaN(lowerBound) && isNaN(upperBound) && isNaN(numberOfArguments)) {
+            exception.raise(exception.types.ArgumentType, "(validateNumberOfArguments) Arguments are not numbers");
+        }
+
+        lowerBound = parseInt(lowerBound, 10);
+        upperBound = parseInt(upperBound, 10);
+        numberOfArguments = parseInt(numberOfArguments, 10);
+
+        if (numberOfArguments < lowerBound || numberOfArguments > upperBound) {
+            exception.raise((customExceptionType || exception.types.ArgumentLength), (customExceptionMessage + "\n\nWrong number of arguments"), customExceptionObject);
+        }
+
+    },
+
+    validateArgumentType: function (arg, argType, customExceptionType, customExceptionMessage, customExceptionObject) {
+        var invalidArg = false,
+            msg;
+
+        switch (argType) {
+        case "array":
+            if (!arg instanceof Array) {
+                invalidArg = true;
+            }
+            break;
+        case "date":
+            if (!arg instanceof Date) {
+                invalidArg = true;
+            }
+            break;
+        case "integer":
+            if (typeof arg === "number") {
+                if (arg !== Math.floor(arg)) {
+                    invalidArg = true;
+                }
+            }
+            else {
+                invalidArg = true;
+            }
+            break;
+        default:
+            if (typeof arg !== argType) {
+                invalidArg = true;
+            }
+            break;
+        }
+
+        if (invalidArg) {
+            msg = customExceptionMessage +  ("\n\nInvalid Argument type. argument: " + arg + " ==> was expected to be of type: " + argType);
+            exception.raise((customExceptionType || exception.types.ArgumentType), msg, customExceptionObject);
+        }
+    },
+
+    validateMultipleArgumentTypes: function (argArray, argTypeArray, customExceptionType, customExceptionMessage, customExceptionObject) {
+        for (var i = 0; i < argArray.length; i++) {
+            this.validateArgumentType(argArray[i], argTypeArray[i], customExceptionType, customExceptionMessage, customExceptionObject);
+        }
+    },
+
+    arrayContains: function (array, obj) {
+        var i = array.length;
+        while (i--) {
+            if (array[i] === obj) {
+                return true;
+            }
+        }
+        return false;
+    },
+
+    some: function (obj, predicate, scope) {
+        if (obj instanceof Array) {
+            return obj.some(predicate, scope);
+        }
+        else {
+            var values = self.map(obj, predicate, scope);
+
+            return self.reduce(values, function (some, value) {
+                return value ? value : some;
+            }, false);
+        }
+    },
+
+    count: function (obj) {
+        return self.sum(obj, function (total) {
+            return 1;
+        });
+    },
+
+    sum: function (obj, selector, scope) {
+        var values = self.map(obj, selector, scope);
+        return self.reduce(values, function (total, value) {
+            return total + value;
+        });
+    },
+
+    max: function (obj, selector, scope) {
+        var values = self.map(obj, selector, scope);
+        return self.reduce(values, function (max, value) {
+            return max < value ? value : max;
+        }, Number.MIN_VALUE);
+    },
+
+    min: function (obj, selector, scope) {
+        var values = self.map(obj, selector, scope);
+        return self.reduce(values, function (min, value) {
+            return min > value ? value : min;
+        }, Number.MAX_VALUE);
+    },
+
+    forEach: function (obj, action, scope) {
+        if (obj instanceof Array) {
+            return obj.forEach(action, scope);
+        }
+        else {
+            self.map(obj, action, scope);
+        }
+    },
+
+    filter: function (obj, predicate, scope) {
+        if (obj instanceof Array) {
+            return obj.filter(predicate, scope);
+        }
+        else {
+            var result = [];
+            self.forEach(obj, function (value, index) {
+                if (predicate.apply(scope, [value, index])) {
+                    result.push(value);
+                }
+
+            }, scope);
+
+            return result;
+        }
+    },
+
+    reduce: function (obj, func, init, scope) {
+        var i,
+            initial = init === undefined ? 0 : init,
+            result = initial;
+
+
+        if (obj instanceof Array) {
+            return obj.reduce(func, initial);
+        }
+        else if (obj instanceof NamedNodeMap) {
+            for (i = 0; i < obj.length; i++) {
+                result = func.apply(scope, [result, obj[i], i]);
+            }
+        }
+        else {
+            for (i in obj) {
+                if (obj.hasOwnProperty(i)) {
+                    result = func.apply(scope, [result, obj[i], i]);
+                }
+            }
+        }
+
+        return result;
+
+    },
+
+    map: function (obj, func, scope) {
+        var i,
+            returnVal = null,
+            result = [];
+
+        if (obj instanceof Array) {
+            return obj.map(func, scope);
+        }
+        else if (obj instanceof NamedNodeMap) {
+            for (i = 0; i < obj.length; i++) {
+                returnVal = func.apply(scope, [obj[i], i]);
+                result.push(returnVal);
+            }
+        }
+        else {
+            for (i in obj) {
+                if (obj.hasOwnProperty(i)) {
+                    returnVal = func.apply(scope, [obj[i], i]);
+                    result.push(returnVal);
+                }
+            }
+        }
+
+        return result;
+    },
+
+    series: function (tasks, callback) {
+
+        var execute = function () {
+            var args = [],
+                task;
+
+            if (tasks.length) {
+                task = tasks.shift();
+                args = args.concat(task.args).concat(execute);
+                task.func.apply(this, args);
+            }
+            else {
+                callback.func.apply(this, callback.args);
+            }
+        };
+
+        execute();
+    },
+
+    regexSanitize: function (regexString) {
+        return regexString.replace("^", "\\^")
+                    .replace("$", "\\$")
+                    .replace("(", "\\(")
+                    .replace(")", "\\)")
+                    .replace("<", "\\<")
+                    .replace("[", "\\[")
+                    .replace("{", "\\{")
+                    .replace(/\\/, "\\\\")
+                    .replace("|", "\\|")
+                    .replace(">", "\\>")
+                    .replace(".", "\\.")
+                    .replace("*", "\\*")
+                    .replace("+", "\\+")
+                    .replace("?", "\\?");
+    },
+
+    find: function (comparison, collection, startInx, endInx, callback) {
+        var results = [],
+            compare = function (s, pattern) {
+
+                if (typeof(s) !== "string" || pattern === null) {
+                    return s === pattern;
+                }
+
+                var regex = pattern.replace(/\./g, "\\.")
+                                   .replace(/\^/g, "\\^")
+                                   .replace(/\*/g, ".*")
+                                   .replace(/\\\.\*/g, "\\*");
+
+                regex = "^".concat(regex, "$");
+
+                return !!s.match(new RegExp(regex, "i"));
+            };
+
+        self.forEach(collection, function (c) {
+            var match,
+                fail = false;
+
+            self.forEach(comparison, function (value, key) {
+                if (!fail && value !== undefined) {
+
+                    if (compare(c[key], value)) {
+                        match = c;
+                    }
+                    else {
+                        fail = true;
+                        match = null;
+                    }
+                }
+            });
+
+            if (match) {
+                results.push(match);
+            }
+        });
+
+        if (callback) {
+            if (startInx === undefined) {
+                startInx = 0;
+            }
+            if (endInx === undefined) {
+                endInx = results.length;
+            }
+            if (startInx === endInx) {
+                endInx = startInx + 1;
+            }
+
+            callback.apply(null, [results.slice(startInx, endInx)]);
+        }
+    },
+
+    mixin: function (mixin, to) {
+        Object.getOwnPropertyNames(mixin).forEach(function (prop) {
+            if (Object.hasOwnProperty.call(mixin, prop)) {
+                Object.defineProperty(to, prop, Object.getOwnPropertyDescriptor(mixin, prop));
+            }
+        });
+        return to;
+    },
+
+    copy: function (obj) {
+        var i,
+            newObj = (obj === null ? false : global.toString.call(obj) === "[object Array]") ? [] : {};
+
+        if (typeof obj === 'number' ||
+            typeof obj === 'string' ||
+            typeof obj === 'boolean' ||
+            obj === null ||
+            obj === undefined) {
+            return obj;
+        }
+
+        if (obj instanceof Date) {
+            return new Date(obj);
+        }
+
+        if (obj instanceof RegExp) {
+            return new RegExp(obj);
+        }
+
+        for (i in obj) {
+            if (obj.hasOwnProperty(i)) {
+                if (obj[i] && typeof obj[i] === "object") {
+                    if (obj[i] instanceof Date) {
+                        newObj[i] = obj[i];
+                    }
+                    else {
+                        newObj[i] = self.copy(obj[i]);
+                    }
+                }
+                else {
+                    newObj[i] = obj[i];
+                }
+            }
+        }
+
+        return newObj;
+    },
+
+    startsWith : function (str, substr) {
+        return str.indexOf(substr) === 0;
+    },
+
+    endsWith : function (str, substr) {
+        return str.indexOf(substr, str.length - substr.length) !== -1;
+    },
+
+    parseUri : function (str) {
+        var i, uri = {},
+            key = [ "source", "scheme", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "anchor" ],
+            matcher = /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(str);
+
+        for (i = key.length - 1; i >= 0; i--) {
+            uri[key[i]] = matcher[i] || "";
+        }
+
+        return uri;
+    },
+
+    // uri - output from parseUri
+    isAbsoluteURI : function (uri) {
+        if (uri && uri.source) {
+            return uri.relative !== uri.source;
+        }
+
+        return false;
+    },
+
+    fileNameToImageMIME : function (fileName) {
+
+        var extensionsToMIME = {},
+            ext;
+
+        extensionsToMIME.png = 'image/png';
+        extensionsToMIME.jpg = 'image/jpeg';
+        extensionsToMIME.jpe = 'image/jpeg';
+        extensionsToMIME.jpeg = 'image/jpeg';
+        extensionsToMIME.gif = 'image/gif';
+        extensionsToMIME.bmp = 'image/bmp';
+        extensionsToMIME.bm = 'image/bmp';
+        extensionsToMIME.svg = 'image/svg+xml';
+        extensionsToMIME.tif = 'image/tiff';
+        extensionsToMIME.tiff = 'image/tiff';
+
+        ext = fileName.split('.').pop();
+        return extensionsToMIME[ext];
+    },
+
+    isLocalURI : function (uri) {
+        return uri && uri.scheme && "local:///".indexOf(uri.scheme.toLowerCase()) !== -1;
+    },
+
+    isFileURI : function (uri) {
+        return uri && uri.scheme && "file://".indexOf(uri.scheme.toLowerCase()) !== -1;
+    },
+
+    isHttpURI : function (uri) {
+        return uri && uri.scheme && "http://".indexOf(uri.scheme.toLowerCase()) !== -1;
+    },
+
+    isHttpsURI : function (uri) {
+        return uri && uri.scheme && "https://".indexOf(uri.scheme.toLowerCase()) !== -1;
+    },
+
+    // Checks if the specified uri starts with 'data:'
+    isDataURI : function (uri) {
+        return uri && uri.scheme && "data:".indexOf(uri.scheme.toLowerCase()) !== -1;
+    },
+
+    performExec : function (featureId, property, args) {
+        var result;
+
+        window.webworks.exec(function (data, response) {
+            result = data;
+        }, function (data, response) {
+            throw data;
+        }, featureId, property, args, true);
+
+        return result;
+    },
+
+    inNode : function () {
+        return !!require.resolve;
+    },
+
+    requireWebview : function () {
+        return require("./webview");
+    },
+    convertDataToBinary : function (data, dataEncoding) {
+        var rawData,
+            uint8Array,
+            i;
+
+        if (data) {
+            if (dataEncoding.toLowerCase() === "base64") {
+                rawData = window.atob(data);
+            }
+            else {
+                rawData = data;
+            }
+
+            uint8Array = new Uint8Array(new ArrayBuffer(rawData.length));
+
+            for (i = 0; i < uint8Array.length; i++) {
+                uint8Array[i] = rawData.charCodeAt(i);
+            }
+
+            return uint8Array.buffer;
+        }
+    },
+    getBlobWithArrayBufferAsData : function (data, dataEncoding) {
+        var rawData,
+            blobBuilderObj = new window.WebKitBlobBuilder();
+        rawData = this.convertDataToBinary(data, dataEncoding);
+        blobBuilderObj.append(rawData);
+
+        return blobBuilderObj.getBlob("arraybuffer");
+    },
+    loadModule: function (module) {
+        return require(module);
+    },
+    loadExtensionModule: function (plugin, path) {
+        if (plugin && path) {
+            return require("../plugin/" + plugin + "/" + path);
+        } else {
+            return null;
+        }
+    },
+    hasPermission: function (config, permission) {
+        if (config && config.permissions && config.permissions.length) {
+            return config.permissions.indexOf(permission) >= 0;
+        }
+
+        return false;
+    },
+    guid: function () {
+        return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
+    },
+    getURIPrefix: function () {
+        return "http://localhost:8472/";
+    },
+    translatePath: function (path) {
+        if (path.indexOf("local:///") === 0) {
+            var sourceDir = window.qnx.webplatform.getApplication().getEnv("HOME"); //leading slashes need to be removed
+            path = "file:///" + sourceDir.replace(/^\/*/, '') + "/../app/native/" + path.replace(/local:\/\/\//, '');
+        }
+        return path;
+    },
+    invokeInBrowser: function (url) {
+        var request = {
+            uri: url,
+            target: "sys.browser"
+        };
+        window.qnx.webplatform.getApplication().invocation.invoke(request);
+    },
+    isPersonal: function () {
+        return window.qnx.webplatform.getApplication().getEnv("PERIMETER") === "personal";
+    },
+    deepclone: function (obj) {
+        var newObj = obj instanceof Array ? [] : {},
+            key;
+
+        if (typeof obj === 'number' ||
+                typeof obj === 'string' ||
+                typeof obj === 'boolean' ||
+                obj === null ||
+                obj === undefined) {
+            return obj;
+        }
+
+        if (obj instanceof Date) {
+            return new Date(obj);
+        }
+
+        if (obj instanceof RegExp) {
+            return new RegExp(obj);
+        }
+
+        for (key in obj) {
+            if (obj.hasOwnProperty(key)) {
+                if (obj[key] && typeof obj[key] === "object") {
+                    newObj[key] = self.deepclone(obj[key]);
+                } else {
+                    newObj[key] = obj[key];
+                }
+            }
+        }
+
+        return newObj;
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/framework/lib/webkitEvent.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/framework/lib/webkitEvent.js b/lib/cordova-blackberry/blackberry10/framework/lib/webkitEvent.js
new file mode 100644
index 0000000..0f4bef7
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/framework/lib/webkitEvent.js
@@ -0,0 +1,87 @@
+/*
+ *  Copyright 2012 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var utils = require('./utils'),
+    exception = require('./exception'),
+    _listeners = {};
+
+function _on(eventType, listener, scope, once) {
+    if (!eventType) {
+        throw "eventType must be truthy";
+    }
+    _listeners[eventType] = _listeners[eventType] || [];
+    _listeners[eventType].push({
+        func: listener,
+        scope: scope,
+        once: !!once
+    });
+}
+
+function _trigger(listener, args, sync) {
+    try {
+        if (sync) {
+            listener.func.apply(listener.scope, args);
+        }
+        else {
+            setTimeout(function () {
+                listener.func.apply(listener.scope, args);
+            }, 1);
+        }
+    }
+    catch (e) {
+        exception.handle(e);
+    }
+}
+
+module.exports = {
+    on: function (eventType, listener, scope) {
+        _on(eventType, listener, scope, false);
+    },
+
+    once: function (eventType, listener, scope) {
+        _on(eventType, listener, scope, true);
+    },
+
+    trigger: function (eventType, args, sync) {
+        args = args || [];
+        sync = sync || false;
+
+        var listeners = _listeners[eventType];
+
+        if (listeners) {
+            listeners.forEach(function (listener) {
+                _trigger(listener, args, sync);
+            });
+
+            _listeners[eventType] = listeners.filter(function (listener) {
+                return !listener.once;
+            });
+        }
+    },
+
+    eventHasSubscriber: function (eventType) {
+        return !!_listeners[eventType];
+    },
+
+    getEventSubscribers: function (eventType) {
+        return utils.copy(_listeners[eventType]) || [];
+    },
+
+    clear: function (eventType) {
+        if (eventType) {
+            delete _listeners[eventType];
+        }
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/framework/lib/webkitHandlers/networkResourceRequested.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/framework/lib/webkitHandlers/networkResourceRequested.js b/lib/cordova-blackberry/blackberry10/framework/lib/webkitHandlers/networkResourceRequested.js
new file mode 100644
index 0000000..759c8bd
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/framework/lib/webkitHandlers/networkResourceRequested.js
@@ -0,0 +1,126 @@
+/*
+ *  Copyright 2012 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var Whitelist = require('../policy/whitelist').Whitelist,
+    ACCEPT_RESPONSE = {setAction: "ACCEPT"},
+    DENY_RESPONSE = {setAction: "DENY"},
+    SUBSTITUTE_RESPONSE = {setAction: "SUBSTITUTE"},
+    utils = require('../utils');
+
+function _formMessage(url, origin, sid, body, securityOrigin, webview) {
+    var tokens = url.split(utils.getURIPrefix())[1].split("/"),
+        //Handle the case where the method is multi-level
+        finalToken = (tokens[3] && tokens.length > 4) ? tokens.slice(3).join('/') : tokens[3];
+
+    return {
+        request : {
+            params : {
+                service : tokens[0],
+                action : tokens[1],
+                ext : tokens[2],
+                method : (finalToken && finalToken.indexOf("?") >= 0) ? finalToken.split("?")[0] : finalToken,
+                args : (finalToken && finalToken.indexOf("?") >= 0) ? finalToken.split("?")[1] : null
+            },
+            body : body,
+            origin : origin,
+            securityOrigin: securityOrigin
+
+        },
+        response : {
+            send : function (code, data) {
+                var responseText;
+                if (typeof(data) === 'string') {
+                    responseText = data;
+                } else {
+                    responseText =  JSON.stringify(data);
+                }
+
+                webview.notifyOpen(sid, code, "OK");
+                webview.notifyHeaderReceived(sid, "Access-Control-Allow-Origin", "*");
+                webview.notifyHeaderReceived(sid, "Access-Control-Allow-Origin", securityOrigin);
+                webview.notifyHeaderReceived(sid, "Access-Control-Allow-Headers", "Content-Type");
+                webview.notifyDataReceived(sid, responseText, responseText.length);
+                webview.notifyDone(sid);
+            }
+        }
+    };
+}
+
+function networkResourceRequestedHandler(value) {
+    var config = require("./../config"),
+        obj = JSON.parse(value),
+        response,
+        url = obj.url,
+        body = obj.body,
+        whitelist = new Whitelist(),
+        server,
+        message,
+        sid = obj.streamId,
+        origin = obj.referrer,
+        securityOrigin = obj.securityOrigin,
+        isXHR = obj.targetType === "TargetIsXMLHTTPRequest",
+        //Assumes its a navigation request if the target is the main frame
+        isNav = obj.targetType === "TargetIsMainFrame",
+        hasAccess = whitelist.isAccessAllowed(url, isXHR),
+        deniedMsg;
+
+    //If the URL starts with the prefix then its a request from an API
+    //In this case we will hijack and give our own response
+    //Otherwise follow whitelisting rules
+    if (url.match("^" + utils.getURIPrefix())) {
+        server = require("../server");
+        message = _formMessage(url, origin, sid, body, securityOrigin, this.webview, config);
+        response = SUBSTITUTE_RESPONSE;
+        server.handle(message.request, message.response, this.webview);
+    } else {
+        //Whitelisting will not prevent navigation, ONLY we will
+        //Except when they've disabled web security
+        if (hasAccess || !config.enableWebSecurity) {
+            response = ACCEPT_RESPONSE;
+        } else {
+            response = DENY_RESPONSE;
+            url = utils.parseUri(url);
+            deniedMsg = "Access to \"" + url.source + "\" not allowed";
+
+            console.warn(deniedMsg);
+
+            //Denied navigation requests are sent to the inApp browser rather than an alert
+            if (isNav) {
+                if (config.enableChildWebView) {
+                    this.webview.uiWebView.childwebviewcontrols.open(url.source);
+                } else {
+                    utils.invokeInBrowser(url.source);
+                }
+            } else {
+                this.webview.executeJavaScript("alert('" + deniedMsg + "')");
+            }
+        }
+    }
+
+    if (response) {
+        return JSON.stringify(response);
+    }
+}
+
+function NetworkResourceRequestHandler(webview) {
+    this.webview = webview;
+    this.networkResourceRequestedHandler = networkResourceRequestedHandler.bind(this);
+}
+
+module.exports = {
+    createHandler: function (webview) {
+        return new NetworkResourceRequestHandler(webview);
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/framework/lib/webview.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/framework/lib/webview.js b/lib/cordova-blackberry/blackberry10/framework/lib/webview.js
new file mode 100644
index 0000000..495dfbe
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/framework/lib/webview.js
@@ -0,0 +1,271 @@
+/*
+ *  Copyright 2012 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var networkResourceRequested = require('./webkitHandlers/networkResourceRequested'),
+    utils = require('./utils'),
+    config = require('./config'),
+    webkitOriginAccess = require("./policy/webkitOriginAccess"),
+    CHROME_HEIGHT = 0,
+    OUT_OF_PROCESS = 1,
+    webview,
+    _webviewObj;
+
+webview =
+    {
+    create: function (ready) {
+        _webviewObj = window.qnx.webplatform.createWebView({processId: OUT_OF_PROCESS, defaultSendEventHandlers: ['onChooseFile', 'onOpenWindow'], defaultWebEventHandlers: ['InvokeRequestEvent']}, function () {
+            //Create webkit event handlers
+            var requestObj =  networkResourceRequested.createHandler(_webviewObj);
+
+            //Bind networkResourceRequested event so that everything works
+            _webviewObj.onNetworkResourceRequested = requestObj.networkResourceRequestedHandler;
+
+            webkitOriginAccess.addWebView(_webviewObj);
+
+            _webviewObj.visible = true;
+            _webviewObj.active = true;
+            _webviewObj.zOrder = 0;
+            _webviewObj.setGeometry(0, CHROME_HEIGHT, screen.width, screen.height - CHROME_HEIGHT);
+
+            if (typeof config.backgroundColor !== 'undefined') {
+                _webviewObj.backgroundColor = config.backgroundColor;
+            }
+
+            if (typeof config.customHeaders !== 'undefined') {
+                _webviewObj.extraHttpHeaders = config.customHeaders;
+            }
+
+            if (typeof config.userAgent !== 'undefined') {
+                _webviewObj.userAgent = config.userAgent;
+            }
+
+            _webviewObj.autoDeferNetworkingAndJavaScript = config.autoDeferNetworkingAndJavaScript;
+
+            /* Catch and trigger our custom HTML dialog */
+            _webviewObj.allowWebEvent("DialogRequested");
+
+            _webviewObj.addEventListener("DocumentLoadFinished", function () {
+                // show app window if auto hide splash screen is true, OR splash screen is not specified
+                // if auto hide is set to false explicitly but no splash screen is specified, should still show app window
+                // otherwise the app cannot be launched
+                if (config.autoHideSplashScreen || !config["rim:splash"]) {
+                    window.qnx.webplatform.getApplication().windowVisible = true;
+                }
+            });
+
+
+            if (ready && typeof ready === 'function') {
+                ready();
+            }
+
+            window.qnx.webplatform.getController().dispatchEvent("webview.initialized", [_webviewObj]);
+
+            // If content is not loaded, too bad open the visibility up.
+            setTimeout(function () {
+                if (config.autoHideSplashScreen || !config["rim:splash"]) {
+                    window.qnx.webplatform.getApplication().windowVisible = true;
+                }
+            }, 2500);
+        });
+
+    },
+
+    destroy: function () {
+        _webviewObj.destroy();
+    },
+
+    setURL: function (url) {
+        _webviewObj.url = url;
+    },
+
+    reload: function () {
+        _webviewObj.reload();
+    },
+
+    executeJavascript: function (js) {
+        _webviewObj.executeJavaScript(js);
+    },
+
+    addEventListener: function (eventName, callback) {
+        _webviewObj.addEventListener(eventName, callback);
+    },
+
+    removeEventListener: function (eventName, callback) {
+        _webviewObj.removeEventListener(eventName, callback);
+    },
+
+    windowGroup: function () {
+        return _webviewObj.windowGroup;
+    },
+
+    getGeometry: function () {
+        return this.geometry;
+    },
+
+    setGeometry: function (x, y, width, height) {
+        this.geometry = {x: x, y: y, w: width, h: height};
+        _webviewObj.setGeometry(x, y, width, height);
+    },
+
+    setApplicationOrientation: function (angle) {
+        _webviewObj.setApplicationOrientation(angle);
+    },
+
+    setExtraPluginDirectory: function (directory) {
+        _webviewObj.setExtraPluginDirectory(directory);
+    },
+
+    setEnablePlugins: function (enablePlugins) {
+        _webviewObj.pluginsEnabled = enablePlugins;
+    },
+
+    getEnablePlugins: function () {
+        return _webviewObj.pluginsEnabled;
+    },
+
+    notifyApplicationOrientationDone: function () {
+        _webviewObj.notifyApplicationOrientationDone();
+    },
+
+    setSandbox: function (sandbox) {
+        _webviewObj.setFileSystemSandbox = sandbox;
+    },
+
+    getSandbox: function () {
+        return _webviewObj.setFileSystemSandbox;
+    },
+
+    downloadURL: function (url) {
+        _webviewObj.downloadURL(url);
+    },
+
+    handleContextMenuResponse: function (action) {
+        _webviewObj.handleContextMenuResponse(action);
+    },
+
+    allowGeolocation : function (url) {
+        _webviewObj.allowGeolocation(url);
+    },
+
+    disallowGeolocation : function (url) {
+        _webviewObj.disallowGeolocation(url);
+
+    },
+
+    addKnownSSLCertificate: function (url, certificateInfo) {
+        _webviewObj.addKnownSSLCertificate(url, certificateInfo);
+    },
+
+    continueSSLHandshaking: function (streamId, SSLAction) {
+        _webviewObj.continueSSLHandshaking(streamId, SSLAction);
+    },
+
+    getSensitivity: function () {
+        return _webviewObj.getSensitivity();
+    },
+
+    setSensitivity: function (sensitivity) {
+        return _webviewObj.setSensitivity(sensitivity);
+    },
+
+    getBackgroundColor: function () {
+        return _webviewObj.getBackgroundColor();
+    },
+
+    setBackgroundColor: function (backgroundColor) {
+        return _webviewObj.setBackgroundColor(backgroundColor);
+    },
+
+    getWebViewObj: function (webview) {
+        return _webviewObj;
+    },
+
+    setUIWebViewObj: function (webviewObj) {
+        _webviewObj.uiWebView = webviewObj;
+    },
+
+    allowUserMedia: function (evtId, cameraName) {
+        _webviewObj.allowUserMedia(evtId, cameraName);
+    },
+
+    disallowUserMedia: function (evtId) {
+        _webviewObj.disallowUserMedia(evtId);
+    }
+};
+
+webview.__defineGetter__('id', function () {
+    if (_webviewObj) {
+        return _webviewObj.id;
+    }
+});
+
+webview.__defineGetter__('enableCrossSiteXHR', function () {
+    return _webviewObj.enableCrossSiteXHR;
+});
+
+webview.__defineSetter__('enableCrossSiteXHR', function (shouldEnable) {
+    _webviewObj.enableCrossSiteXHR = !!shouldEnable;
+});
+
+webview.__defineGetter__('processId', function () {
+    return _webviewObj.processId;
+});
+
+webview.__defineSetter__('onOpenWindow', function (input) {
+    _webviewObj.onOpenWindow = input;
+});
+
+webview.__defineSetter__('onCloseWindow', function (input) {
+    _webviewObj.onCloseWindow = input;
+});
+
+webview.__defineSetter__('onDestroyWindow', function (input) {
+    _webviewObj.onDestroyWindow = input;
+});
+
+webview.__defineSetter__('onDialogRequested', function (input) {
+    _webviewObj.onDialogRequested = input;
+});
+
+webview.__defineSetter__('onGeolocationPermissionRequest', function (input) {
+    _webviewObj.onGeolocationPermissionRequest = input;
+});
+
+webview.__defineSetter__('onSSLHandshakingFailed', function (input) {
+    _webviewObj.onSSLHandshakingFailed = input;
+});
+
+webview.__defineSetter__('onPropertyCurrentContextEvent', function (input) {
+    _webviewObj.onPropertyCurrentContextEvent = input;
+});
+
+webview.__defineSetter__('onContextMenuRequestEvent', function (input) {
+    _webviewObj.onContextMenuRequestEvent = input;
+});
+
+webview.__defineSetter__('onContextMenuCancelEvent', function (input) {
+    _webviewObj.onContextMenuCancelEvent = input;
+});
+
+webview.__defineSetter__('onUserMediaRequest', function (input) {
+    _webviewObj.onUserMediaRequest = input;
+});
+
+webview.__defineSetter__('onChildWindowOpen', function (input) {
+    _webviewObj.onChildWindowOpen = input;
+});
+
+module.exports = webview;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/config.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/config.js b/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/config.js
new file mode 100644
index 0000000..64e8f7e
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/config.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010-2011 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var srcPath = __dirname + '/../../../lib/';
+
+describe("Config", function () {
+    var config = require(srcPath + 'config.js');
+
+    it("verify user value is correctly mixed", function () {
+        expect(config.copyright).toEqual("@Rebecca");
+    });
+
+    it("verify default value is correctly mixed", function () {
+        expect(config.widgetExtensions).toEqual(null);
+    });
+
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/controllerWebView.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/controllerWebView.js b/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/controllerWebView.js
new file mode 100644
index 0000000..003d276
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/controllerWebView.js
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2010-2012 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+describe("controllerWebView", function () {
+    var controllerWebView = require('./../../../lib/controllerWebView'),
+        mockedController,
+        mockedInvocation,
+        mockedApplication;
+
+    beforeEach(function () {
+        mockedController = {
+            id: 42,
+            enableWebInspector: null,
+            enableCrossSiteXHR: null,
+            visible: null,
+            active: null,
+            setGeometry: jasmine.createSpy(),
+            setApplicationOrientation: jasmine.createSpy(),
+            notifyApplicationOrientationDone: jasmine.createSpy(),
+            publishRemoteFunction: jasmine.createSpy(),
+            dispatchEvent : jasmine.createSpy()
+        };
+        mockedInvocation = {
+            queryTargets: function (request, callback) {
+                callback("error", "results");
+            }
+        };
+        mockedApplication = {
+            invocation: mockedInvocation
+        };
+        GLOBAL.window = {
+            qnx: {
+                webplatform: {
+                    getController: function () {
+                        return mockedController;
+                    },
+                    getApplication: function () {
+                        return mockedApplication;
+                    }
+                }
+            }
+        };
+        GLOBAL.screen = {
+            width : 1024,
+            height: 768
+        };
+    });
+
+    describe("init", function () {
+        it("sets up the controllerWebview", function () {
+            controllerWebView.init({debugEnabled: true});
+            expect(mockedController.enableWebInspector).toEqual(true);
+            expect(mockedController.enableCrossSiteXHR).toEqual(true);
+            expect(mockedController.visible).toEqual(false);
+            expect(mockedController.active).toEqual(false);
+            expect(mockedController.setGeometry).toHaveBeenCalledWith(0, 0, screen.width, screen.height);
+        });
+
+        it("tests that the dispatch function is called properly", function () {
+            controllerWebView.init({debugEnabled: true});
+            controllerWebView.dispatchEvent('Awesome Event', ['these are agruments', 'another argument']);
+            expect(mockedController.dispatchEvent).toHaveBeenCalledWith('Awesome Event', ['these are agruments', 'another argument']);
+        });
+    });
+
+    describe("id", function () {
+        it("can get the id for the webiew", function () {
+            controllerWebView.init({debugEnabled: true});
+            expect(controllerWebView.id).toEqual(mockedController.id);
+        });
+    });
+
+    describe("geometry", function () {
+        it("can set geometry", function () {
+            controllerWebView.init({debugEnabled: true});
+            controllerWebView.setGeometry(0, 0, 100, 200);
+            expect(mockedController.setGeometry).toHaveBeenCalledWith(0, 0, 100, 200);
+        });
+    });
+
+    describe("application orientation", function () {
+        it("can set application orientation", function () {
+            controllerWebView.init({debugEnabled: true});
+            controllerWebView.setApplicationOrientation(90);
+            expect(mockedController.setApplicationOrientation).toHaveBeenCalledWith(90);
+        });
+
+        it("can notifyApplicationOrientationDone", function () {
+            controllerWebView.init({debugEnabled: true});
+            controllerWebView.notifyApplicationOrientationDone();
+            expect(mockedController.notifyApplicationOrientationDone).toHaveBeenCalled();
+        });
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/event.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/event.js b/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/event.js
new file mode 100644
index 0000000..3d3e7fe
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/event.js
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2010-2011 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var libRoot = __dirname + "/../../../lib/";
+
+describe("lib/event", function () {
+    var event = require(libRoot + "event"),
+        webview = require(libRoot + "webview"),
+        mockedWebview;
+
+    beforeEach(function () {
+        spyOn(webview, "executeJavascript");
+        mockedWebview = {
+            executeJavaScript: jasmine.createSpy(),
+            id: (new Date()).getTime()
+        };
+    });
+
+    describe("trigger", function () {
+
+
+        it("will trigger on the content webview when no webview is registered (for backwards compatability)", function () {
+            event.trigger("foo", {"id": 123});
+            expect(mockedWebview.executeJavaScript).not.toHaveBeenCalled();
+            expect(webview.executeJavascript).toHaveBeenCalled();
+        });
+
+        it("can invoke the webview execute javascript", function () {
+            var data = {"id": 123};
+            event.add({event: "foo", context: {addEventListener: jasmine.createSpy()}}, mockedWebview);
+            event.trigger("foo", data);
+            expect(mockedWebview.executeJavaScript).toHaveBeenCalledWith("webworks.event.trigger('foo', '" + escape(encodeURIComponent(JSON.stringify([data]))) + "')");
+            expect(webview.executeJavascript).not.toHaveBeenCalled();
+            this.after(function () {
+                event.remove({event: "foo", context: {removeEventListener: jasmine.createSpy()}}, mockedWebview);
+            });
+        });
+
+        it("sends multiple arguments passed in across as a JSONified array", function () {
+            var args = [{"id": 123, "foo": "hello world", list: [1, 2, 3]}, "Grrrrrrr", "Arrrrg"];
+            event.add({event: "foo", context: {addEventListener: jasmine.createSpy()}}, mockedWebview);
+            event.trigger.apply(null, ["foo"].concat(args));
+            expect(mockedWebview.executeJavaScript).toHaveBeenCalledWith("webworks.event.trigger('foo', '" + escape(encodeURIComponent(JSON.stringify(args))) + "')");
+            expect(webview.executeJavascript).not.toHaveBeenCalled();
+            this.after(function () {
+                event.remove({event: "foo", context: {removeEventListener: jasmine.createSpy()}}, mockedWebview);
+            });
+        });
+
+        it("invokes on all webviews that have registered, but not those removed", function () {
+            var mockedWebview2 = {
+                    executeJavaScript: jasmine.createSpy(),
+                    id: mockedWebview.id - 42
+                },
+                mockedWebview3 = {
+                    executeJavaScript: jasmine.createSpy(),
+                    id: mockedWebview.id + 42
+                },
+                mockedWebview4 = {
+                    executeJavaScript: jasmine.createSpy(),
+                    id: mockedWebview.id * 42
+                };
+            event.add({event: "foo", context: {addEventListener: jasmine.createSpy()}}, mockedWebview);
+            event.add({event: "foo", context: {addEventListener: jasmine.createSpy()}}, mockedWebview2);
+            event.add({event: "foo", context: {addEventListener: jasmine.createSpy()}}, mockedWebview3);
+            event.trigger("foo", {"id": 123});
+            expect(mockedWebview.executeJavaScript).toHaveBeenCalledWith("webworks.event.trigger('foo', '" + escape(encodeURIComponent(JSON.stringify([{"id": 123}]))) + "')");
+            expect(mockedWebview2.executeJavaScript).toHaveBeenCalledWith("webworks.event.trigger('foo', '" + escape(encodeURIComponent(JSON.stringify([{"id": 123}]))) + "')");
+            expect(mockedWebview3.executeJavaScript).toHaveBeenCalledWith("webworks.event.trigger('foo', '" + escape(encodeURIComponent(JSON.stringify([{"id": 123}]))) + "')");
+            expect(mockedWebview4.executeJavaScript).not.toHaveBeenCalledWith("webworks.event.trigger('foo', '" + escape(encodeURIComponent(JSON.stringify([{"id": 123}]))) + "')");
+            expect(webview.executeJavascript).not.toHaveBeenCalled();
+
+
+            event.remove({event: "foo", context: {removeEventListener: jasmine.createSpy()}}, mockedWebview3);
+            mockedWebview.executeJavaScript.reset();
+            mockedWebview2.executeJavaScript.reset();
+            mockedWebview3.executeJavaScript.reset();
+            mockedWebview4.executeJavaScript.reset();
+            event.trigger("foo", {"id": 123});
+            expect(mockedWebview.executeJavaScript).toHaveBeenCalledWith("webworks.event.trigger('foo', '" + escape(encodeURIComponent(JSON.stringify([{"id": 123}]))) + "')");
+            expect(mockedWebview2.executeJavaScript).toHaveBeenCalledWith("webworks.event.trigger('foo', '" + escape(encodeURIComponent(JSON.stringify([{"id": 123}]))) + "')");
+            expect(mockedWebview3.executeJavaScript).not.toHaveBeenCalledWith("webworks.event.trigger('foo', '" + escape(encodeURIComponent(JSON.stringify([{"id": 123}]))) + "')");
+            expect(mockedWebview4.executeJavaScript).not.toHaveBeenCalledWith("webworks.event.trigger('foo', '" + escape(encodeURIComponent(JSON.stringify([{"id": 123}]))) + "')");
+            expect(webview.executeJavascript).not.toHaveBeenCalled();
+            this.after(function () {
+                event.remove({event: "foo", context: {removeEventListener: jasmine.createSpy()}}, mockedWebview);
+                event.remove({event: "foo", context: {removeEventListener: jasmine.createSpy()}}, mockedWebview2);
+            });
+        });
+
+    });
+
+    describe("add/remove would invoke action context", function () {
+        var action = {
+                context: {
+                    addEventListener: jasmine.createSpy(),
+                    removeEventListener: jasmine.createSpy()
+                },
+                event: "HELLO",
+                trigger: function () {}
+            };
+
+        beforeEach(function () {
+            action.context.addEventListener.reset();
+            action.context.removeEventListener.reset();
+        });
+
+        it("can invoke action context add listener", function () {
+            event.add(action, mockedWebview);
+            expect(action.context.addEventListener).toHaveBeenCalledWith(action.event, action.trigger);
+        });
+
+        it("will not invoke action context add listener when the action has a once field", function () {
+            action.once = true;
+            event.add(action, mockedWebview);
+            expect(action.context.addEventListener).not.toHaveBeenCalledWith(action.event, action.trigger);
+            this.after(function () {
+                delete action.once;
+            });
+        });
+
+        it("can invoke action context remove listener", function () {
+            event.remove(action, mockedWebview);
+            expect(action.context.removeEventListener).toHaveBeenCalledWith(action.event, action.trigger);
+        });
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/events/applicationEvents.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/events/applicationEvents.js b/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/events/applicationEvents.js
new file mode 100644
index 0000000..81fa2e1
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/events/applicationEvents.js
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2010-2011 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var _libDir = __dirname + "./../../../../lib/",
+    appEventPrefix = "application.",
+    appEvents,
+    mockedApplication;
+
+describe("lib/events/applicationEvents", function () {
+    beforeEach(function () {
+        mockedApplication = {
+            addEventListener: jasmine.createSpy("application addEventListener"),
+            removeEventListener: jasmine.createSpy("application removeEventListener")
+        };
+        GLOBAL.window = {
+            qnx: {
+                webplatform: {
+                    getApplication: function () {
+                        return mockedApplication;
+                    }
+                }
+            }
+        };
+        appEvents = require(_libDir + "events/applicationEvents");
+    });
+
+    afterEach(function () {
+        mockedApplication = null;
+        delete GLOBAL.window;
+        appEvents = null;
+        delete require.cache[require.resolve(_libDir + "events/applicationEvents")];
+    });
+
+    describe("addEventListener", function () {
+        it("adds event name with application prepended", function () {
+            var eventName = "MostAwesomeEventEver",
+                trigger = function () {};
+            appEvents.addEventListener(eventName, trigger);
+            expect(mockedApplication.addEventListener).toHaveBeenCalledWith(appEventPrefix + eventName, trigger);
+        });
+
+        it("warns in the console if the eventName is falsey", function () {
+            var eventName = false,
+                trigger = function () {};
+            spyOn(console, "warn");
+            appEvents.addEventListener(eventName, trigger);
+            expect(mockedApplication.addEventListener).not.toHaveBeenCalledWith(appEventPrefix + eventName, trigger);
+            expect(console.warn).toHaveBeenCalledWith(jasmine.any(String));
+        });
+    });
+
+    describe("removeEventListener", function () {
+        it("adds event name with application prepended", function () {
+            var eventName = "MostAwesomeEventEver",
+                trigger = function () {};
+            appEvents.removeEventListener(eventName, trigger);
+            expect(mockedApplication.removeEventListener).toHaveBeenCalledWith(appEventPrefix + eventName, trigger);
+        });
+
+        it("warns in the console if the eventName is falsey", function () {
+            var eventName = false,
+                trigger = function () {};
+            spyOn(console, "warn");
+            appEvents.removeEventListener(eventName, trigger);
+            expect(mockedApplication.removeEventListener).not.toHaveBeenCalledWith(appEventPrefix + eventName, trigger);
+            expect(console.warn).toHaveBeenCalledWith(jasmine.any(String));
+        });
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/events/deviceEvents.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/events/deviceEvents.js b/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/events/deviceEvents.js
new file mode 100644
index 0000000..2e55455
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/events/deviceEvents.js
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010-2011 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var _libDir = __dirname + "./../../../../lib/",
+    deviceEventPrefix = "device.",
+    deviceEvents;
+
+describe("lib/events/deviceEvents", function () {
+    beforeEach(function () {
+        GLOBAL.window = {
+            qnx: {
+                webplatform: {
+                    device: {
+                        addEventListener: jasmine.createSpy(),
+                        removeEventListener: jasmine.createSpy()
+                    }
+                }
+            }
+        };
+        deviceEvents = require(_libDir + "events/deviceEvents");
+    });
+
+    afterEach(function () {
+        delete GLOBAL.window;
+        deviceEvents = null;
+        delete require.cache[require.resolve(_libDir + "events/deviceEvents")];
+    });
+
+    describe("addEventListener", function () {
+        it("adds event name with application prepended", function () {
+            var eventName = "MostAwesomeEventEver",
+                trigger = function () {};
+            deviceEvents.addEventListener(eventName, trigger);
+            expect(window.qnx.webplatform.device.addEventListener).toHaveBeenCalledWith(deviceEventPrefix + eventName, trigger);
+        });
+
+        it("warns in the console if the eventName is falsey", function () {
+            var eventName = false,
+                trigger = function () {};
+            spyOn(console, "warn");
+            deviceEvents.addEventListener(eventName, trigger);
+            expect(window.qnx.webplatform.device.addEventListener).not.toHaveBeenCalledWith(deviceEventPrefix + eventName, trigger);
+            expect(console.warn).toHaveBeenCalledWith(jasmine.any(String));
+        });
+    });
+
+    describe("removeEventListener", function () {
+        it("adds event name with application prepended", function () {
+            var eventName = "MostAwesomeEventEver",
+                trigger = function () {};
+            deviceEvents.removeEventListener(eventName, trigger);
+            expect(window.qnx.webplatform.device.removeEventListener).toHaveBeenCalledWith(deviceEventPrefix + eventName, trigger);
+        });
+
+        it("warns in the console if the eventName is falsey", function () {
+            var eventName = false,
+                trigger = function () {};
+            spyOn(console, "warn");
+            deviceEvents.removeEventListener(eventName, trigger);
+            expect(window.qnx.webplatform.device.removeEventListener).not.toHaveBeenCalledWith(deviceEventPrefix + eventName, trigger);
+            expect(console.warn).toHaveBeenCalledWith(jasmine.any(String));
+        });
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6831bed4/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/framework.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/framework.js b/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/framework.js
new file mode 100644
index 0000000..312dd8b
--- /dev/null
+++ b/lib/cordova-blackberry/blackberry10/framework/test/unit/lib/framework.js
@@ -0,0 +1,429 @@
+/*
+ * Copyright 2010-2011 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var srcPath = __dirname + '/../../../lib/',
+    config = require(srcPath + "config"),
+    framework,
+    webview,
+    overlayWebView,
+    overlayWebViewObj,
+    controllerWebView,
+    Whitelist = require(srcPath + 'policy/whitelist').Whitelist,
+    mockedController,
+    mockedApplicationWindow,
+    mockedApplication,
+    mockedDevice,
+    mockedQnx,
+    mock_request = {
+        url: "http://www.dummy.com",
+        allow: jasmine.createSpy(),
+        deny: jasmine.createSpy()
+    };
+
+describe("framework", function () {
+    beforeEach(function () {
+        mockedController = {
+            id: 42,
+            enableCrossSiteXHR: undefined,
+            visible: undefined,
+            active: undefined,
+            zOrder: undefined,
+            url: undefined,
+            setGeometry: jasmine.createSpy(),
+            onNetworkResourceRequested: undefined,
+            destroy: jasmine.createSpy(),
+            executeJavaScript: jasmine.createSpy(),
+            windowGroup: undefined,
+            addEventListener: jasmine.createSpy(),
+            uiWebView: undefined,
+            onChildWindowOpen: undefined
+        };
+        mockedApplicationWindow = {
+            visible: undefined
+        };
+        mockedApplication = {
+            addEventListener: jasmine.createSpy(),
+            webInspectorPort : "1337",
+            invocation: {
+                invoke: jasmine.createSpy()
+            }
+        };
+        mockedDevice = {
+            getNetworkInterfaces : jasmine.createSpy()
+        };
+        mockedQnx = {
+            callExtensionMethod : function () {
+                return 42;
+            },
+            webplatform : {
+                getController : function () {
+                    return mockedController;
+                },
+                getApplication : function () {
+                    return mockedApplication;
+                },
+                getApplicationWindow : function () {
+                    return mockedApplicationWindow;
+                },
+                device : mockedDevice,
+                nativeCall: jasmine.createSpy("qnx.webplatform.nativeCall")
+            }
+        };
+        GLOBAL.window = {
+            qnx: mockedQnx
+        };
+        GLOBAL.qnx = mockedQnx;
+        GLOBAL.NamedNodeMap = function () {};
+
+        delete require.cache[require.resolve(srcPath + "webview")];
+        webview = require(srcPath + "webview");
+        delete require.cache[require.resolve(srcPath + "overlayWebView")];
+        overlayWebView = require(srcPath + "overlayWebView");
+        delete require.cache[require.resolve(srcPath + "controllerWebView")];
+        controllerWebView = require(srcPath + "controllerWebView");
+
+        spyOn(webview, "create").andCallFake(function (done) {
+            done();
+        });
+
+        spyOn(overlayWebView, "getWebViewObj").andCallFake(function () {
+            overlayWebViewObj = {
+                formcontrol: {
+                    subscribeTo: jasmine.createSpy()
+                }
+            };
+            return overlayWebViewObj;
+        });
+
+        spyOn(overlayWebView, "create").andCallFake(function (done) {
+            done();
+        });
+
+        spyOn(controllerWebView, "init");
+        spyOn(controllerWebView, "dispatchEvent");
+        spyOn(webview, "destroy");
+        spyOn(webview, "executeJavascript");
+        spyOn(webview, "setURL");
+        spyOn(webview, "setUIWebViewObj");
+        spyOn(webview, "addEventListener").andCallFake(function (eventName, callback) {
+            callback();
+        });
+        spyOn(webview, "removeEventListener");
+
+        spyOn(overlayWebView, "setURL");
+        spyOn(overlayWebView, "renderContextMenuFor");
+        spyOn(overlayWebView, "handleDialogFor");
+        spyOn(overlayWebView, "addEventListener").andCallFake(function (eventName, callback) {
+            callback();
+        });
+        spyOn(overlayWebView, "removeEventListener");
+        spyOn(overlayWebView, "bindAppWebViewToChildWebViewControls");
+
+        delete require.cache[require.resolve(srcPath + "framework")];
+        framework = require(srcPath + 'framework');
+    });
+
+    afterEach(function () {
+        delete GLOBAL.blackberry;
+        delete GLOBAL.window;
+        delete GLOBAL.qnx;
+        delete GLOBAL.NamedNodeMap;
+    });
+
+    it("can start a webview instance", function () {
+        framework.start();
+        expect(controllerWebView.init).toHaveBeenCalled();
+        expect(webview.create).toHaveBeenCalled();
+    });
+
+    it("on start passing callback and setting object parameters to create method of webview", function () {
+        framework.start();
+        expect(webview.create).toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Object));
+    });
+
+    it("setting object should have debugEnabled to be defined", function () {
+        framework.start();
+        expect((webview.create.mostRecentCall.args)[1].debugEnabled).toBeDefined();
+    });
+
+    it("can start a webview instance with a url", function () {
+        var url = "http://www.google.com";
+        framework.start(url);
+        expect(webview.setURL).toHaveBeenCalledWith(url);
+    });
+
+    it("can stop a webview instance", function () {
+        framework.start();
+        framework.stop();
+        expect(webview.destroy).toHaveBeenCalled();
+    });
+
+    describe('creating the overlay webview', function () {
+        beforeEach(function () {
+            framework.start();
+        });
+        it('calls overlayWebView.create', function () {
+            expect(overlayWebView.create).toHaveBeenCalled();
+        });
+
+        it('sets the overlayWebView URL', function () {
+            expect(overlayWebView.setURL).toHaveBeenCalledWith("local:///chrome/ui.html");
+        });
+
+        it('calls renderContextMenuFor passing the webview', function () {
+            expect(overlayWebView.renderContextMenuFor).toHaveBeenCalledWith(webview);
+        });
+
+        it('calls handleDialogFor passing the webview', function () {
+            expect(overlayWebView.handleDialogFor).toHaveBeenCalledWith(webview);
+        });
+
+        it('dispatches the ui.init event on the controllerWebView', function () {
+            expect(controllerWebView.dispatchEvent).toHaveBeenCalledWith('ui.init', null);
+        });
+    });
+
+    describe('configuring webSecurity', function () {
+        var enableCrossSiteXHRSetter;
+
+        beforeEach(function () {
+            enableCrossSiteXHRSetter = jasmine.createSpy();
+            Object.defineProperty(webview, "enableCrossSiteXHR", {set: enableCrossSiteXHRSetter, configurable: true});
+        });
+
+        afterEach(function () {
+            delete webview.enableCrossSiteXHR;
+            delete require.cache[require.resolve(srcPath + "webview")];
+            webview = require(srcPath + "webview");
+        });
+
+        it('does not call enableCrossSiteXHR by default', function () {
+            expect(config.enableWebSecurity).toBe(true);
+            framework.start();
+
+            expect(enableCrossSiteXHRSetter).not.toHaveBeenCalledWith(true);
+        });
+
+        it('does enable crossSiteXHR when the config says too', function () {
+            delete require.cache[require.resolve(srcPath + "config")];
+            config = require(srcPath + 'config');
+            config.enableWebSecurity = false;
+
+            //reload config in framework
+            delete require.cache[require.resolve(srcPath + "framework")];
+            framework = require(srcPath + 'framework');
+
+            this.after(function () {
+                delete require.cache[require.resolve(srcPath + "config")];
+                config = require(srcPath + 'config');
+
+                delete require.cache[require.resolve(srcPath + "framework")];
+                framework = require(srcPath + 'framework');
+            });
+
+            expect(config.enableWebSecurity).toBe(false);
+            framework.start();
+
+            expect(enableCrossSiteXHRSetter).toHaveBeenCalledWith(true);
+        });
+    });
+
+    describe('configuring OpenChildWindow events', function () {
+        var onChildWindowOpenHandler;
+
+        beforeEach(function () {
+            Object.defineProperty(webview, "onChildWindowOpen", {set: function (input) {
+                onChildWindowOpenHandler = input;
+            }, configurable: true});
+        });
+
+        afterEach(function () {
+            delete webview.onChildWindowOpen;
+            delete require.cache[require.resolve(srcPath + "webview")];
+            webview = require(srcPath + "webview");
+        });
+
+        it('delegates to childWebViewControls on the overlay webview', function () {
+            config.enableChildWebView = true;
+
+            //reload config in framework
+            delete require.cache[require.resolve(srcPath + "framework")];
+            framework = require(srcPath + 'framework');
+
+            this.after(function () {
+                delete require.cache[require.resolve(srcPath + "config")];
+                config = require(srcPath + 'config');
+            });
+
+            framework.start();
+            expect(overlayWebView.bindAppWebViewToChildWebViewControls).toHaveBeenCalledWith(webview);
+            expect(webview.onChildWindowOpen).not.toBeDefined();
+        });
+
+        it('binds to OpenChildWindow and invokes the browser', function () {
+            config.enableChildWebView = false;
+
+            //reload config in framework
+            delete require.cache[require.resolve(srcPath + "framework")];
+            framework = require(srcPath + 'framework');
+
+            this.after(function () {
+                delete require.cache[require.resolve(srcPath + "config")];
+                config = require(srcPath + 'config');
+            });
+
+            framework.start();
+            expect(overlayWebView.bindAppWebViewToChildWebViewControls).not.toHaveBeenCalledWith(webview);
+            expect(onChildWindowOpenHandler).toEqual(jasmine.any(Function));
+            onChildWindowOpenHandler(JSON.stringify({url: 'http://www.google.com'}));
+            expect(mockedApplication.invocation.invoke).toHaveBeenCalledWith(
+                {uri: 'http://www.google.com', target: "sys.browser" }
+            );
+        });
+    });
+
+    describe('shows the webinspector dialog', function () {
+        it('show the webinspector dialog', function () {
+            var flag = false;
+            spyOn(overlayWebView, "showDialog");
+
+            window.qnx.webplatform.device.getNetworkInterfaces = function (callback) {
+                callback();
+                flag = true;
+            };
+            config.debugEnabled = true;
+            framework.start();
+            waitsFor(function () {
+                return flag;
+            });
+            runs(function () {
+                expect(overlayWebView.showDialog).toHaveBeenCalled();
+            });
+        });
+
+        it('show the webinspector dialog with the correct IP address', function () {
+            var flag = false,
+            messageObj;
+            spyOn(overlayWebView, "showDialog");
+
+            window.qnx.webplatform.device.getNetworkInterfaces = function (callback) {
+                var dummyData = {
+                    asix0i : null,
+                    bb0 : null,
+                    bptp0 : null,
+                    cellular0 : null,
+                    cellular1 : null,
+                    cellular2 : null,
+                    cellular3 : null,
+                    cellular4 : null,
+                    ecm0 : {
+                        connected : true,
+                        ipv4Address : "169.254.0.1",
+                        ipv6Address : "fe80::70aa:b2ff:fef9:b374",
+                        type : "usb"
+                    },
+                    ipsec0 : null,
+                    ipsec1 : null,
+                    lo0 : null,
+                    lo2 : null,
+                    nap0 : null,
+                    pan0 : null,
+                    pflog0 : null,
+                    ppp0 : null,
+                    rndis0 : null,
+                    smsc0 : null,
+                    tiw_drv0 : null,
+                    tiw_ibss0 : null,
+                    tiw_p2pdev0 : null,
+                    tiw_p2pgrp0 : null,
+                    tiw_sta0 : {
+                        connected : true,
+                        ipv4Address : "192.168.2.2",
+                        ipv6Address : "fe80::72aa:b2ff:fef9:b374",
+                        type : "wifi"
+                    },
+                    vlan0 : null,
+                    vpn0 : null
+                };
+                callback(dummyData);
+                flag = true;
+            };
+            config.debugEnabled = true;
+            framework.start();
+            waitsFor(function () {
+                return flag;
+            });
+            runs(function () {
+                messageObj = {
+                    title : "Web Inspector Enabled",
+                    htmlmessage : "\n ip4:    169.254.0.1:1337<br/> ip6:    fe80::70aa:b2ff:fef9:b374:1337",
+                    dialogType : "JavaScriptAlert"
+                };
+                expect(overlayWebView.showDialog).toHaveBeenCalledWith(messageObj);
+            });
+        });
+
+    });
+
+    describe('enabling form control', function () {
+        var originalConfigVal;
+
+        beforeEach(function () {
+            originalConfigVal = config.enableFormControl;
+        });
+
+        afterEach(function () {
+            config.enableFormControl = originalConfigVal;
+        });
+
+        it('subscribes webview to formcontrol', function () {
+            config.enableFormControl = true;
+            framework.start();
+            expect(overlayWebViewObj.formcontrol.subscribeTo).toHaveBeenCalledWith(webview);
+        });
+
+        it('does not subscribe webview to formcontrol is enableFormControl is false', function () {
+            config.enableFormControl = false;
+            framework.start();
+            expect(overlayWebViewObj.formcontrol.subscribeTo).not.toHaveBeenCalled();
+        });
+    });
+
+    describe('enabling popup blocker', function () {
+        var originalConfigVal;
+
+        beforeEach(function () {
+            originalConfigVal = config.enablePopupBlocker;
+        });
+
+        afterEach(function () {
+            config.enablePopupBlocker = originalConfigVal;
+        });
+
+        it('does nothing when enablePopupBlocker is true', function () {
+            config.enablePopupBlocker = true;
+            framework.start();
+            expect(mockedQnx.webplatform.nativeCall).not.toHaveBeenCalledWith('webview.setBlockPopups', webview.id, false);
+        });
+
+        it('Disables popupblocker when enablePopupBlocker is false', function () {
+            config.enablePopupBlocker = false;
+            framework.start();
+            expect(mockedQnx.webplatform.nativeCall).toHaveBeenCalledWith('webview.setBlockPopups', webview.id, false);
+        });
+    });
+
+});