UNPKG

easy-qwebchannel

Version:

Easy IPC communication for QT applications

1,000 lines (980 loc) 38.3 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _regeneratorRuntime() { _regeneratorRuntime = function () { return exports; }; var exports = {}, Op = Object.prototype, hasOwn = Op.hasOwnProperty, defineProperty = Object.defineProperty || function (obj, key, desc) { obj[key] = desc.value; }, $Symbol = "function" == typeof Symbol ? Symbol : {}, iteratorSymbol = $Symbol.iterator || "@@iterator", asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator", toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; function define(obj, key, value) { return Object.defineProperty(obj, key, { value: value, enumerable: !0, configurable: !0, writable: !0 }), obj[key]; } try { define({}, ""); } catch (err) { define = function (obj, key, value) { return obj[key] = value; }; } function wrap(innerFn, outerFn, self, tryLocsList) { var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator, generator = Object.create(protoGenerator.prototype), context = new Context(tryLocsList || []); return defineProperty(generator, "_invoke", { value: makeInvokeMethod(innerFn, self, context) }), generator; } function tryCatch(fn, obj, arg) { try { return { type: "normal", arg: fn.call(obj, arg) }; } catch (err) { return { type: "throw", arg: err }; } } exports.wrap = wrap; var ContinueSentinel = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var IteratorPrototype = {}; define(IteratorPrototype, iteratorSymbol, function () { return this; }); var getProto = Object.getPrototypeOf, NativeIteratorPrototype = getProto && getProto(getProto(values([]))); NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype); var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype); function defineIteratorMethods(prototype) { ["next", "throw", "return"].forEach(function (method) { define(prototype, method, function (arg) { return this._invoke(method, arg); }); }); } function AsyncIterator(generator, PromiseImpl) { function invoke(method, arg, resolve, reject) { var record = tryCatch(generator[method], generator, arg); if ("throw" !== record.type) { var result = record.arg, value = result.value; return value && "object" == typeof value && hasOwn.call(value, "__await") ? PromiseImpl.resolve(value.__await).then(function (value) { invoke("next", value, resolve, reject); }, function (err) { invoke("throw", err, resolve, reject); }) : PromiseImpl.resolve(value).then(function (unwrapped) { result.value = unwrapped, resolve(result); }, function (error) { return invoke("throw", error, resolve, reject); }); } reject(record.arg); } var previousPromise; defineProperty(this, "_invoke", { value: function (method, arg) { function callInvokeWithMethodAndArg() { return new PromiseImpl(function (resolve, reject) { invoke(method, arg, resolve, reject); }); } return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(innerFn, self, context) { var state = "suspendedStart"; return function (method, arg) { if ("executing" === state) throw new Error("Generator is already running"); if ("completed" === state) { if ("throw" === method) throw arg; return doneResult(); } for (context.method = method, context.arg = arg;;) { var delegate = context.delegate; if (delegate) { var delegateResult = maybeInvokeDelegate(delegate, context); if (delegateResult) { if (delegateResult === ContinueSentinel) continue; return delegateResult; } } if ("next" === context.method) context.sent = context._sent = context.arg;else if ("throw" === context.method) { if ("suspendedStart" === state) throw state = "completed", context.arg; context.dispatchException(context.arg); } else "return" === context.method && context.abrupt("return", context.arg); state = "executing"; var record = tryCatch(innerFn, self, context); if ("normal" === record.type) { if (state = context.done ? "completed" : "suspendedYield", record.arg === ContinueSentinel) continue; return { value: record.arg, done: context.done }; } "throw" === record.type && (state = "completed", context.method = "throw", context.arg = record.arg); } }; } function maybeInvokeDelegate(delegate, context) { var methodName = context.method, method = delegate.iterator[methodName]; if (undefined === method) return context.delegate = null, "throw" === methodName && delegate.iterator.return && (context.method = "return", context.arg = undefined, maybeInvokeDelegate(delegate, context), "throw" === context.method) || "return" !== methodName && (context.method = "throw", context.arg = new TypeError("The iterator does not provide a '" + methodName + "' method")), ContinueSentinel; var record = tryCatch(method, delegate.iterator, context.arg); if ("throw" === record.type) return context.method = "throw", context.arg = record.arg, context.delegate = null, ContinueSentinel; var info = record.arg; return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, "return" !== context.method && (context.method = "next", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = "throw", context.arg = new TypeError("iterator result is not an object"), context.delegate = null, ContinueSentinel); } function pushTryEntry(locs) { var entry = { tryLoc: locs[0] }; 1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry); } function resetTryEntry(entry) { var record = entry.completion || {}; record.type = "normal", delete record.arg, entry.completion = record; } function Context(tryLocsList) { this.tryEntries = [{ tryLoc: "root" }], tryLocsList.forEach(pushTryEntry, this), this.reset(!0); } function values(iterable) { if (iterable) { var iteratorMethod = iterable[iteratorSymbol]; if (iteratorMethod) return iteratorMethod.call(iterable); if ("function" == typeof iterable.next) return iterable; if (!isNaN(iterable.length)) { var i = -1, next = function next() { for (; ++i < iterable.length;) if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next; return next.value = undefined, next.done = !0, next; }; return next.next = next; } } return { next: doneResult }; } function doneResult() { return { value: undefined, done: !0 }; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), defineProperty(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"), exports.isGeneratorFunction = function (genFun) { var ctor = "function" == typeof genFun && genFun.constructor; return !!ctor && (ctor === GeneratorFunction || "GeneratorFunction" === (ctor.displayName || ctor.name)); }, exports.mark = function (genFun) { return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, "GeneratorFunction")), genFun.prototype = Object.create(Gp), genFun; }, exports.awrap = function (arg) { return { __await: arg }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () { return this; }), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) { void 0 === PromiseImpl && (PromiseImpl = Promise); var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl); return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) { return result.done ? result.value : iter.next(); }); }, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, "Generator"), define(Gp, iteratorSymbol, function () { return this; }), define(Gp, "toString", function () { return "[object Generator]"; }), exports.keys = function (val) { var object = Object(val), keys = []; for (var key in object) keys.push(key); return keys.reverse(), function next() { for (; keys.length;) { var key = keys.pop(); if (key in object) return next.value = key, next.done = !1, next; } return next.done = !0, next; }; }, exports.values = values, Context.prototype = { constructor: Context, reset: function (skipTempReset) { if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = "next", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset) for (var name in this) "t" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined); }, stop: function () { this.done = !0; var rootRecord = this.tryEntries[0].completion; if ("throw" === rootRecord.type) throw rootRecord.arg; return this.rval; }, dispatchException: function (exception) { if (this.done) throw exception; var context = this; function handle(loc, caught) { return record.type = "throw", record.arg = exception, context.next = loc, caught && (context.method = "next", context.arg = undefined), !!caught; } for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i], record = entry.completion; if ("root" === entry.tryLoc) return handle("end"); if (entry.tryLoc <= this.prev) { var hasCatch = hasOwn.call(entry, "catchLoc"), hasFinally = hasOwn.call(entry, "finallyLoc"); if (hasCatch && hasFinally) { if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); } else if (hasCatch) { if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); } else { if (!hasFinally) throw new Error("try statement without catch or finally"); if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); } } } }, abrupt: function (type, arg) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) { var finallyEntry = entry; break; } } finallyEntry && ("break" === type || "continue" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null); var record = finallyEntry ? finallyEntry.completion : {}; return record.type = type, record.arg = arg, finallyEntry ? (this.method = "next", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record); }, complete: function (record, afterLoc) { if ("throw" === record.type) throw record.arg; return "break" === record.type || "continue" === record.type ? this.next = record.arg : "return" === record.type ? (this.rval = this.arg = record.arg, this.method = "return", this.next = "end") : "normal" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel; }, finish: function (finallyLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel; } }, catch: function (tryLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc === tryLoc) { var record = entry.completion; if ("throw" === record.type) { var thrown = record.arg; resetTryEntry(entry); } return thrown; } } throw new Error("illegal catch attempt"); }, delegateYield: function (iterable, resultName, nextLoc) { return this.delegate = { iterator: values(iterable), resultName: resultName, nextLoc: nextLoc }, "next" === this.method && (this.arg = undefined), ContinueSentinel; } }, exports; } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebChannel module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ var QWebChannelMessageTypes = { signal: 1, propertyUpdate: 2, init: 3, idle: 4, debug: 5, invokeMethod: 6, connectToSignal: 7, disconnectFromSignal: 8, setProperty: 9, response: 10 }; var QWebChannel = function QWebChannel(transport, initCallback) { if (typeof transport !== "object" || typeof transport.send !== "function") { console.error("The QWebChannel expects a transport object with a send function and onmessage callback property." + " Given is: transport: " + typeof transport + ", transport.send: " + typeof transport.send); return; } var channel = this; this.transport = transport; this.send = function (data) { if (typeof data !== "string") { data = JSON.stringify(data); } channel.transport.send(data); }; this.transport.onmessage = function (message) { var data = message.data; if (typeof data === "string") { data = JSON.parse(data); } switch (data.type) { case QWebChannelMessageTypes.signal: channel.handleSignal(data); break; case QWebChannelMessageTypes.response: channel.handleResponse(data); break; case QWebChannelMessageTypes.propertyUpdate: channel.handlePropertyUpdate(data); break; default: console.error("invalid message received:", message.data); break; } }; this.execCallbacks = {}; this.execId = 0; this.exec = function (data, callback) { if (!callback) { // if no callback is given, send directly channel.send(data); return; } if (channel.execId === Number.MAX_VALUE) { // wrap channel.execId = Number.MIN_VALUE; } if (data.hasOwnProperty("id")) { console.error("Cannot exec message with property id: " + JSON.stringify(data)); return; } data.id = channel.execId++; channel.execCallbacks[data.id] = callback; channel.send(data); }; this.objects = {}; this.handleSignal = function (message) { var object = channel.objects[message.object]; if (object) { object.signalEmitted(message.signal, message.args); } else { console.warn("Unhandled signal: " + message.object + "::" + message.signal); } }; this.handleResponse = function (message) { if (!message.hasOwnProperty("id")) { console.error("Invalid response message received: ", JSON.stringify(message)); return; } channel.execCallbacks[message.id](message.data); delete channel.execCallbacks[message.id]; }; this.handlePropertyUpdate = function (message) { message.data.forEach(function (data) { var object = channel.objects[data.object]; if (object) { object.propertyUpdate(data.signals, data.properties); } else { console.warn("Unhandled property update: " + data.object + "::" + data.signal); } }); channel.exec({ type: QWebChannelMessageTypes.idle }); }; this.debug = function (message) { channel.send({ type: QWebChannelMessageTypes.debug, data: message }); }; channel.exec({ type: QWebChannelMessageTypes.init }, function (data) { for (var _i = 0, _Object$keys = Object.keys(data); _i < _Object$keys.length; _i++) { var objectName = _Object$keys[_i]; new QObject(objectName, data[objectName], channel); } // now unwrap properties, which might reference other registered objects for (var _i2 = 0, _Object$keys2 = Object.keys(channel.objects); _i2 < _Object$keys2.length; _i2++) { var _objectName = _Object$keys2[_i2]; channel.objects[_objectName].unwrapProperties(); } if (initCallback) { initCallback(channel); } channel.exec({ type: QWebChannelMessageTypes.idle }); }); }; function QObject(name, data, webChannel) { this.__id__ = name; webChannel.objects[name] = this; // List of callbacks that get invoked upon signal emission this.__objectSignals__ = {}; // Cache of all properties, updated when a notify signal is emitted this.__propertyCache__ = {}; var object = this; // ---------------------------------------------------------------------- this.unwrapQObject = function (response) { if (response instanceof Array) { // support list of objects return response.map(function (qobj) { return object.unwrapQObject(qobj); }); } if (!(response instanceof Object)) return response; if (!response["__QObject*__"] || response.id === undefined) { var jObj = {}; for (var _i3 = 0, _Object$keys3 = Object.keys(response); _i3 < _Object$keys3.length; _i3++) { var propName = _Object$keys3[_i3]; jObj[propName] = object.unwrapQObject(response[propName]); } return jObj; } var objectId = response.id; if (webChannel.objects[objectId]) return webChannel.objects[objectId]; if (!response.data) { console.error("Cannot unwrap unknown QObject " + objectId + " without data."); return; } var qObject = new QObject(objectId, response.data, webChannel); qObject.destroyed.connect(function () { if (webChannel.objects[objectId] === qObject) { delete webChannel.objects[objectId]; // reset the now deleted QObject to an empty {} object // just assigning {} though would not have the desired effect, but the // below also ensures all external references will see the empty map // NOTE: this detour is necessary to workaround QTBUG-40021 Object.keys(qObject).forEach(function (name) { return delete qObject[name]; }); } }); // here we are already initialized, and thus must directly unwrap the properties qObject.unwrapProperties(); return qObject; }; this.unwrapProperties = function () { for (var _i4 = 0, _Object$keys4 = Object.keys(object.__propertyCache__); _i4 < _Object$keys4.length; _i4++) { var propertyIdx = _Object$keys4[_i4]; object.__propertyCache__[propertyIdx] = object.unwrapQObject(object.__propertyCache__[propertyIdx]); } }; function addSignal(signalData, isPropertyNotifySignal) { var signalName = signalData[0]; var signalIndex = signalData[1]; object[signalName] = { connect: function connect(callback) { if (typeof callback !== "function") { console.error("Bad callback given to connect to signal " + signalName); return; } object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || []; object.__objectSignals__[signalIndex].push(callback); // only required for "pure" signals, handled separately for properties in propertyUpdate if (isPropertyNotifySignal) return; // also note that we always get notified about the destroyed signal if (signalName === "destroyed" || signalName === "destroyed()" || signalName === "destroyed(QObject*)") return; // and otherwise we only need to be connected only once if (object.__objectSignals__[signalIndex].length == 1) { webChannel.exec({ type: QWebChannelMessageTypes.connectToSignal, object: object.__id__, signal: signalIndex }); } }, disconnect: function disconnect(callback) { if (typeof callback !== "function") { console.error("Bad callback given to disconnect from signal " + signalName); return; } object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || []; var idx = object.__objectSignals__[signalIndex].indexOf(callback); if (idx === -1) { console.error("Cannot find connection of signal " + signalName + " to " + callback.name); return; } object.__objectSignals__[signalIndex].splice(idx, 1); if (!isPropertyNotifySignal && object.__objectSignals__[signalIndex].length === 0) { // only required for "pure" signals, handled separately for properties in propertyUpdate webChannel.exec({ type: QWebChannelMessageTypes.disconnectFromSignal, object: object.__id__, signal: signalIndex }); } } }; } /** * Invokes all callbacks for the given signalname. Also works for property notify callbacks. */ function invokeSignalCallbacks(signalName, signalArgs) { var connections = object.__objectSignals__[signalName]; if (connections) { connections.forEach(function (callback) { callback.apply(callback, signalArgs); }); } } this.propertyUpdate = function (signals, propertyMap) { // update property cache for (var _i5 = 0, _Object$keys5 = Object.keys(propertyMap); _i5 < _Object$keys5.length; _i5++) { var propertyIndex = _Object$keys5[_i5]; var propertyValue = propertyMap[propertyIndex]; object.__propertyCache__[propertyIndex] = this.unwrapQObject(propertyValue); } for (var _i6 = 0, _Object$keys6 = Object.keys(signals); _i6 < _Object$keys6.length; _i6++) { var signalName = _Object$keys6[_i6]; // Invoke all callbacks, as signalEmitted() does not. This ensures the // property cache is updated before the callbacks are invoked. invokeSignalCallbacks(signalName, signals[signalName]); } }; this.signalEmitted = function (signalName, signalArgs) { invokeSignalCallbacks(signalName, this.unwrapQObject(signalArgs)); }; function addMethod(methodData) { var methodName = methodData[0]; var methodIdx = methodData[1]; // Fully specified methods are invoked by id, others by name for host-side overload resolution var invokedMethod = methodName[methodName.length - 1] === ')' ? methodIdx : methodName; object[methodName] = function () { var args = []; var callback; var errCallback; for (var i = 0; i < arguments.length; ++i) { var argument = arguments[i]; if (typeof argument === "function") callback = argument;else if (argument instanceof QObject && webChannel.objects[argument.__id__] !== undefined) args.push({ "id": argument.__id__ });else args.push(argument); } var result; // during test, webChannel.exec synchronously calls the callback // therefore, the promise must be constucted before calling // webChannel.exec to ensure the callback is set up if (!callback && typeof Promise === 'function') { result = new Promise(function (resolve, reject) { callback = resolve; errCallback = reject; }); } webChannel.exec({ "type": QWebChannelMessageTypes.invokeMethod, "object": object.__id__, "method": invokedMethod, "args": args }, function (response) { if (response !== undefined) { var result = object.unwrapQObject(response); if (callback) { callback(result); } } else if (errCallback) { errCallback(); } }); return result; }; } function bindGetterSetter(propertyInfo) { var propertyIndex = propertyInfo[0]; var propertyName = propertyInfo[1]; var notifySignalData = propertyInfo[2]; // initialize property cache with current value // NOTE: if this is an object, it is not directly unwrapped as it might // reference other QObject that we do not know yet object.__propertyCache__[propertyIndex] = propertyInfo[3]; if (notifySignalData) { if (notifySignalData[0] === 1) { // signal name is optimized away, reconstruct the actual name notifySignalData[0] = propertyName + "Changed"; } addSignal(notifySignalData, true); } Object.defineProperty(object, propertyName, { configurable: true, get: function get() { var propertyValue = object.__propertyCache__[propertyIndex]; if (propertyValue === undefined) { // This shouldn't happen console.warn("Undefined value in property cache for property \"" + propertyName + "\" in object " + object.__id__); } return propertyValue; }, set: function set(value) { if (value === undefined) { console.warn("Property setter for " + propertyName + " called with undefined value!"); return; } object.__propertyCache__[propertyIndex] = value; var valueToSend = value; if (valueToSend instanceof QObject && webChannel.objects[valueToSend.__id__] !== undefined) valueToSend = { "id": valueToSend.__id__ }; webChannel.exec({ "type": QWebChannelMessageTypes.setProperty, "object": object.__id__, "property": propertyIndex, "value": valueToSend }); } }); } // ---------------------------------------------------------------------- data.methods.forEach(addMethod); data.properties.forEach(bindGetterSetter); data.signals.forEach(function (signal) { addSignal(signal, false); }); Object.assign(object, data.enums); } var Deferred = /*#__PURE__*/function () { function Deferred() { var _this = this; this._state = 'pending'; this.promise = new Promise(function (resolve, reject) { _this._resolve = resolve; _this._reject = reject; }); } var _proto = Deferred.prototype; _proto.resolve = function resolve() { if (!this._resolve) { throw new Error('Deferred.resolve is undefined'); } this._state = 'fulfilled'; return this._resolve.apply(this, arguments); }; _proto.reject = function reject() { if (!this._reject) { throw new Error('Deferred.reject is undefined'); } this._state = 'rejected'; return this._reject.apply(this, arguments); }; _createClass(Deferred, [{ key: "isFulfilled", get: function get() { return this._state === 'fulfilled'; } }, { key: "isRejected", get: function get() { return this._state === 'rejected'; } }]); return Deferred; }(); var EasyQWebChannel = /*#__PURE__*/function () { /** * @param channelObjectName * @example new EasyQWebChannel('fooObj') */ function EasyQWebChannel(channelObjectName) { var _this = this; this.context = null; this.deferred = new Deferred(); this.onceConnectedSignalName = {}; new QWebChannel(window.qt.webChannelTransport, function (channel) { _this.context = channel.objects[channelObjectName]; _this.deferred.resolve(); }); } var _proto = EasyQWebChannel.prototype; _proto.ready = function ready() { return this.deferred.promise; } /** * @param signalName * @param methodName * @param callback * @returns Promise<void> * @example channel.answerNative( * 'signalName', * 'jsFinished', * (args: any[]) => ({ jsSideResult: 'test' }) * ) */; _proto.answerNative = function answerNative(signalName, methodName, callback) { var _this2 = this; var deferred = new Deferred(); this.once(signalName, /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() { var _len, args, _key, data, _args = arguments; return _regeneratorRuntime().wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: for (_len = _args.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = _args[_key]; } _context.next = 3; return callback(args); case 3: data = _context.sent; typeof data === 'undefined' ? _this2.context[methodName]() : _this2.context[methodName](data); deferred.resolve(); case 6: case "end": return _context.stop(); } }, _callee); }))); return deferred.promise; } /** * @param signalName * @param methodName * @param callback * @param skipCallMethodWhenVoid if callback returns void, skip calling methodName */; _proto.answerNativeHeartBeat = function answerNativeHeartBeat(signalName, methodName, callback, skipCallMethodWhenVoid) { var _this3 = this; if (skipCallMethodWhenVoid === void 0) { skipCallMethodWhenVoid = false; } this.context[signalName].connect( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2() { var _len2, args, _key2, data, _args2 = arguments; return _regeneratorRuntime().wrap(function _callee2$(_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: for (_len2 = _args2.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = _args2[_key2]; } _context2.next = 3; return callback(args); case 3: data = _context2.sent; if (typeof data === 'undefined') { if (!skipCallMethodWhenVoid) { _this3.context[methodName](); } } else { _this3.context[methodName](data); } case 5: case "end": return _context2.stop(); } }, _callee2); }))); } /** * @param methodName * @param signalName * @param data * @returns Promise<any> * @example channel.callNative( * 'methodName', * 'nativeMethodFinished', * { methodArgument: 'test' }, * ) */; _proto.callNative = function callNative(methodName, signalName, data) { var deferred = new Deferred(); this.once(signalName, function () { for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { args[_key3] = arguments[_key3]; } deferred.resolve(args); }); typeof data === 'undefined' ? this.context[methodName]() : this.context[methodName](data); return deferred.promise; } /** * @param methodName * @param data */; _proto.callNativeWithoutResponse = function callNativeWithoutResponse(methodName, data) { typeof data === 'undefined' ? this.context[methodName]() : this.context[methodName](data); } /** * @param methodName */; _proto.canUseMethod = function canUseMethod(methodName) { return typeof this.context[methodName] === 'function'; } /** * @param signalName */; _proto.canUseSignal = function canUseSignal(signalName) { var _this$context$signalN; return ((_this$context$signalN = this.context[signalName]) == null ? void 0 : _this$context$signalN.connect) === 'function'; } /** * @param signalName * @param callback * @example channel.once('nativeMethodFinished', (args: any[]) => {}) */; _proto.once = /*#__PURE__*/ function () { var _once = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(signalName, callback) { var _this4 = this; var connectCallback, currentJob, args; return _regeneratorRuntime().wrap(function _callee3$(_context3) { while (1) switch (_context3.prev = _context3.next) { case 0: connectCallback = function connectCallback() { for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { args[_key4] = arguments[_key4]; } var jobs = _this4.onceConnectedSignalName[signalName]; jobs.forEach(function (job) { if (job.isFulfilled || job.isRejected) { return; } job.resolve(args); }); }; if (!this.onceConnectedSignalName[signalName]) { // connect only once this.onceConnectedSignalName[signalName] = []; this.context[signalName].connect(connectCallback); } currentJob = new Deferred(); this.onceConnectedSignalName[signalName].push(currentJob); _context3.next = 6; return currentJob.promise; case 6: args = _context3.sent; callback.apply(void 0, args); case 8: case "end": return _context3.stop(); } }, _callee3, this); })); function once(_x, _x2) { return _once.apply(this, arguments); } return once; }(); return EasyQWebChannel; }(); exports.EasyQWebChannel = EasyQWebChannel; //# sourceMappingURL=easy-qwebchannel.cjs.development.js.map