All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ms.android.js-bridge.1.0.2.source-code.jsi.js Maven / Gradle / Ivy

There is a newer version: 1.0.4
Show newest version
(function (window) {
    ///////////////////////////////////////////////////////////////////////////
    // Promises
    var Promise = (function () {
        // Store setTimeout reference so promise-polyfill will be unaffected by
        // other code modifying setTimeout (like sinon.useFakeTimers())
        var setTimeoutFunc = setTimeout;

        function noop() {
        }

        // Use polyfill for setImmediate for performance gains
        var asap = (typeof setImmediate === 'function' && setImmediate) ||
                   function (fn) {
                       setTimeoutFunc(fn, 1);
                   };

        var onUnhandledRejection = function onUnhandledRejection(err) {
            if (typeof console !== 'undefined' && console) {
                console.warn('Possible Unhandled Promise Rejection:', err);
            }
        };

        // Polyfill for Function.prototype.bind
        function bind(fn, thisArg) {
            return function () {
                fn.apply(thisArg, arguments);
            };
        }

        function Promise(fn) {
            if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new');
            if (typeof fn !== 'function') throw new TypeError('not a function');
            this._state     = 0;
            this._handled   = false;
            this._value     = undefined;
            this._deferreds = [];

            doResolve(fn, this);
        }

        function handle(self, deferred) {
            while (self._state === 3) {
                self = self._value;
            }
            if (self._state === 0) {
                self._deferreds.push(deferred);
                return;
            }
            self._handled = true;
            asap(function () {
                var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
                if (cb === null) {
                    (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
                    return;
                }
                var ret;
                try {
                    ret = cb(self._value);
                } catch (e) {
                    reject(deferred.promise, e);
                    return;
                }
                resolve(deferred.promise, ret);
            });
        }

        function resolve(self, newValue) {
            try {
                // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
                if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.');
                if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
                    var then = newValue.then;
                    if (newValue instanceof Promise) {
                        self._state = 3;
                        self._value = newValue;
                        finale(self);
                        return;
                    } else if (typeof then === 'function') {
                        doResolve(bind(then, newValue), self);
                        return;
                    }
                }
                self._state = 1;
                self._value = newValue;
                finale(self);
            } catch (e) {
                reject(self, e);
            }
        }

        function reject(self, newValue) {
            self._state = 2;
            self._value = newValue;
            finale(self);
        }

        function finale(self) {
            if (self._state === 2 && self._deferreds.length === 0) {
                asap(function () {
                    if (!self._handled) {
                        onUnhandledRejection(self._value);
                    }
                });
            }

            for (var i = 0, len = self._deferreds.length; i < len; i++) {
                handle(self, self._deferreds[i]);
            }
            self._deferreds = null;
        }

        function Handler(onFulfilled, onRejected, promise) {
            this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
            this.onRejected  = typeof onRejected === 'function' ? onRejected : null;
            this.promise     = promise;
        }

        /**
         * Take a potentially misbehaving resolver function and make sure
         * onFulfilled and onRejected are only called once.
         *
         * Makes no guarantees about asynchrony.
         */
        function doResolve(fn, self) {
            var done = false;
            try {
                fn(function (value) {
                    if (done) return;
                    done = true;
                    resolve(self, value);
                }, function (reason) {
                    if (done) return;
                    done = true;
                    reject(self, reason);
                });
            } catch (ex) {
                if (done) return;
                done = true;
                reject(self, ex);
            }
        }

        Promise.prototype['catch'] = function (onRejected) {
            return this.then(null, onRejected);
        };

        Promise.prototype['finally'] = function (always) {
            return this.then(always, always);
        };

        Promise.prototype.then = function (onFulfilled, onRejected) {
            var prom = new (this.constructor)(noop);

            handle(this, new Handler(onFulfilled, onRejected, prom));
            return prom;
        };

        Promise.all = function (arr) {
            var args = Array.prototype.slice.call(arr);

            return new Promise(function (resolve, reject) {
                if (args.length === 0) return resolve([]);
                var remaining = args.length;

                function res(i, val) {
                    try {
                        if (val && (typeof val === 'object' || typeof val === 'function')) {
                            var then = val.then;
                            if (typeof then === 'function') {
                                then.call(val, function (val) {
                                    res(i, val);
                                }, reject);
                                return;
                            }
                        }
                        args[i] = val;
                        if (--remaining === 0) {
                            resolve(args);
                        }
                    } catch (ex) {
                        reject(ex);
                    }
                }

                for (var i = 0; i < args.length; i++) {
                    res(i, args[i]);
                }
            });
        };

        Promise.resolve = function (value) {
            if (value && typeof value === 'object' && value.constructor === Promise) {
                return value;
            }

            return new Promise(function (resolve) {
                resolve(value);
            });
        };

        Promise.reject = function (value) {
            return new Promise(function (resolve, reject) {
                reject(value);
            });
        };

        Promise.race = function (values) {
            return new Promise(function (resolve, reject) {
                for (var i = 0, len = values.length; i < len; i++) {
                    values[i].then(resolve, reject);
                }
            });
        };

        return Promise;
    })();


    ///////////////////////////////////////////////////////////////////////////
    // Interfaces
    var jsi = function (name, method, args) {
        var callbackName   = jsi.callbackIndex++;
        var remoteResource = document.createElement('iframe');

        var promise = new Promise(function (resolve, reject) {
            /* Setup callback! */
            jsi[callbackName] = [resolve, reject];
            /* Trigger fire */
            remoteResource.setAttribute('src', jsi.prefix + name +
                                               "/" + method + "/" + callbackName +
                                               "/?r=" + Math.random() +
                                               "&args=" + encodeURIComponent(JSON.stringify(args)));
            document.head.appendChild(remoteResource);
        });

        return promise.finally(function () {
            remoteResource.remove();
            delete jsi[callbackName];
        });
    };

    jsi.prefix        = "jsi://";
    jsi.callbackIndex = 0;

    jsi.event = function (name, data) {
        var event = document.createEvent('HTMLEvents');
        event.initEvent(name, true, true);
        event.data = data;
        document.dispatchEvent(event);
    };

    jsi.define = function (name, methods) {
        var obj = {};
        for (var methodIndex in methods) {
            /* Prevent iteration over toString and such */
            if (!methods.hasOwnProperty(methodIndex)) continue;
            /* Create a promise based proxy method using jsi */
            (function (methodName) {
                obj[methodName] = function () {
                    return jsi(name, methodName, Array.prototype.slice.call(arguments));
                };
            }(methods[methodIndex]));
        }
        window[name] = obj;
        console.log("JSI: installed interface " + name + " with " + JSON.stringify(methods));
    };

    window.jsi = jsi;

})(window);




© 2015 - 2025 Weber Informatics LLC | Privacy Policy