diff --git a/LICENSE.txt b/LICENSE.txt
index e9a3e15e..a8d24e39 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -43,6 +43,8 @@ licenses (all MPL 2.0 compatible):
vendor/browser-es-module-loader: MIT
+ vendor/promise.js : MIT
+
Any other files not mentioned above are typically marked with
a copyright/license header at the top of the file. The default noVNC
license is MPL-2.0.
diff --git a/utils/use_require.js b/utils/use_require.js
index f0383d09..8522256b 100755
--- a/utils/use_require.js
+++ b/utils/use_require.js
@@ -14,24 +14,29 @@ program
.parse(process.argv);
// the various important paths
-var main_path = path.resolve(__dirname, '..');
-var core_path = path.resolve(__dirname, '..', 'core');
-var app_path = path.resolve(__dirname, '..', 'app');
-var vendor_path = path.resolve(__dirname, '..', 'vendor');
-var out_dir_base = path.resolve(__dirname, '..', 'build');
-var lib_dir_base = path.resolve(__dirname, '..', 'lib');
+const paths = {
+ main: path.resolve(__dirname, '..'),
+ core: path.resolve(__dirname, '..', 'core'),
+ app: path.resolve(__dirname, '..', 'app'),
+ vendor: path.resolve(__dirname, '..', 'vendor'),
+ out_dir_base: path.resolve(__dirname, '..', 'build'),
+ lib_dir_base: path.resolve(__dirname, '..', 'lib'),
+};
const no_copy_files = new Set([
// skip these -- they don't belong in the processed application
- path.join(vendor_path, 'sinon.js'),
- path.join(vendor_path, 'browser-es-module-loader'),
+ path.join(paths.vendor, 'sinon.js'),
+ path.join(paths.vendor, 'browser-es-module-loader'),
+ path.join(paths.vendor, 'promise.js'),
]);
const no_transform_files = new Set([
// don't transform this -- we want it imported as-is to properly catch loading errors
- path.join(app_path, 'error-handler.js'),
+ path.join(paths.app, 'error-handler.js'),
]);
+no_copy_files.forEach((file) => no_transform_files.add(file));
+
// walkDir *recursively* walks directories trees,
// calling the callback for all normal files found.
var walkDir = function (base_path, cb, filter) {
@@ -55,7 +60,7 @@ var walkDir = function (base_path, cb, filter) {
var transform_html = function (new_script) {
// write out the modified vnc.html file that works with the bundle
var src_html_path = path.resolve(__dirname, '..', 'vnc.html');
- var out_html_path = path.resolve(out_dir_base, 'vnc.html');
+ var out_html_path = path.resolve(paths.out_dir_base, 'vnc.html');
fs.readFile(src_html_path, (err, contents_raw) => {
if (err) { throw err; }
@@ -92,10 +97,10 @@ var make_lib_files = function (import_format, source_maps, with_app_dir) {
var in_path;
if (with_app_dir) {
- var out_path_base = out_dir_base;
- in_path = main_path;
+ var out_path_base = paths.out_dir_base;
+ in_path = paths.main;
} else {
- var out_path_base = lib_dir_base;
+ var out_path_base = paths.lib_dir_base;
}
fse.ensureDirSync(out_path_base);
@@ -144,11 +149,15 @@ var make_lib_files = function (import_format, source_maps, with_app_dir) {
});
};
- walkDir(core_path, handleDir.bind(null, true, in_path || core_path), (filename, stats) => !no_copy_files.has(filename));
- walkDir(vendor_path, handleDir.bind(null, true, in_path || main_path), (filename, stats) => !no_copy_files.has(filename));
+ if (with_app_dir && helper && helper.noCopyOverride) {
+ helper.noCopyOverride(paths, no_copy_files);
+ }
+
+ walkDir(paths.core, handleDir.bind(null, true, in_path || paths.core), (filename, stats) => !no_copy_files.has(filename));
+ walkDir(paths.vendor, handleDir.bind(null, true, in_path || paths.main), (filename, stats) => !no_copy_files.has(filename));
if (with_app_dir) {
- walkDir(app_path, handleDir.bind(null, false, in_path || app_path), (filename, stats) => !no_copy_files.has(filename));
+ walkDir(paths.app, handleDir.bind(null, false, in_path || paths.app), (filename, stats) => !no_copy_files.has(filename));
const out_app_path = path.join(out_path_base, 'app.js');
if (helper && helper.appWriter) {
diff --git a/utils/use_require_helpers.js b/utils/use_require_helpers.js
index b8ac46e6..990fb4df 100644
--- a/utils/use_require_helpers.js
+++ b/utils/use_require_helpers.js
@@ -11,6 +11,7 @@ module.exports = {
console.log(`Please place RequireJS in ${path.join(base_out_path, 'require.js')}`);
return ``;
},
+ noCopyOverride: () => {},
},
'commonjs': {
optionsOverride: (opts) => {
@@ -23,12 +24,17 @@ module.exports = {
b.bundle().pipe(fs.createWriteStream(out_path));
return ``;
},
+ noCopyOverride: () => {},
},
'systemjs': {
appWriter: (base_out_path, out_path) => {
fs.writeFile(out_path, 'SystemJS.import("./app/ui.js");', (err) => { if (err) throw err; });
console.log(`Please place SystemJS in ${path.join(base_out_path, 'system-production.js')}`);
- return `\n`;
+ return `
+\n`;
+ },
+ noCopyOverride: (paths, no_copy_files) => {
+ no_copy_files.delete(path.join(paths.vendor, 'promise.js'));
},
},
'umd': {
diff --git a/vendor/browser-es-module-loader/dist/browser-es-module-loader.js b/vendor/browser-es-module-loader/dist/browser-es-module-loader.js
index 0d22bab2..8d3a2eea 100644
--- a/vendor/browser-es-module-loader/dist/browser-es-module-loader.js
+++ b/vendor/browser-es-module-loader/dist/browser-es-module-loader.js
@@ -1343,9 +1343,9 @@ WorkerPool.prototype = {
},
_stop: function () {
- for (let wrkr of this._workers) {
+ this._workers.forEach(function(wrkr) {
wrkr.terminate();
- }
+ });
}
};
diff --git a/vendor/browser-es-module-loader/src/browser-es-module-loader.js b/vendor/browser-es-module-loader/src/browser-es-module-loader.js
index a9d72097..6154e446 100644
--- a/vendor/browser-es-module-loader/src/browser-es-module-loader.js
+++ b/vendor/browser-es-module-loader/src/browser-es-module-loader.js
@@ -183,9 +183,9 @@ WorkerPool.prototype = {
},
_stop: function () {
- for (let wrkr of this._workers) {
+ this._workers.forEach(function(wrkr) {
wrkr.terminate();
- }
+ });
}
};
diff --git a/vendor/promise.js b/vendor/promise.js
new file mode 100644
index 00000000..62843432
--- /dev/null
+++ b/vendor/promise.js
@@ -0,0 +1,255 @@
+/* Copyright (c) 2014 Taylor Hakes
+ * Copyright (c) 2014 Forbes Lindesay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+(function (root) {
+
+ // Store setTimeout reference so promise-polyfill will be unaffected by
+ // other code modifying setTimeout (like sinon.useFakeTimers())
+ var setTimeoutFunc = setTimeout;
+
+ function noop() {}
+
+ // 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;
+ Promise._immediateFn(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) {
+ Promise._immediateFn(function() {
+ if (!self._handled) {
+ Promise._unhandledRejectionFn(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.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);
+ }
+ });
+ };
+
+ // Use polyfill for setImmediate for performance gains
+ Promise._immediateFn = (typeof setImmediate === 'function' && function (fn) { setImmediate(fn); }) ||
+ function (fn) {
+ setTimeoutFunc(fn, 0);
+ };
+
+ Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {
+ if (typeof console !== 'undefined' && console) {
+ console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
+ }
+ };
+
+ /**
+ * Set the immediate function to execute callbacks
+ * @param fn {function} Function to execute
+ * @deprecated
+ */
+ Promise._setImmediateFn = function _setImmediateFn(fn) {
+ Promise._immediateFn = fn;
+ };
+
+ /**
+ * Change the function to execute on unhandled rejection
+ * @param {function} fn Function to execute on unhandled rejection
+ * @deprecated
+ */
+ Promise._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) {
+ Promise._unhandledRejectionFn = fn;
+ };
+
+ if (typeof module !== 'undefined' && module.exports) {
+ module.exports = Promise;
+ } else if (!root.Promise) {
+ root.Promise = Promise;
+ }
+
+})(this);
diff --git a/vnc.html b/vnc.html
index 10cc1430..02fe5c69 100644
--- a/vnc.html
+++ b/vnc.html
@@ -63,6 +63,8 @@
+
+