forked from lamp/vrchat-emoji-manager
This commit is contained in:
parent
d1de5350e1
commit
f748d0b771
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
react
|
||||
package.json
|
||||
package-lock.json
|
2
edit.js
2
edit.js
@ -45,7 +45,7 @@ async function instantiateRow(url, internalId, animationStyle) {
|
||||
c0.appendChild(img);
|
||||
|
||||
let select = document.createElement("select");
|
||||
animationStyles.forEach(a => {
|
||||
ANIMATION_STYLES.forEach(a => {
|
||||
let option = document.createElement("option");
|
||||
option.innerText = a;
|
||||
option.value = a.toLowerCase();
|
||||
|
@ -25,8 +25,5 @@
|
||||
"background": {
|
||||
"service_worker": "background.js",
|
||||
"type": "module"
|
||||
},
|
||||
"action": {
|
||||
"default_popup": "toggle.html"
|
||||
}
|
||||
}
|
21
toggle.html
21
toggle.html
@ -1,11 +1,7 @@
|
||||
<!DOCTYPE html><html><head>
|
||||
<meta charset="UTF-8" />
|
||||
<style>
|
||||
#topright {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
#emojigrid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@ -19,6 +15,7 @@
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
}
|
||||
.emojisquare .imgcontainer img {
|
||||
max-width: 100%;
|
||||
@ -26,15 +23,20 @@
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.enabled {
|
||||
[data-state=enabled] {
|
||||
background-color:rgba(0, 255, 0, 0.5);
|
||||
}
|
||||
.disabled {
|
||||
[data-state=disabled] {
|
||||
background-color:rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.pending {
|
||||
[data-state=pending] {
|
||||
background-color:rgba(255, 255, 0, 0.5);
|
||||
}
|
||||
|
||||
#emojiadd {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
#errorDiv {
|
||||
color: red;
|
||||
}
|
||||
@ -43,6 +45,7 @@
|
||||
<h1>VRChat Emoji Manager</h1>
|
||||
<div id="emojigrid"></div>
|
||||
<div id="errorDiv"></div>
|
||||
|
||||
<div id="emojiadd">Add more!!! <input type="file" id="fileinput" accept="image/png,image/jpeg" multiple /> <select id="default_animation_style_select" value="aura"><option value="aura">Aura</option><option value="bats">Bats</option><option value="bees">Bees</option><option value="bounce">Bounce</option><option value="cloud">Cloud</option><option value="confetti">Confetti</option><option value="crying">Crying</option><option value="dislike">Dislike</option><option value="fire">Fire</option><option value="idea">Idea</option><option value="lasers">Lasers</option><option value="like">Like</option><option value="magnet">Magnet</option><option value="mistletoe">Mistletoe</option><option value="money">Money</option><option value="noise">Noise</option><option value="orbit">Orbit</option><option value="pizza">Pizza</option><option value="rain">Rain</option><option value="rotate">Rotate</option><option value="shake">Shake</option><option value="snow">Snow</option><option value="snowball">Snowball</option><option value="spin">Spin</option><option value="splash">Splash</option><option value="stop">Stop</option><option value="zzz">ZZZ</option></select> <input type="submit" id="submit" value="Add" /></div>
|
||||
<div><button id="deletemodebtn">Delete Emojis</button></div>
|
||||
<script src="toggle.js"></script>
|
||||
</body></html>
|
135
toggle.js
135
toggle.js
@ -1,4 +1,4 @@
|
||||
var animationStyles = `Aura
|
||||
const ANIMATION_STYLES = `Aura
|
||||
Bats
|
||||
Bees
|
||||
Bounce
|
||||
@ -28,7 +28,7 @@ ZZZ`.split('\n');
|
||||
|
||||
function createAnimationStyleSelect() {
|
||||
let select = document.createElement("select");
|
||||
animationStyles.forEach(a => {
|
||||
ANIMATION_STYLES.forEach(a => {
|
||||
let option = document.createElement("option");
|
||||
option.innerText = a;
|
||||
option.value = a.toLowerCase();
|
||||
@ -43,6 +43,48 @@ function createAnimationStyleSelect() {
|
||||
|
||||
|
||||
|
||||
submit.onclick = async () => {
|
||||
submit.disabled = true;
|
||||
var newEmoji = [];
|
||||
for (let file of fileinput.files) {
|
||||
let e = {
|
||||
internalId: randomId(),
|
||||
animationStyle: default_animation_style_select.value,
|
||||
};
|
||||
let data = await fileToDataURL(file);
|
||||
//todo convert/resize
|
||||
await chrome.storage.local.set({["data-"+e.internalId]: data});
|
||||
newEmoji.push(e);
|
||||
instantiateRow(data, e.internalId, e.animationStyle);
|
||||
}
|
||||
var {emoji} = await chrome.storage.local.get("emoji");
|
||||
emoji = emoji.concat(newEmoji);
|
||||
await chrome.storage.local.set({emoji});
|
||||
fileinput.value = "";
|
||||
submit.disabled = false;
|
||||
};
|
||||
|
||||
|
||||
var deleteMode = false;
|
||||
deletemodebtn.onclick = () => {
|
||||
if (deleteMode) {
|
||||
deleteMode = false;
|
||||
deletemodebtn.innerText = "Delete Emojis";
|
||||
return;
|
||||
}
|
||||
alert("Delete mode activated, click emojis to delete.");
|
||||
deleteMode = true;
|
||||
deletemodebtn.innerText = "CANCEL DELETE MODE";
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
loadEmojis().catch(displayError);
|
||||
@ -80,14 +122,13 @@ async function loadEmojis() {
|
||||
}
|
||||
|
||||
async function loadToggleState() {
|
||||
console.debug("loadToggleState");
|
||||
var elements = document.querySelectorAll(".emojisquare");
|
||||
if (elements.length === 0) return;
|
||||
var currentEmojis = await callContentScript("getEmojis");
|
||||
var active = currentEmojis?.map(e => e.id);
|
||||
elements.forEach(e => {
|
||||
var yes = active.includes(e.dataset.currentId);
|
||||
e.classList.add(yes ? "enabled" : "disabled");
|
||||
e.classList.remove(yes ? "disabled" : "enabled");
|
||||
e.dataset.state = active.includes(e.dataset.currentId) ? "enabled" : "disabled";
|
||||
});
|
||||
}
|
||||
|
||||
@ -119,46 +160,52 @@ async function callContentScript(method, ...args) {
|
||||
};
|
||||
|
||||
async function toggleEmoji(event) {
|
||||
if (this.classList.contains("pending")) return;
|
||||
this.classList.add("pending");
|
||||
if (this.dataset.state == "pending") return;
|
||||
var selectedState = this.dataset.state;
|
||||
this.dataset.state = "pending";
|
||||
errorDiv.innerText = "";
|
||||
|
||||
if (document.querySelectorAll(".enabled").length + document.querySelectorAll(".disabled").length < document.querySelectorAll(".emojisquare").length) {
|
||||
if (emojigrid.querySelector(".emojisquare:not([data-state])")) {
|
||||
try {
|
||||
await loadToggleState();
|
||||
} catch (error) {
|
||||
displayError(error);
|
||||
this.classList.remove("pending");
|
||||
this.dataset.state = selectedState;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.classList.contains("enabled")) {
|
||||
if (selectedState == "enabled") {
|
||||
// disable
|
||||
callContentScript("deleteEmoji", this.dataset.currentId).then(() => {
|
||||
this.classList.remove("pending");
|
||||
this.classList.remove("enabled");
|
||||
this.classList.add("disabled");
|
||||
this.dataset.state = "disabled";
|
||||
}).catch(error => {
|
||||
this.classList.remove("pending");
|
||||
displayError(error);
|
||||
});
|
||||
} else {
|
||||
// enable
|
||||
callContentScript("createEmoji", this.querySelector("img").src, this.dataset.animationStyle).then(newEmoji => {
|
||||
chrome.storage.local.get("emoji").then(({emoji}) => {
|
||||
emoji.find(e => e.internalId == this.dataset.internalId).currentId = newEmoji.id;
|
||||
chrome.storage.local.set({emoji});
|
||||
this.dataset.currentId = newEmoji.id;
|
||||
this.classList.remove("pending");
|
||||
this.classList.remove("disabled");
|
||||
this.classList.add("enabled");
|
||||
});
|
||||
}).catch(error => {
|
||||
this.classList.remove("pending");
|
||||
this.dataset.state = selectedState;
|
||||
displayError(error);
|
||||
});
|
||||
if (!deleteMode) return;
|
||||
}
|
||||
|
||||
if (deleteMode) {
|
||||
let {emoji} = await chrome.storage.local.get("emoji");
|
||||
emoji = emoji.filter(e => e.internalId != this.dataset.internalId);
|
||||
await chrome.storage.local.set({emoji});
|
||||
this.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
// enable
|
||||
callContentScript("createEmoji", this.querySelector("img").src, this.dataset.animationStyle).then(newEmoji => {
|
||||
chrome.storage.local.get("emoji").then(({emoji}) => {
|
||||
emoji.find(e => e.internalId == this.dataset.internalId).currentId = newEmoji.id;
|
||||
chrome.storage.local.set({emoji});
|
||||
this.dataset.currentId = newEmoji.id;
|
||||
this.dataset.state = "enabled";
|
||||
});
|
||||
}).catch(error => {
|
||||
this.dataset.state = selectedState;
|
||||
displayError(error);
|
||||
});
|
||||
}
|
||||
|
||||
async function setAnimationStyle(internalId, animationStyle) {
|
||||
@ -166,4 +213,34 @@ async function setAnimationStyle(internalId, animationStyle) {
|
||||
var e = emoji.find(e => e.internalId == internalId);
|
||||
e.animationStyle = animationStyle;
|
||||
await chrome.storage.local.set({emoji});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function fileToDataURL(file) {
|
||||
return new Promise(function(resolve, reject){
|
||||
let reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = () => {
|
||||
resolve(reader.result);
|
||||
};
|
||||
reader.onerror = reject;
|
||||
});
|
||||
}
|
||||
|
||||
function randomId() {
|
||||
let id = "";
|
||||
const CHARS = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
for (var i = 0; i < 16; i++) {
|
||||
id += CHARS[Math.floor(Math.random() * CHARS.length)];
|
||||
}
|
||||
return id;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user