Compare commits
3 Commits
6e7f3d4b4c
...
f748d0b771
Author | SHA1 | Date | |
---|---|---|---|
f748d0b771 | |||
d1de5350e1 | |||
826c7ccb73 |
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
react
|
||||
package.json
|
||||
package-lock.json
|
@ -17,7 +17,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
<h1>Add emoji</h1>
|
||||
<input type="file" id="fileinput" accept="image/*" multiple /><input type="submit" id="submit" />
|
||||
|
||||
<input type="file" id="fileinput" accept="image/png,image/jpeg" multiple /><input type="submit" id="submit" />
|
||||
|
||||
<script src="edit.js" charset="UTF-8"></script>
|
||||
</body></html>
|
17
edit.js
17
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();
|
||||
@ -59,20 +59,16 @@ async function instantiateRow(url, internalId, animationStyle) {
|
||||
|
||||
let button = document.createElement("button");
|
||||
button.innerText = "🗑️";
|
||||
button.onclick = () => {
|
||||
deleteEmoji(internalId);
|
||||
button.onclick = async () => {
|
||||
//if (!confirm("Delete emoji from storage. Are you sure?")) return;
|
||||
var {emoji} = await chrome.storage.local.get("emoji");
|
||||
emoji = emoji.filter(e => e.internalId != internalId);
|
||||
await chrome.storage.local.set({emoji});
|
||||
row.remove();
|
||||
};
|
||||
c2.appendChild(button);
|
||||
}
|
||||
|
||||
async function deleteEmoji(internalId) {
|
||||
if (!confirm("Delete emoji from storage. Are you sure?")) return;
|
||||
var {emoji} = await chrome.storage.local.get("emoji");
|
||||
emoji = emoji.filter(e => e.internalId != internalId);
|
||||
await chrome.storage.local.set({emoji});
|
||||
}
|
||||
|
||||
async function setAnimationStyle(internalId, animationStyle) {
|
||||
var {emoji} = await chrome.storage.local.get("emoji");
|
||||
var e = emoji.find(e => e.internalId == internalId);
|
||||
@ -98,6 +94,7 @@ submit.onclick = async () => {
|
||||
var {emoji} = await chrome.storage.local.get("emoji");
|
||||
emoji = emoji.concat(newEmoji);
|
||||
await chrome.storage.local.set({emoji});
|
||||
fileinput.value = "";
|
||||
submit.disabled = false;
|
||||
};
|
||||
|
||||
|
@ -25,8 +25,5 @@
|
||||
"background": {
|
||||
"service_worker": "background.js",
|
||||
"type": "module"
|
||||
},
|
||||
"action": {
|
||||
"default_popup": "toggle.html"
|
||||
}
|
||||
}
|
36
toggle.html
36
toggle.html
@ -1,39 +1,51 @@
|
||||
<!DOCTYPE html><html><head>
|
||||
<meta charset="UTF-8" />
|
||||
<style>
|
||||
|
||||
#emojigrid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 269px;
|
||||
}
|
||||
.emojisquare {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 1px solid gray;
|
||||
margin: 1px;
|
||||
padding: 4px;
|
||||
}
|
||||
.emojisquare .imgcontainer {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
}
|
||||
.emojisquare img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
margin: auto;
|
||||
.emojisquare .imgcontainer img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
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;
|
||||
}
|
||||
</style>
|
||||
</head><body>
|
||||
|
||||
<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>
|
200
toggle.js
200
toggle.js
@ -1,3 +1,92 @@
|
||||
const ANIMATION_STYLES = `Aura
|
||||
Bats
|
||||
Bees
|
||||
Bounce
|
||||
Cloud
|
||||
Confetti
|
||||
Crying
|
||||
Dislike
|
||||
Fire
|
||||
Idea
|
||||
Lasers
|
||||
Like
|
||||
Magnet
|
||||
Mistletoe
|
||||
Money
|
||||
Noise
|
||||
Orbit
|
||||
Pizza
|
||||
Rain
|
||||
Rotate
|
||||
Shake
|
||||
Snow
|
||||
Snowball
|
||||
Spin
|
||||
Splash
|
||||
Stop
|
||||
ZZZ`.split('\n');
|
||||
|
||||
function createAnimationStyleSelect() {
|
||||
let select = document.createElement("select");
|
||||
ANIMATION_STYLES.forEach(a => {
|
||||
let option = document.createElement("option");
|
||||
option.innerText = a;
|
||||
option.value = a.toLowerCase();
|
||||
select.appendChild(option);
|
||||
});
|
||||
return select;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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);
|
||||
|
||||
async function loadEmojis() {
|
||||
@ -6,15 +95,26 @@ async function loadEmojis() {
|
||||
if (!store.emoji) throw new Error("No emoji.");
|
||||
for (let emoji of store.emoji) {
|
||||
let div = document.createElement("div");
|
||||
div.className = "emojisquare";
|
||||
div.dataset.animationStyle = emoji.animationStyle;
|
||||
div.dataset.internalId = emoji.internalId;
|
||||
div.dataset.currentId = emoji.currentId;
|
||||
div.classList.add("emojisquare");
|
||||
div.onclick = toggleEmoji;
|
||||
|
||||
let imgdiv = document.createElement("div");
|
||||
imgdiv.className = "imgcontainer";
|
||||
let img = document.createElement("img");
|
||||
img.src = store["data-" + emoji.internalId];
|
||||
div.appendChild(img);
|
||||
imgdiv.appendChild(img);
|
||||
div.appendChild(imgdiv);
|
||||
|
||||
let select = createAnimationStyleSelect();
|
||||
select.value = emoji.animationStyle;
|
||||
select.onclick = event => event.stopPropagation();
|
||||
select.onchange = event => {
|
||||
setAnimationStyle(emoji.internalId, event.target.value);
|
||||
};
|
||||
div.appendChild(select);
|
||||
|
||||
emojigrid.appendChild(div);
|
||||
}
|
||||
@ -22,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";
|
||||
});
|
||||
}
|
||||
|
||||
@ -61,44 +160,87 @@ 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) {
|
||||
var {emoji} = await chrome.storage.local.get("emoji");
|
||||
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…
Reference in New Issue
Block a user