Files
aza/AzA/_internal/webview/js/api.js
2026-06-15 08:06:06 +02:00

331 lines
8.4 KiB
JavaScript

window.pywebview = {
token: '%(token)s',
platform: '%(platform)s',
api: {},
_eventHandlers: {},
_returnValuesCallbacks: {},
_createApi: function (funcList) {
function sanitize_params(params) {
var reservedWords = [
'case',
'catch',
'const',
'debugger',
'default',
'delete',
'do',
'export',
'extends',
'false',
'function',
'instanceof',
'let',
'new',
'null',
'super',
'switch',
'this',
'throw',
'true',
'typeof',
'var',
'void',
];
for (var i = 0; i < params.length; i++) {
var param = params[i];
if (reservedWords.indexOf(param) !== -1) {
params[i] = param + '_';
}
}
return params;
}
for (var i = 0; i < funcList.length; i++) {
var element = funcList[i];
var funcName = element.func;
var params = element.params;
// Create nested structure and assign function
var funcHierarchy = funcName.split('.');
var functionName = funcHierarchy.pop();
var nestedObject = funcHierarchy.reduce(function (obj, prop) {
if (!obj[prop]) {
obj[prop] = {};
}
return obj[prop];
}, window.pywebview.api);
// Define the function body
var funcBody =
'var __id = (Math.random() + "").substring(2);' +
'var promise = new Promise(function(resolve, reject) {' +
' window.pywebview._checkValue("' +
funcName +
'", resolve, reject, __id);' +
'});' +
'window.pywebview._jsApiCallback("' +
funcName +
'", Array.prototype.slice.call(arguments), __id);' +
'return promise;';
// Assign the new function
nestedObject[functionName] = new Function(
sanitize_params(params),
funcBody
);
window.pywebview._returnValuesCallbacks[funcName] = {};
}
},
_jsApiCallback: function (funcName, params, id) {
switch (window.pywebview.platform) {
case 'mshtml':
case 'cef':
case 'qtwebkit':
case 'android-webkit':
return window.external.call(funcName, pywebview.stringify(params), id);
case 'edgechromium':
// Full file path support for WebView2
if (
params.event instanceof Event &&
params.event.type === 'drop' &&
params.event.dataTransfer.files
) {
chrome.webview.postMessageWithAdditionalObjects(
'FilesDropped',
params.event.dataTransfer.files
);
}
return window.chrome.webview.postMessage([
funcName,
pywebview.stringify(params),
id,
]);
case 'cocoa':
case 'gtkwebkit2':
return window.webkit.messageHandlers.jsBridge.postMessage(
pywebview.stringify(
{ funcName: funcName, params: params, id: id }
)
);
case 'qtwebengine':
if (!window.pywebview._QWebChannel) {
setTimeout(function () {
window.pywebview._QWebChannel.objects.external.call(
funcName,
pywebview.stringify(params),
id
);
}, 100);
} else {
window.pywebview._QWebChannel.objects.external.call(
funcName,
pywebview.stringify(params),
id
);
}
break;
default:
break;
}
},
_checkValue: function (funcName, resolve, reject, id) {
window.pywebview._returnValuesCallbacks[funcName][id] = function(returnObj) {
var value = returnObj.value;
var isError = returnObj.isError;
delete window.pywebview._returnValuesCallbacks[funcName][id];
if (isError) {
var pyError = JSON.parse(value);
var error = new Error(pyError.message);
error.name = pyError.name;
error.stack = pyError.stack;
reject(error);
} else {
resolve(JSON.parse(value));
}
};
},
_asyncCallback: function (result, id) {
window.pywebview._jsApiCallback('pywebviewAsyncCallback', result, id);
},
_isPromise: function (obj) {
return (
!!obj &&
(typeof obj === 'object' || typeof obj === 'function') &&
typeof obj.then === 'function'
);
},
stringify: function stringify(obj, timing) {
function tryConvertToArray(obj) {
try {
return Array.prototype.slice.call(obj);
} catch (e) {
return obj;
}
}
function isArrayLike(a) {
return (
a &&
typeof a.length === 'number' &&
typeof a !== 'string' &&
(Array.isArray(a) ||
(typeof a === 'object' &&
a.length >= 0 &&
(a.length === 0 || (a.length - 1) in a)))
);
}
function serialize(obj, ancestors) {
try {
if (obj instanceof Window) return 'Window';
if (obj instanceof Node) {
obj = pywebview.domJSON.toJSON(obj, {
metadata: false,
serialProperties: true,
});
}
var boundSerialize = serialize.bind(obj);
if (typeof obj !== 'object' || obj === null) {
return obj;
}
while (
ancestors.length > 0 &&
ancestors[ancestors.length - 1] !== this
) {
ancestors.pop();
}
if (ancestors.indexOf(obj) > -1) {
return '[Circular Reference]';
}
ancestors.push(obj);
if (isArrayLike(obj)) {
obj = tryConvertToArray(obj);
}
if (Array.isArray(obj)) {
var arr = obj.map(function (value) {
return boundSerialize(value, ancestors);
});
return arr;
}
var newObj = {};
for (var key in obj) {
if (typeof obj === 'function') {
continue;
}
newObj[key] = boundSerialize(obj[key], ancestors);
}
return newObj;
} catch (e) {
console.error(e);
return e.toString();
}
}
var startTime = +new Date();
var _serialize = serialize.bind(null);
var finalObj = _serialize(obj, []);
var result = JSON.stringify(finalObj);
var endTime = +new Date();
if (timing) {
console.log('Serialization time: ' + (endTime - startTime) / 1000 + 's');
}
return result;
},
_getNodeId: function (element) {
if (!element) {
return null;
}
var pywebviewId =
element.getAttribute('data-pywebview-id') ||
Math.random().toString(36).substr(2, 11);
if (!element.hasAttribute('data-pywebview-id')) {
element.setAttribute('data-pywebview-id', pywebviewId);
}
return pywebviewId;
},
_insertNode: function (node, parent, mode) {
if (mode === 'LAST_CHILD') {
parent.appendChild(node);
} else if (mode === 'FIRST_CHILD') {
parent.insertBefore(node, parent.firstChild);
} else if (mode === 'BEFORE') {
parent.parentNode.insertBefore(node, parent);
} else if (mode === 'AFTER') {
parent.parentNode.insertBefore(node, parent.nextSibling);
} else if (mode === 'REPLACE') {
parent.parentNode.replaceChild(node, parent);
}
},
_loadCss: function (css) {
var interval = setInterval(function () {
if (document.readyState === 'complete') {
clearInterval(interval);
var cssElement = document.createElement('style');
cssElement.type = 'text/css';
cssElement.innerHTML = css;
document.head.appendChild(cssElement);
}
}, 10);
},
_processElements: function (elements) {
var serializedElements = [];
for (var i = 0; i < elements.length; i++) {
var pywebviewId;
if (elements[i] === window) {
pywebviewId = 'window';
} else if (elements[i] === document) {
pywebviewId = 'document';
} else {
pywebviewId = window.pywebview._getNodeId(elements[i]);
}
var node = pywebview.domJSON.toJSON(elements[i], {
metadata: false,
serialProperties: true,
deep: false,
});
node._pywebviewId = pywebviewId;
serializedElements.push(node);
}
return serializedElements;
},
_debounce: function (func, delay) {
var timeout;
return function () {
var context = this;
var args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function () {
func.apply(context, args);
}, delay);
};
},
};