276 lines
6.9 KiB
HTML
276 lines
6.9 KiB
HTML
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="en">
|
|||
|
|
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<title>vMenu</title>
|
|||
|
|
</head>
|
|||
|
|
|
|||
|
|
<style>
|
|||
|
|
@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
|
|||
|
|
|
|||
|
|
* {
|
|||
|
|
margin: 0;
|
|||
|
|
padding: 0;
|
|||
|
|
text-align: center;
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
font-family: 'Roboto', sans-serif;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#body {
|
|||
|
|
margin-top: 50px;
|
|||
|
|
max-width: 1200px;
|
|||
|
|
margin-left: auto;
|
|||
|
|
margin-right: auto;
|
|||
|
|
background-color: rgba(255, 255, 255, 0.8);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.error {
|
|||
|
|
background-color: lightcoral;
|
|||
|
|
color: rgb(121, 34, 34);
|
|||
|
|
padding: 30px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
input[type="checkbox"]:not(:checked)+div {
|
|||
|
|
display: none;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
hr {
|
|||
|
|
margin-top: 10px;
|
|||
|
|
margin-bottom: 10px;
|
|||
|
|
border: none;
|
|||
|
|
border-top: 1px solid lightgray;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
button:not(#close-button) {
|
|||
|
|
padding: 5px 10px;
|
|||
|
|
border: none;
|
|||
|
|
border-radius: 3px;
|
|||
|
|
background-color: #0075ff;
|
|||
|
|
font-size: 14px;
|
|||
|
|
color: white;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#close-button {
|
|||
|
|
position: relative;
|
|||
|
|
top: 0;
|
|||
|
|
right: 5px;
|
|||
|
|
background: none;
|
|||
|
|
border: none;
|
|||
|
|
float: right;
|
|||
|
|
font-size: 20px;
|
|||
|
|
font-weight: 100;
|
|||
|
|
color: gray;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.grid {
|
|||
|
|
display: grid;
|
|||
|
|
grid-template-columns: repeat(2, 1fr);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.column {
|
|||
|
|
padding: 20px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.column:first-of-type {
|
|||
|
|
border-right: 1px solid lightgray;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
textarea {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 100%;
|
|||
|
|
text-align: left;
|
|||
|
|
padding: 5px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
strong {
|
|||
|
|
color: rgb(189, 45, 45);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.mt {
|
|||
|
|
display: block;
|
|||
|
|
margin-top: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.mb {
|
|||
|
|
display: block;
|
|||
|
|
margin-bottom: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.left {
|
|||
|
|
text-align: left;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ol,
|
|||
|
|
li {
|
|||
|
|
text-align: left;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ol {
|
|||
|
|
margin-left: 20px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
input[type=file] {
|
|||
|
|
margin-top: 8px;
|
|||
|
|
margin-bottom: 8px;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
|
|||
|
|
<body>
|
|||
|
|
<div id="body"
|
|||
|
|
hidden>
|
|||
|
|
<button id="close-button">×</button>
|
|||
|
|
<h2 class="mt">IMPORTANT</h2>
|
|||
|
|
<p class="mb"><strong>Use this feature at your own risk, YOU are
|
|||
|
|
responsible for any potential data loss or corruption.</strong>
|
|||
|
|
</p>
|
|||
|
|
<input type="checkbox"> I accept the risk and take full responsibility
|
|||
|
|
for my actions, now let me in!
|
|||
|
|
<div class="mt mb">
|
|||
|
|
<div class="error"
|
|||
|
|
id="error-div"
|
|||
|
|
hidden>
|
|||
|
|
</div>
|
|||
|
|
<div class="grid">
|
|||
|
|
<div class="column">
|
|||
|
|
<form onsubmit="importData()">
|
|||
|
|
<div class="group">
|
|||
|
|
<h3>Import vMenu data</h3>
|
|||
|
|
<p>
|
|||
|
|
<strong>Warning</strong>: This <em>will</em>
|
|||
|
|
replace any existing data.
|
|||
|
|
Make a backup before you do this!
|
|||
|
|
</p>
|
|||
|
|
<textarea id="import-data"
|
|||
|
|
class="mt mb"
|
|||
|
|
placeholder="Paste the JSON data in here."
|
|||
|
|
rows="5"></textarea>
|
|||
|
|
<p class="mt mb">Alternatively, select a JSON file
|
|||
|
|
containing exported data directly.</p>
|
|||
|
|
<strong>Note:</strong>
|
|||
|
|
<p>
|
|||
|
|
This probably won't work when you're in
|
|||
|
|
fullscreen mode.
|
|||
|
|
</p>
|
|||
|
|
<input type="file"
|
|||
|
|
id="import-file"
|
|||
|
|
placeholder="Import a file">
|
|||
|
|
<hr>
|
|||
|
|
<button type="submit">Click to import data</button>
|
|||
|
|
</div>
|
|||
|
|
</form>
|
|||
|
|
</div>
|
|||
|
|
<div class="column">
|
|||
|
|
<form>
|
|||
|
|
<div class="group">
|
|||
|
|
<h3>Export vMenu data</h3>
|
|||
|
|
<strong>Note:</strong>
|
|||
|
|
<p class="mt">Do not edit the contents of this
|
|||
|
|
export if you don't know what you're doing.
|
|||
|
|
Importing edited content may result in data
|
|||
|
|
corruption. Which means that all your saved data
|
|||
|
|
will be deleted when you restart your game.</p>
|
|||
|
|
<strong class="mt">Instructions:</strong>
|
|||
|
|
<ol>
|
|||
|
|
<li>
|
|||
|
|
Select all text using <kbd>CTRL + A</kbd> in
|
|||
|
|
the textarea below, and use <kbd>CTRL +
|
|||
|
|
C</kbd> to copy it.
|
|||
|
|
</li>
|
|||
|
|
<li>
|
|||
|
|
Use <kbd>CTRL + V</kbd> to paste the data in
|
|||
|
|
something like notepad.
|
|||
|
|
</li>
|
|||
|
|
<li>
|
|||
|
|
Save the file somewhere as a
|
|||
|
|
<kbd>.json</kbd> file.
|
|||
|
|
</li>
|
|||
|
|
</ol>
|
|||
|
|
<textarea rows="5"
|
|||
|
|
disabled
|
|||
|
|
class="mt left"
|
|||
|
|
placeholder="Exported data will appear here automatically, if you see this text, something went wrong :("
|
|||
|
|
id="output"></textarea>
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
</form>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
document.getElementById("close-button").onclick = () => {
|
|||
|
|
event.preventDefault();
|
|||
|
|
document.getElementById("body").setAttribute("hidden", "");
|
|||
|
|
fetch(`https://${GetParentResourceName()}/disableImportExportNUI`, {
|
|||
|
|
method: 'POST',
|
|||
|
|
headers: {
|
|||
|
|
'Content-Type': 'application/json; charset=UTF-8',
|
|||
|
|
},
|
|||
|
|
body: JSON.stringify({ close: true })
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var jsonData = "{}";
|
|||
|
|
var error_div = document.getElementById("error-div");
|
|||
|
|
var importTextField = document.getElementById("import-data");
|
|||
|
|
|
|||
|
|
function importData() {
|
|||
|
|
event.preventDefault();
|
|||
|
|
error_div.setAttribute("hidden", "");
|
|||
|
|
|
|||
|
|
let el = document.getElementById("import-file");
|
|||
|
|
if (el != null && el.files.length == 1) {
|
|||
|
|
let file = el.files[0];
|
|||
|
|
if (file != null && file.type === "application/json") {
|
|||
|
|
let reader = new FileReader();
|
|||
|
|
reader.onload = (a) => {
|
|||
|
|
jsonData = a.target.result;
|
|||
|
|
postImportData();
|
|||
|
|
};
|
|||
|
|
reader.readAsText(file);
|
|||
|
|
} else {
|
|||
|
|
if ((importTextField.value || "").trim() != "") {
|
|||
|
|
jsonData = importTextField.value;
|
|||
|
|
postImportData();
|
|||
|
|
return;
|
|||
|
|
} else {
|
|||
|
|
error_div.removeAttribute("hidden");
|
|||
|
|
error_div.innerText = "No valid JSON file is selected and the textarea is empty!";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
if ((importTextField.value || "").trim() != "") {
|
|||
|
|
jsonData = importTextField.value;
|
|||
|
|
postImportData();
|
|||
|
|
return;
|
|||
|
|
} else {
|
|||
|
|
error_div.removeAttribute("hidden");
|
|||
|
|
error_div.innerText = "You did not select a file and the textarea is empty!";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function postImportData() {
|
|||
|
|
fetch(`https://vMenu/importData`, {
|
|||
|
|
method: 'POST',
|
|||
|
|
headers: {
|
|||
|
|
'Content-Type': 'application/json; charset=UTF-8',
|
|||
|
|
},
|
|||
|
|
body: jsonData
|
|||
|
|
}).then(resp => resp.json()).then(resp => {
|
|||
|
|
document.getElementById("body").setAttribute("hidden", "");
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
window.addEventListener("message", (data) => {
|
|||
|
|
document.getElementById("body").removeAttribute("hidden");
|
|||
|
|
document.getElementById("output").innerText = JSON.stringify(data.data);
|
|||
|
|
})
|
|||
|
|
</script>
|
|||
|
|
</body>
|
|||
|
|
|
|||
|
|
|
|||
|
|
</html>
|