Files
grayjay/app/src/main/assets/devportal/index.html
T
2023-09-25 17:18:43 +02:00

897 lines
28 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" />
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.x/css/materialdesignicons.min.css" rel="stylesheet">
<!--<link href="./dependencies/vuetify.min.css" rel="stylesheet">-->
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.7.1/dist/vuetify.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
<style>
html {
overflow: hidden;
}
#topMenu {
width: 100%;
height: 70px;
background-color: black;
}
.menuTab {
display: inline-block;
height: 100%;
padding-left: 20px;
padding-right: 20px;
vertical-align: top;
line-height: 70px;
color: #AAAAAA;
cursor: pointer;
}
.menuTab.active {
background-color: #140a4a;
color: white;
}
#mainContainer {
}
#mainContainer .page {
position: absolute;
top: 70px;
left: 0px;
width: 100%;
height: calc(100% - 70px);
overflow-y: auto;
}
.requestCard {
margin: 10px;
}
.requestCard .title {
margin-left: 10px;
}
.requestCard .description {
font-weight: lighter;
margin-left: 10px;
}
.requestCard .code {
font-weight: lighter;
margin-left: 10px;
background-color: rgba(0,0,0,.3);
font-family: consolas;
padding: 10px;
}
.requestCard .parameter {
position: relative;
width: 100%;
padding: 5px;
margin-bottom: 10px;
border-radius: 20px;
margin: 5px;
}
.requestCard .parameter .name {
position: absolute;
width: 100px;
margin-left: 10px;
text-align: right;
padding: 10px;
top: 0px;
left: 0px;
}
.requestCard .parameter .description {
top: 0px;
padding: 5px;
font-weight: lighter;
margin-left: 120px;
}
.requestCard .parameter input {
margin: 10px;
background-color: #444444;
margin-left: 120px;
color: white;
padding: 5px;
width: calc(100% - 140px);
}
.testResult {
height: calc(100% - 125px);
overflow-y: auto;
white-space: pre-wrap;
background-color: #222222;
padding: 10px;
font-family: consolas, "Courier New";
font-size: 10px;
}
.testResult.exception {
color: red;
}
.property {
font-weight: 300;
margin-bottom: 15px;
}
.property .key {
color: white;
}
.property .value {
color: #999999;
}
.logContainer {
background-color: rgba(0,0,0,.5);
border-radius: 30px;
height: 500px;
font-family: consolas;
font-size: 16px;
padding: 30px;
overflow-y: auto;
}
.logLine {
color: white;
}
.logLine.exception {
color: red;
}
.logLine.system {
color: blue;
}
.logType {
display: inline-block;
font-weight: lighter;
}
.logMsg {
display: inline-block;
font-weight: 300;
white-space: pre-wrap;
}
.pastPluginUrl {
margin-left: auto;
margin-right: auto;
width: 500px;
text-align: center;
margin-top: 10px;
margin-bottom: 10px;
padding: 10px;
background-color: #1e1e1e;
border-radius: 50px;
box-shadow: 0px 1px 2px #131313;
font-weight: lighter;
cursor: pointer;
}
</style>
</head>
<body>
<div id="app">
<v-app>
<v-main>
<div id="topMenu">
<div style="height: 100%; display: inline-block; padding-left: 10px; padding-right: 20px;">
<img src="./dependencies/FutoMainLogo.svg"
style="margin-top: 20px;" />
</div>
<div class="menuTab" :class="{ 'active': page == 'Plugin' }" @click="page = 'Plugin'">
Overview
</div>
<div class="menuTab" :class="{ 'active': page == 'Testing' }" @click="page = 'Testing'">
Testing
</div>
<div class="menuTab" :class="{ 'active': page == 'Integration' }" @click="page = 'Integration'">
Integration
</div>
<div class="menuTab" :class="{ 'active': page == 'Settings' }" @click="page = 'Settings'">
Settings
</div>
<div style="right: 370px; top: 15px; position: absolute" v-if="Plugin?.currentPlugin?.authentication">
<v-btn @click="loginTestPlugin()" v-if="!Plugin.isLoggedIn">
Login
</v-btn>
<v-btn @click="logoutTestPlugin()" v-if="Plugin.isLoggedIn">
Logout
</v-btn>
</div>
<img v-if="Plugin.currentPlugin"
:src="Plugin.currentPluginIcon"
style="right: 300px; top: 10px; width: 50px; width: 50px; position: absolute;" />
<div v-if="Plugin.currentPlugin" style="position: absolute; right: 100px; top: 12px; width: 180px;">
<div>
{{Plugin.currentPlugin.name}}
</div>
<div>
Last updated: {{Plugin.lastLoadTime}}
</div>
</div>
<v-btn class="mx-2" fab dark color="#140a4a" style="position: absolute; right: 10px; top: 5px;"
@click="reloadPlugin()" v-if="Plugin.currentPluginUrl">
<v-icon dark>mdi-refresh</v-icon>
</v-btn>
</div>
<div id="mainContainer">
<div class="page" v-if="page == 'Plugin'">
<div v-if="!Plugin.currentPlugin && !Plugin.currentScript">
<div style="margin-left: auto; margin-right: auto; width: 750px; vertical-align: top; padding-left: 40px;">
<v-card style="width: 450px; margin-top: 80px; display: inline-block;">
<v-card-text>
<div>
<v-text-field label="Plugin Config Json Url"
v-model="Plugin.newPluginUrl"></v-text-field>
<div style="margin-top: -10px;">
<v-switch v-model="Plugin.loadUsingTag"
label="Load using script tag"></v-switch>
<div style="font-size: 11px; margin-top: -20px; color: #888888">
Loading via script tag might give issues reloading script, as it makes the script part of DOM, but does allow debugging via dev console.
</div>
</div>
</div>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn @click="loadPlugin(Plugin.newPluginUrl)">Load Plugin</v-btn>
</v-card-actions>
</v-card>
<v-card style="width: 250px; margin-top: 80px; display: inline-block; vertical-align: top;">
<v-card-title>
Package Overrides
</v-card-title>
<v-card-text>
<div>
<div style="font-size: 12px; font-weight: lighter;">
Enabling a package override replaces the package with a browser implementation.
This generally improves speed, at the cost of test accuracy.
</div>
<div v-for="(value, name, index) in Plugin.packagesOverridden">
<v-switch v-model="Plugin.packagesOverridden[name]" :label="name" :change="saveOverrides()"></v-switch>
</div>
</div>
</v-card-text>
</v-card>
</div>
<div v-if="pastPluginUrls" style="margin-top: 60px;">
<h2 style="font-weight: lighter; text-align: center;">Past Plugins</h2>
<div class="pastPluginUrl" v-for="pastPluginUrl in pastPluginUrls" @click="this.Plugin.newPluginUrl = pastPluginUrl; loadPlugin(pastPluginUrl)">
{{pastPluginUrl}}
</div>
</div>
</div>
<v-card style="width: 500px; margin-left: auto; margin-right: auto; margin-top: 20px;"
v-if="Plugin.currentPluginError">
<v-card-text>
<div>
<h2 style="color: red">Errors in Plugin</h2>
{{Plugin.currentPluginError}}
</div>
</v-card-text>
</v-card>
<v-card style="width: 500px; margin-left: auto; margin-right: auto; margin-top: 20px;"
v-if="Plugin.currentPlugin && Plugin.currentScript">
<v-card-text>
<div>
<h2>Your plugin is loaded</h2>
You can now use testing methods available on the webapp. <br /> <br />
The information and warnings the user will see when installing the app can be viewed below.
</div>
</v-card-text>
</v-card>
<v-card style="width: 500px; margin-left: auto; margin-right: auto; margin-top: 20px;"
v-if="Plugin.currentPlugin && Plugin.currentScript">
<v-card-text>
<div>
<div style="height: 100px;">
<img :src="Plugin.currentPluginIcon"
style="width: 100px; position: absolute; top: 0px; left: 0px; margin: 10px;" />
<div style="position: absolute; right: 5px; top: 5px;">
Last updated: {{Plugin.lastLoadTime}}
</div>
<div style="width: calc(100% - 100px); height: 100px; position: absolute; top: 0px; right: 0px; padding-top: 40px; padding-left: 40px;">
<h2>{{Plugin.currentPlugin.name}}</h2>
<div>
<span>By </span>
<span v-if="!Plugin.currentPlugin.authorUrl">{{Plugin.currentPlugin.author}}</span>
<span v-if="Plugin.currentPlugin.authorUrl">
<a :href="Plugin.currentPlugin.authorUrl" style="text-decoration: none;">
{{Plugin.currentPlugin.author}}
</a>
</span>
</div>
</div>
</div>
<div style="color: #999999">
{{Plugin.currentPlugin.description}}
</div>
<div style="margin-top: 30px;">
<div class="property">
<div class="key">
Version
</div>
<div class="value">
{{Plugin.currentPlugin.version}}
</div>
</div>
<div class="property">
<div class="key">
Repository URL
</div>
<div class="value">
<a :href="Plugin.currentPlugin.scriptUrl">
{{Plugin.currentPlugin.repositoryUrl}}
</a>
</div>
</div>
<div class="property">
<div class="key">
Script URL
</div>
<div class="value">
<a :href="Plugin.currentPlugin.scriptUrl">
{{Plugin.currentPlugin.scriptUrl}}
</a>
</div>
</div>
</div>
</div>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<a href="/reference_autocomplete.js" download="ref.js" style="text-decoration: none; margin-right: 10px;">
<v-btn>Ref.js</v-btn>
</a>
<a href="/reference_plugin.d.ts" download="plugin.d.ts" style="text-decoration: none; margin-right: 10px;">
<v-btn>Plugin.d.ts</v-btn>
</a>
<v-btn @click="reloadPlugin()">Reload</v-btn>
</v-card-actions>
</v-card>
<div v-if="Plugin.warnings && Plugin.warnings.length > 0">
<h2 style="text-align: center; margin-top: 40px;">Warnings</h2>
<div style="text-align: center; color: #999999; font-size: 14px;">
These are the warnings a user will see when they attempt to install this plugin
</div>
<v-card style="width: 500px; margin-left: auto; margin-right: auto; margin-top: 20px; min-height: 130px;"
v-for="warning in Plugin.warnings">
<v-card-text>
<div>
<div class="material-symbols-outlined"
style="width: 100px; margin: 10px; color: rgb(194, 83, 83); font-size: 100px; position: absolute; top: 10px; left: 10px;">
security
</div>
<div style="margin-left: 120px;">
<div style="font-size: 18px;">
{{warning.first}}
</div>
<div style="color: #C25353">
{{warning.second}}
</div>
</div>
</div>
</v-card-text>
</v-card>
</div>
</div>
<div class="page" v-if="page == 'Testing'">
<v-card style="margin-top: 20px; margin-bottom: 20px; margin-left: auto; margin-right: auto; width: 500px;" v-if="!Plugin.currentPlugin">
<v-card-title>
No Plugin Loaded
</v-card-title>
</v-card-header>
<v-card-text>
<div>
Load a plugin before doing testing.
</div>
</v-card-text>
</v-card>
<div style="width: 50%" v-if="Plugin.currentPlugin">
<!--Get Home-->
<v-card class="requestCard" v-for="req in Testing.requests">
<v-card-text>
<div class="title">
<span v-if="req.isOptional">(Optional)</span>
<span>{{req.title}}</span>
</div>
<!--
<div v-if="req.title == 'enable'" style="position: absolute; top:3px; right: 18px">
<v-checkbox v-model="Plugin.enableOnReload" label="Enable on Refresh" />
</div> -->
<div class="description">
{{req.description}}
</div>
<div class="code">
{{req.code}}
</div>
<div>
<div class="parameter" v-for="parameter in req.parameters">
<div class="name">
{{parameter.name}}
</div>
<div class="description">
{{parameter.description}}
</div>
<input type="text" :placeholder="parameter.name + ' value'" v-model="parameter.value" />
</div>
</div>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn @click="testSource(req)">
Test
</v-btn>
</v-card-actions>
</v-card>
</div>
<div style="position: fixed; right: 0px; top: 70px;width: 50%; height: 100%; background-color: black;" v-if="Plugin.currentPlugin">
<h2 style="padding: 10px; font-weight: lighter;">Results</h2>
<div style="position: absolute; top: 10px; right: 10px;">
<v-btn @click="copyClipboard(Testing.lastResult)" v-if="Testing.lastResult && !Testing.lastResultError">Copy</v-btn>
</div>
<div v-if="!Testing.lastResult && !Testing.lastResultError" style="padding: 10px; font-weight: lighter;">
No test done yet
</div>
<div v-if="Testing.lastResult && !Testing.lastResultError" class="testResult">{{Testing.lastResult}}</div>
<div v-if="Testing.lastResultError" class="testResult exception">{{Testing.lastResultError}}</div>
</div>
</div>
<div class="page" v-if="page == 'Integration'">
<v-card style="margin-top: 20px; margin-bottom: 20px; margin-left: auto; margin-right: auto; width: 500px;" v-if="!Plugin.currentPlugin">
<v-card-title>
No Plugin Loaded
</v-card-title>
</v-card-header>
<v-card-text>
<div>
Load a plugin before doing integration testing.
</div>
</v-card-text>
</v-card>
<v-card style="width: 500px; margin-left: auto; margin-right: auto; margin-top: 20px;"
v-if="Plugin.currentPluginError">
<v-card-text>
<div>
<h2 style="color: red">Errors in Plugin</h2>
Its best to fix errors before doing any integration testing
</div>
</v-card-text>
</v-card>
<v-card style="margin-top: 20px; margin-bottom: 20px; margin-left: auto; margin-right: auto; width: 500px;" v-if="Plugin.currentPlugin">
<v-card-title>
Integration Testing
</v-card-title>
</v-card-header>
<v-card-text>
<div>
<div style="margin-bottom: 10px;">
Integration testing allows you to upload your loaded plugin onto your phone, and get logs below to find any exceptions in actual usage.
</div>
<div v-if="Integration.lastInjectTime">
Last Injected: {{Integration.lastInjectTime}} <br />
Click Inject Plugin again to update to last version.
</div>
<div v-if="!Integration.lastInjectTime">
Plugin is not yet injected. Click "Inject Plugin" to load the plugin on your phone.
</div>
</div>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn @click="injectDevPlugin()">Inject Plugin</v-btn>
</v-card-actions>
</v-card>
<v-card style="margin: 20px;" v-if="Plugin.currentPlugin">
<v-card-title>
Device Logs
</v-card-title>
</v-card-header>
<v-card-text>
<div class="logContainer">
<div class="logLine" v-for="line in Integration.logs" :class="{exception: line.type == 'EXCEPTION', system: line.type == 'SYSTEM'}">
<div class="logType" style="vertical-align: top;">
[{{line.type}}]
</div>
<div class="logMsg">{{line.log}}</div>
</div>
</div>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn>Clear</v-btn>
</v-card-actions>
</v-card>
</div>
<div class="page" v-if="page == 'Settings'">
<v-card style="margin-top: 20px; margin-bottom: 20px; margin-left: auto; margin-right: auto; width: 500px;">
<v-card-title>
Settings
</v-card-title>
</v-card-header>
<v-card-text>
<div>
<div style="height: 30px;">
<v-checkbox label="Enable on Reload" v-model="settings.enableOnReload"></v-checkbox>
</div>
<div style="height: 30px;">
<v-checkbox label="Login on Reload" v-model="settings.loginOnReload">></v-checkbox>
</div>
</div>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn @click="saveSettings()">Save</v-btn>
</v-card-actions>
</v-card>
</div>
</div>
</v-main>
</v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.7.1/dist/vuetify.min.js"></script>
<!--<script src="./dependencies/vue.js"></script>-->
<!--<script src="./dependencies/vuetify.js"></script>-->
<script src="./source_docs.js"></script>
<script src="./source.js"></script>
<script src="./dev_bridge.js"></script>
<script>
IS_TESTING = true;
let lastScriptTag = null;
new Vue({
el: '#app',
data: {
page: "Plugin",
pastPluginUrls: [],
settings: {},
Integration: {
lastLogIndex: -1,
lastLogDevID: "",
logs: [],
lastInjectTime: ""
},
Plugin: {
loadUsingTag: false,
newPluginUrl: "",
packagesOverridden: packageOverridesEnabled,
currentPluginUrl: "",
currentPlugin: null,
currentPluginError: "",
currentScript: "",
lastLoadTime: "",
didInitialLoad: false,
enableOnReload: false,
isLoggedIn: false
},
Testing: {
requests: sourceDocs.map(x=>{
x.parameters.forEach(y=>y.value = null);
return x;
}),
lastResult: "",
lastResultError: ""
}
},
mounted() {
let existing = localStorage.getItem("pastPlugins");
if(!existing)
existing = [];
else
existing = JSON.parse(existing);
let settingsStr = localStorage.getItem("settings");
if(!settingsStr)
this.settings = {};
else
this.settings = JSON.parse(settingsStr);
this.pastPluginUrls = existing.slice(0, 5);
this.loadOverrides();
window.onerror = (event, source, lineno, colno, error)=>{
Vue.nextTick(()=>{
if(error)
this.Plugin.currentPluginError = error + " (" + lineno + ", " + colno + ")";
else
this.Plugin.currentPluginError = "There is an error in your script, check console for info";
});
};
setInterval(()=>{
try{
if(!this.Plugin.currentPlugin)
return;
getDevLogs(this.Integration.lastLogIndex, (newLogs)=> {
if(newLogs.length > 0) {
let firstLog = newLogs[0];
let lastLog = newLogs[newLogs.length - 1];
Vue.nextTick(()=>{
let lastDevId = this.Integration.lastLogDevID;
this.Integration.lastLogDevID = lastLog.devId;
this.Integration.lastLogIndex = lastLog.id;
for(i = 0; i < newLogs.length; i++) {
const log = newLogs[i];
console.log("Log", log);
if(lastDevId != log.devId) {
this.Integration.logs = [];
lastDevId = log.devId;
this.Integration.logs.unshift({
id: -1,
devId: lastDevId,
message: "New Dev Session: " + lastDevId
});
}
this.Integration.logs.unshift(log)
};
});
}
});
}
catch(ex) {
console.error("Failed update", ex);
}
}, 1000);
setInterval(()=>{
try{
this.isTestLoggedIn();
}catch(ex){}
}, 2500);
},
methods: {
loadOverrides() {
let overridesExisting = localStorage.getItem("overrides");
if(overridesExisting && overridesExisting != "undefined") {
try{
const overrides = JSON.parse(overridesExisting);
for(override in this.Plugin.packagesOverridden) {
if(overrides[override])
this.Plugin.packagesOverridden[override] = true;
}
}
catch(ex) {
console.error(ex);
}
}
this.Plugin.didInitialLoad = true;
},
saveOverrides() {
if(this.Plugin.packagesOverridden && this.Plugin.didInitialLoad) {
let overridesExisting = JSON.stringify(this.Plugin.packagesOverridden);
localStorage.setItem("overrides", overridesExisting);
}
},
loadPlugin(url) {
Vue.nextTick(()=>{
this.Plugin.currentPluginUrl = url;
this.reloadPlugin();
});
},
loginTestPlugin() {
pluginLoginTestPlugin();
setTimeout(()=>{
reloadPackages();
this.isTestLoggedIn((loggedIn)=>{
if(loggedIn && this.settings.enableOnReload)
this.testSource(this.Testing.requests.find(x=>x.title == 'enable'));
});
}, 1000);
},
logoutTestPlugin() {
pluginLogoutTestPlugin();
},
reloadPlugin() {
const url = this.Plugin.currentPluginUrl;
const pluginResp = httpGETBypass(url, {}, "text/json");
if(pluginResp.code != 200) {
alert("Failed to get plugin, check log")
console.error("Failed to get plugin", pluginResp);
}
else {
this.Plugin.currentPlugin = JSON.parse(pluginResp.body);
this.Plugin.currentPlugin.sourceUrl = url;
}
this.Plugin.currentPluginIcon = new URL(this.Plugin.currentPlugin.iconUrl, url).href
let currentPastPlugins = this.pastPluginUrls;
currentPastPlugins = currentPastPlugins.filter(x=>x.toLowerCase() != url.toLowerCase());
currentPastPlugins.unshift(url);
this.pastPluginUrls = currentPastPlugins;
localStorage.setItem("pastPlugins", JSON.stringify(currentPastPlugins));
try {
this.Plugin.warnings = pluginGetWarnings(this.Plugin.currentPlugin);
}
catch(ex) {
alert("Failed to validate config, check log")
console.error("Failed to validate config", ex);
return;
}
if(!this.Plugin.currentPlugin.scriptUrl) {
alert("Misssing plugin script, check log")
console.error("Failed to get plugin due to missing script");
}
let absScriptUrl = new URL(this.Plugin.currentPlugin.scriptUrl, url).href;
console.log("Loading script (Abs):" + absScriptUrl);
const scriptResp = httpGETBypass(absScriptUrl, {}, "application/js");
if(pluginResp.code != 200) {
alert("Failed to get plugin")
console.error("Failed to get plugin", pluginResp);
}
else {
this.Plugin.currentScript = scriptResp.body;
try{
//TODO: Load packages
const testPluginPackages = pluginUpdateTestPlugin(this.Plugin.currentPlugin);
console.log("Required packages:", testPluginPackages);
applyPackages(testPluginPackages);
if(this.Plugin.loadUsingTag)
{
this.Plugin.currentPluginError = ""
//Create script tag
const scriptUrl = absScriptUrl + "?x=" + new Date().getTime();
if(lastScriptTag)
lastScriptTag.parentNode.removeChild(lastScriptTag);
lastScriptTag = document.createElement('script');
lastScriptTag.src = scriptUrl;
lastScriptTag.crossorigin = "anonymous";
lastScriptTag.onerror = function() {
Vue.nextTick(()=>{
this.Plugin.currentPluginError = "Exception loading script: " + scriptUrl;
});
}
document.getElementsByTagName('body')[0].appendChild(lastScriptTag);
}
else
eval(this.Plugin.currentScript);
const date = new Date();
this.Plugin.lastLoadTime =
(date.getHours()+"").padStart(2, '0') + ":" +
(date.getMinutes()+"").padStart(2, '0') + ":" +
(date.getSeconds()+"").padStart(2, '0');
if(this.settings.loginOnReload) {
this.loginTestPlugin()
}
else if(this.settings.enableOnReload)
this.testSource(this.Testing.requests.find(x=>x.title == 'enable'));
}
catch(ex) {
alert("Failed to load plugin script, check log");
console.error("Failed to load plugin script", ex);
this.Plugin.currentPluginError = "Exception loading script:\n" + ex;
}
}
},
isTestLoggedIn(cb) {
pluginIsLoggedIn((isLoggedIn)=> {
Vue.nextTick(()=>{
const hasChanged = isLoggedIn != isLoggedIn;
this.Plugin.isLoggedIn = isLoggedIn;
if(hasChanged)
clearPackages();
if(cb)
cb(isLoggedIn);
});
}, (ex)=> {
if(cb)
cb(false);
});
},
injectDevPlugin() {
this.Integration.lastLogDevID = uploadDevPlugin(this.Plugin.currentPlugin);
this.Integration.logs = [
{
id: -1,
devId: this.Integration.lastLogDevID,
type: 'SYSTEM',
log: 'New Injected Session [' + this.Integration.lastLogDevID + ']'
}
];
const date = new Date();
this.Integration.lastInjectTime =
(date.getHours()+"").padStart(2, '0') + ":" +
(date.getMinutes()+"").padStart(2, '0') + ":" +
(date.getSeconds()+"").padStart(2, '0');
},
testSource(req) {
const name = req.title;
const parameterVals = req.parameters.map(x=>{
if(x.value && x.value.startsWith && x.value.startsWith("json:"))
return JSON.parse(x.value.substring(5));
return x.value
});
if(name == "enable") {
if(parameterVals.length > 0)
parameterVals[0] = this.Plugin.currentPlugin;
else
parameterVals.push(this.Plugin.currentPlugin);
if(parameterVals.length > 1)
parameterVals[1] = __DEV_SETTINGS;
else
parameterVals.push(__DEV_SETTINGS);
}
const func = source[name];
if(!func)
alert("Test func not found");
try {
const result = func(...parameterVals);
console.log("Result for " + req.title, result);
this.Testing.lastResult = "//Results [" + name + "]\n" +
JSON.stringify(result, null, 3);
this.Testing.lastResultError = "";
}
catch(ex) {
console.error("Failed to run test for " + req.title, ex);
this.Testing.lastResult = ""
if(ex.message)
this.Testing.lastResultError = "//Results [" + name + "]\n\n" +
"Error: " + ex.message + "\n\n" + ex.stack;
else
this.Testing.lastResultError = "//Results [" + name + "]\n\n" +
"Error: " + ex;
}
},
showTestResults(results) {
},
copyClipboard(cpy) {
if(navigator.clipboard)
navigator.clipboard.writeText(cpy);
else {
var textArea = document.createElement("textarea");
textArea.value = cpy;
textArea.style.top = "0";
textArea.style.left = "0";
textArea.style.position = "fixed";
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
document.execCommand('copy');
} catch (err) { console.error('Failed to copy', err); }
document.body.removeChild(textArea);
}
},
saveSettings() {
let settingsStr = JSON.stringify(this.settings);
localStorage.setItem("settings", settingsStr);
}
},
vuetify: new Vuetify({
theme: {
dark: true
}
}),
});
function copyTextToClipboard(text) {
if (!navigator.clipboard) {
fallbackCopyTextToClipboard(text);
return;
}
navigator.clipboard.writeText(text).then(function() {
console.log('Async: Copying to clipboard was successful!');
}, function(err) {
console.error('Async: Could not copy text: ', err);
});
}
</script>
</body>
</html>