mirror of
https://github.com/NohamR/Pocket-Bird.git
synced 2026-05-25 19:59:38 +00:00
Add sticky note saving
This commit is contained in:
133
birb.js
133
birb.js
@@ -563,6 +563,23 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
super("", () => {});
|
super("", () => {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StickyNote {
|
||||||
|
/**
|
||||||
|
* @param {string} id
|
||||||
|
* @param {string} [site]
|
||||||
|
* @param {string} [content]
|
||||||
|
* @param {number} [top]
|
||||||
|
* @param {number} [left]
|
||||||
|
*/
|
||||||
|
constructor(id, site="", content="", top=0, left=0) {
|
||||||
|
this.id = id;
|
||||||
|
this.site = site;
|
||||||
|
this.content = content;
|
||||||
|
this.top = top;
|
||||||
|
this.left = left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
new MenuItem(`Pet ${birdBirb()}`, pet),
|
new MenuItem(`Pet ${birdBirb()}`, pet),
|
||||||
@@ -579,6 +596,7 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
new DebugMenuItem("Disable Debug", () => {
|
new DebugMenuItem("Disable Debug", () => {
|
||||||
debugMode = false;
|
debugMode = false;
|
||||||
}),
|
}),
|
||||||
|
new MenuItem("Add Sticky Note", newStickyNote),
|
||||||
new Separator(),
|
new Separator(),
|
||||||
new MenuItem("Settings", () => switchMenuItems(settingsItems), false),
|
new MenuItem("Settings", () => switchMenuItems(settingsItems), false),
|
||||||
];
|
];
|
||||||
@@ -657,6 +675,8 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
let unlockedSpecies = [DEFAULT_BIRD];
|
let unlockedSpecies = [DEFAULT_BIRD];
|
||||||
let visible = true;
|
let visible = true;
|
||||||
let lastPetTimestamp = 0;
|
let lastPetTimestamp = 0;
|
||||||
|
/** @type {StickyNote[]} */
|
||||||
|
let stickyNotes = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {boolean} Whether the script is running in a userscript extension context
|
* @returns {boolean} Whether the script is running in a userscript extension context
|
||||||
@@ -689,6 +709,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
userSettings = saveData.settings ?? {};
|
userSettings = saveData.settings ?? {};
|
||||||
unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD];
|
unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD];
|
||||||
currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD;
|
currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD;
|
||||||
|
stickyNotes = [];
|
||||||
|
if (saveData.stickyNotes) {
|
||||||
|
for (let note of saveData.stickyNotes) {
|
||||||
|
if (note.id) {
|
||||||
|
stickyNotes.push(new StickyNote(note.id, note.site, note.content, note.top, note.left));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log(stickyNotes.length + " sticky notes loaded");
|
||||||
switchSpecies(currentSpecies);
|
switchSpecies(currentSpecies);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -698,6 +727,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
currentSpecies: currentSpecies,
|
currentSpecies: currentSpecies,
|
||||||
settings: userSettings
|
settings: userSettings
|
||||||
};
|
};
|
||||||
|
if (stickyNotes.length > 0) {
|
||||||
|
saveData.stickyNotes = stickyNotes.map(note => ({
|
||||||
|
id: note.id,
|
||||||
|
site: note.site,
|
||||||
|
content: note.content,
|
||||||
|
top: note.top,
|
||||||
|
left: note.left
|
||||||
|
}));
|
||||||
|
}
|
||||||
if (isUserScript()) {
|
if (isUserScript()) {
|
||||||
log("Saving data to UserScript storage");
|
log("Saving data to UserScript storage");
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -739,41 +777,84 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
return settings().birbMode ? "Birb" : "Bird";
|
return settings().birbMode ? "Birb" : "Bird";
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeStickyNote(top = 500, left = 500) {
|
function newStickyNote() {
|
||||||
|
const id = Date.now().toString();
|
||||||
|
const site = window.location.href;
|
||||||
|
const stickyNote = new StickyNote(id, site, "");
|
||||||
|
const element = renderStickyNote(stickyNote);
|
||||||
|
centerElement(element);
|
||||||
|
stickyNote.top = parseInt(element.style.top, 10);
|
||||||
|
stickyNote.left = parseInt(element.style.left, 10);
|
||||||
|
stickyNotes.push(stickyNote);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {StickyNote} stickyNote
|
||||||
|
* @returns {HTMLElement}
|
||||||
|
*/
|
||||||
|
function renderStickyNote(stickyNote) {
|
||||||
let html = `
|
let html = `
|
||||||
<div class="birb-window-header">
|
<div class="birb-window-header">
|
||||||
<div class="birb-window-title">Sticky Note</div>
|
<div class="birb-window-title">Sticky Note</div>
|
||||||
<div class="birb-window-close">x</div>
|
<div class="birb-window-close">x</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="birb-window-content">
|
<div class="birb-window-content">
|
||||||
<textarea class="birb-sticky-note-input" style="width: 150px;" placeholder="Write your notes here and they'll stick to the page..."></textarea>
|
<textarea class="birb-sticky-note-input" style="width: 150px;" placeholder="Write your notes here and they'll stick to the page...">${stickyNote.content}</textarea>
|
||||||
</div>`
|
</div>`
|
||||||
const stickyNote = makeElement("birb-window");
|
const noteElement = makeElement("birb-window");
|
||||||
stickyNote.classList.add("birb-sticky-note");
|
noteElement.classList.add("birb-sticky-note");
|
||||||
stickyNote.innerHTML = html;
|
noteElement.innerHTML = html;
|
||||||
|
|
||||||
stickyNote.style.top = `${top}px`;
|
noteElement.style.top = `${stickyNote.top}px`;
|
||||||
stickyNote.style.left = `${left}px`;
|
noteElement.style.left = `${stickyNote.left}px`;
|
||||||
document.body.appendChild(stickyNote);
|
document.body.appendChild(noteElement);
|
||||||
|
|
||||||
makeDraggable(stickyNote.querySelector(".birb-window-header"));
|
makeDraggable(noteElement.querySelector(".birb-window-header"), true, (top, left) => {
|
||||||
|
stickyNote.top = top;
|
||||||
|
stickyNote.left = left;
|
||||||
|
save();
|
||||||
|
});
|
||||||
|
|
||||||
const closeButton = stickyNote.querySelector(".birb-window-close");
|
const closeButton = noteElement.querySelector(".birb-window-close");
|
||||||
if (closeButton) {
|
if (closeButton) {
|
||||||
makeClosable(() => {
|
makeClosable(() => {
|
||||||
confirm("Are you sure you want to delete this sticky note?") && stickyNote.remove();
|
if (confirm("Are you sure you want to delete this sticky note?")) {
|
||||||
|
deleteStickyNote(stickyNote);
|
||||||
|
noteElement.remove();
|
||||||
|
}
|
||||||
}, closeButton);
|
}, closeButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
centerElement(stickyNote);
|
const textarea = noteElement.querySelector(".birb-sticky-note-input");
|
||||||
|
if (textarea && textarea instanceof HTMLTextAreaElement) {
|
||||||
|
let saveTimeout;
|
||||||
|
// Save after debounce
|
||||||
|
textarea.addEventListener("input", () => {
|
||||||
|
stickyNote.content = textarea.value;
|
||||||
|
clearTimeout(saveTimeout);
|
||||||
|
saveTimeout = setTimeout(() => {
|
||||||
|
save();
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// On window resize
|
// On window resize
|
||||||
window.addEventListener("resize", () => {
|
window.addEventListener("resize", () => {
|
||||||
const modTop = `${top - Math.min(window.innerHeight - stickyNote.offsetHeight, top)}px`;
|
const modTop = `${stickyNote.top - Math.min(window.innerHeight - noteElement.offsetHeight, stickyNote.top)}px`;
|
||||||
const modLeft = `${left - Math.min(window.innerWidth - stickyNote.offsetWidth, left)}px`;
|
const modLeft = `${stickyNote.left - Math.min(window.innerWidth - noteElement.offsetWidth, stickyNote.left)}px`;
|
||||||
stickyNote.style.transform = `translate(-${modLeft}, -${modTop})`;
|
noteElement.style.transform = `translate(-${modLeft}, -${modTop})`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return noteElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {StickyNote} stickyNote
|
||||||
|
*/
|
||||||
|
function deleteStickyNote(stickyNote) {
|
||||||
|
stickyNotes = stickyNotes.filter(note => note.id !== stickyNote.id);
|
||||||
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
@@ -828,7 +909,12 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
makeStickyNote();
|
// Render all sticky notes
|
||||||
|
for (let stickyNote of stickyNotes) {
|
||||||
|
if (stickyNote.site === window.location.href.split("?")[0]) {
|
||||||
|
renderStickyNote(stickyNote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setInterval(update, 1000 / 60);
|
setInterval(update, 1000 / 60);
|
||||||
}
|
}
|
||||||
@@ -1354,8 +1440,9 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
/**
|
/**
|
||||||
* @param {HTMLElement|null} element The element to detect drag events on
|
* @param {HTMLElement|null} element The element to detect drag events on
|
||||||
* @param {boolean} [parent] Whether to move the parent element when the child is dragged
|
* @param {boolean} [parent] Whether to move the parent element when the child is dragged
|
||||||
|
* @param {(top: number, left: number) => void} [callback] Callback for when element is moved
|
||||||
*/
|
*/
|
||||||
function makeDraggable(element, parent = true) {
|
function makeDraggable(element, parent = true, callback = () => {}) {
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1384,11 +1471,19 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("mouseup", () => {
|
document.addEventListener("mouseup", (e) => {
|
||||||
|
if (isMouseDown) {
|
||||||
|
callback(elementToMove.offsetTop, elementToMove.offsetLeft);
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
isMouseDown = false;
|
isMouseDown = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("touchend", () => {
|
document.addEventListener("touchend", (e) => {
|
||||||
|
if (isMouseDown) {
|
||||||
|
callback(elementToMove.offsetTop, elementToMove.offsetLeft);
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
isMouseDown = false;
|
isMouseDown = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
133
dist/birb.js
vendored
133
dist/birb.js
vendored
@@ -881,6 +881,23 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
super("", () => {});
|
super("", () => {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StickyNote {
|
||||||
|
/**
|
||||||
|
* @param {string} id
|
||||||
|
* @param {string} [site]
|
||||||
|
* @param {string} [content]
|
||||||
|
* @param {number} [top]
|
||||||
|
* @param {number} [left]
|
||||||
|
*/
|
||||||
|
constructor(id, site="", content="", top=0, left=0) {
|
||||||
|
this.id = id;
|
||||||
|
this.site = site;
|
||||||
|
this.content = content;
|
||||||
|
this.top = top;
|
||||||
|
this.left = left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
new MenuItem(`Pet ${birdBirb()}`, pet),
|
new MenuItem(`Pet ${birdBirb()}`, pet),
|
||||||
@@ -897,6 +914,7 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
new DebugMenuItem("Disable Debug", () => {
|
new DebugMenuItem("Disable Debug", () => {
|
||||||
debugMode = false;
|
debugMode = false;
|
||||||
}),
|
}),
|
||||||
|
new MenuItem("Add Sticky Note", newStickyNote),
|
||||||
new Separator(),
|
new Separator(),
|
||||||
new MenuItem("Settings", () => switchMenuItems(settingsItems), false),
|
new MenuItem("Settings", () => switchMenuItems(settingsItems), false),
|
||||||
];
|
];
|
||||||
@@ -975,6 +993,8 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
let unlockedSpecies = [DEFAULT_BIRD];
|
let unlockedSpecies = [DEFAULT_BIRD];
|
||||||
let visible = true;
|
let visible = true;
|
||||||
let lastPetTimestamp = 0;
|
let lastPetTimestamp = 0;
|
||||||
|
/** @type {StickyNote[]} */
|
||||||
|
let stickyNotes = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {boolean} Whether the script is running in a userscript extension context
|
* @returns {boolean} Whether the script is running in a userscript extension context
|
||||||
@@ -1007,6 +1027,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
userSettings = saveData.settings ?? {};
|
userSettings = saveData.settings ?? {};
|
||||||
unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD];
|
unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD];
|
||||||
currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD;
|
currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD;
|
||||||
|
stickyNotes = [];
|
||||||
|
if (saveData.stickyNotes) {
|
||||||
|
for (let note of saveData.stickyNotes) {
|
||||||
|
if (note.id) {
|
||||||
|
stickyNotes.push(new StickyNote(note.id, note.site, note.content, note.top, note.left));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log(stickyNotes.length + " sticky notes loaded");
|
||||||
switchSpecies(currentSpecies);
|
switchSpecies(currentSpecies);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1016,6 +1045,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
currentSpecies: currentSpecies,
|
currentSpecies: currentSpecies,
|
||||||
settings: userSettings
|
settings: userSettings
|
||||||
};
|
};
|
||||||
|
if (stickyNotes.length > 0) {
|
||||||
|
saveData.stickyNotes = stickyNotes.map(note => ({
|
||||||
|
id: note.id,
|
||||||
|
site: note.site,
|
||||||
|
content: note.content,
|
||||||
|
top: note.top,
|
||||||
|
left: note.left
|
||||||
|
}));
|
||||||
|
}
|
||||||
if (isUserScript()) {
|
if (isUserScript()) {
|
||||||
log("Saving data to UserScript storage");
|
log("Saving data to UserScript storage");
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -1057,41 +1095,84 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
return settings().birbMode ? "Birb" : "Bird";
|
return settings().birbMode ? "Birb" : "Bird";
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeStickyNote(top = 500, left = 500) {
|
function newStickyNote() {
|
||||||
|
const id = Date.now().toString();
|
||||||
|
const site = window.location.href;
|
||||||
|
const stickyNote = new StickyNote(id, site, "");
|
||||||
|
const element = renderStickyNote(stickyNote);
|
||||||
|
centerElement(element);
|
||||||
|
stickyNote.top = parseInt(element.style.top, 10);
|
||||||
|
stickyNote.left = parseInt(element.style.left, 10);
|
||||||
|
stickyNotes.push(stickyNote);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {StickyNote} stickyNote
|
||||||
|
* @returns {HTMLElement}
|
||||||
|
*/
|
||||||
|
function renderStickyNote(stickyNote) {
|
||||||
let html = `
|
let html = `
|
||||||
<div class="birb-window-header">
|
<div class="birb-window-header">
|
||||||
<div class="birb-window-title">Sticky Note</div>
|
<div class="birb-window-title">Sticky Note</div>
|
||||||
<div class="birb-window-close">x</div>
|
<div class="birb-window-close">x</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="birb-window-content">
|
<div class="birb-window-content">
|
||||||
<textarea class="birb-sticky-note-input" style="width: 150px;" placeholder="Write your notes here and they'll stick to the page..."></textarea>
|
<textarea class="birb-sticky-note-input" style="width: 150px;" placeholder="Write your notes here and they'll stick to the page...">${stickyNote.content}</textarea>
|
||||||
</div>`
|
</div>`
|
||||||
const stickyNote = makeElement("birb-window");
|
const noteElement = makeElement("birb-window");
|
||||||
stickyNote.classList.add("birb-sticky-note");
|
noteElement.classList.add("birb-sticky-note");
|
||||||
stickyNote.innerHTML = html;
|
noteElement.innerHTML = html;
|
||||||
|
|
||||||
stickyNote.style.top = `${top}px`;
|
noteElement.style.top = `${stickyNote.top}px`;
|
||||||
stickyNote.style.left = `${left}px`;
|
noteElement.style.left = `${stickyNote.left}px`;
|
||||||
document.body.appendChild(stickyNote);
|
document.body.appendChild(noteElement);
|
||||||
|
|
||||||
makeDraggable(stickyNote.querySelector(".birb-window-header"));
|
makeDraggable(noteElement.querySelector(".birb-window-header"), true, (top, left) => {
|
||||||
|
stickyNote.top = top;
|
||||||
|
stickyNote.left = left;
|
||||||
|
save();
|
||||||
|
});
|
||||||
|
|
||||||
const closeButton = stickyNote.querySelector(".birb-window-close");
|
const closeButton = noteElement.querySelector(".birb-window-close");
|
||||||
if (closeButton) {
|
if (closeButton) {
|
||||||
makeClosable(() => {
|
makeClosable(() => {
|
||||||
confirm("Are you sure you want to delete this sticky note?") && stickyNote.remove();
|
if (confirm("Are you sure you want to delete this sticky note?")) {
|
||||||
|
deleteStickyNote(stickyNote);
|
||||||
|
noteElement.remove();
|
||||||
|
}
|
||||||
}, closeButton);
|
}, closeButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
centerElement(stickyNote);
|
const textarea = noteElement.querySelector(".birb-sticky-note-input");
|
||||||
|
if (textarea && textarea instanceof HTMLTextAreaElement) {
|
||||||
|
let saveTimeout;
|
||||||
|
// Save after debounce
|
||||||
|
textarea.addEventListener("input", () => {
|
||||||
|
stickyNote.content = textarea.value;
|
||||||
|
clearTimeout(saveTimeout);
|
||||||
|
saveTimeout = setTimeout(() => {
|
||||||
|
save();
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// On window resize
|
// On window resize
|
||||||
window.addEventListener("resize", () => {
|
window.addEventListener("resize", () => {
|
||||||
const modTop = `${top - Math.min(window.innerHeight - stickyNote.offsetHeight, top)}px`;
|
const modTop = `${stickyNote.top - Math.min(window.innerHeight - noteElement.offsetHeight, stickyNote.top)}px`;
|
||||||
const modLeft = `${left - Math.min(window.innerWidth - stickyNote.offsetWidth, left)}px`;
|
const modLeft = `${stickyNote.left - Math.min(window.innerWidth - noteElement.offsetWidth, stickyNote.left)}px`;
|
||||||
stickyNote.style.transform = `translate(-${modLeft}, -${modTop})`;
|
noteElement.style.transform = `translate(-${modLeft}, -${modTop})`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return noteElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {StickyNote} stickyNote
|
||||||
|
*/
|
||||||
|
function deleteStickyNote(stickyNote) {
|
||||||
|
stickyNotes = stickyNotes.filter(note => note.id !== stickyNote.id);
|
||||||
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
@@ -1146,7 +1227,12 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
makeStickyNote();
|
// Render all sticky notes
|
||||||
|
for (let stickyNote of stickyNotes) {
|
||||||
|
if (stickyNote.site === window.location.href.split("?")[0]) {
|
||||||
|
renderStickyNote(stickyNote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setInterval(update, 1000 / 60);
|
setInterval(update, 1000 / 60);
|
||||||
}
|
}
|
||||||
@@ -1672,8 +1758,9 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
/**
|
/**
|
||||||
* @param {HTMLElement|null} element The element to detect drag events on
|
* @param {HTMLElement|null} element The element to detect drag events on
|
||||||
* @param {boolean} [parent] Whether to move the parent element when the child is dragged
|
* @param {boolean} [parent] Whether to move the parent element when the child is dragged
|
||||||
|
* @param {(top: number, left: number) => void} [callback] Callback for when element is moved
|
||||||
*/
|
*/
|
||||||
function makeDraggable(element, parent = true) {
|
function makeDraggable(element, parent = true, callback = () => {}) {
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1702,11 +1789,19 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("mouseup", () => {
|
document.addEventListener("mouseup", (e) => {
|
||||||
|
if (isMouseDown) {
|
||||||
|
callback(elementToMove.offsetTop, elementToMove.offsetLeft);
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
isMouseDown = false;
|
isMouseDown = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("touchend", () => {
|
document.addEventListener("touchend", (e) => {
|
||||||
|
if (isMouseDown) {
|
||||||
|
callback(elementToMove.offsetTop, elementToMove.offsetLeft);
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
isMouseDown = false;
|
isMouseDown = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
133
dist/birb.user.js
vendored
133
dist/birb.user.js
vendored
@@ -894,6 +894,23 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
super("", () => {});
|
super("", () => {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StickyNote {
|
||||||
|
/**
|
||||||
|
* @param {string} id
|
||||||
|
* @param {string} [site]
|
||||||
|
* @param {string} [content]
|
||||||
|
* @param {number} [top]
|
||||||
|
* @param {number} [left]
|
||||||
|
*/
|
||||||
|
constructor(id, site="", content="", top=0, left=0) {
|
||||||
|
this.id = id;
|
||||||
|
this.site = site;
|
||||||
|
this.content = content;
|
||||||
|
this.top = top;
|
||||||
|
this.left = left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
new MenuItem(`Pet ${birdBirb()}`, pet),
|
new MenuItem(`Pet ${birdBirb()}`, pet),
|
||||||
@@ -910,6 +927,7 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
new DebugMenuItem("Disable Debug", () => {
|
new DebugMenuItem("Disable Debug", () => {
|
||||||
debugMode = false;
|
debugMode = false;
|
||||||
}),
|
}),
|
||||||
|
new MenuItem("Add Sticky Note", newStickyNote),
|
||||||
new Separator(),
|
new Separator(),
|
||||||
new MenuItem("Settings", () => switchMenuItems(settingsItems), false),
|
new MenuItem("Settings", () => switchMenuItems(settingsItems), false),
|
||||||
];
|
];
|
||||||
@@ -988,6 +1006,8 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
let unlockedSpecies = [DEFAULT_BIRD];
|
let unlockedSpecies = [DEFAULT_BIRD];
|
||||||
let visible = true;
|
let visible = true;
|
||||||
let lastPetTimestamp = 0;
|
let lastPetTimestamp = 0;
|
||||||
|
/** @type {StickyNote[]} */
|
||||||
|
let stickyNotes = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {boolean} Whether the script is running in a userscript extension context
|
* @returns {boolean} Whether the script is running in a userscript extension context
|
||||||
@@ -1020,6 +1040,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
userSettings = saveData.settings ?? {};
|
userSettings = saveData.settings ?? {};
|
||||||
unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD];
|
unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD];
|
||||||
currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD;
|
currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD;
|
||||||
|
stickyNotes = [];
|
||||||
|
if (saveData.stickyNotes) {
|
||||||
|
for (let note of saveData.stickyNotes) {
|
||||||
|
if (note.id) {
|
||||||
|
stickyNotes.push(new StickyNote(note.id, note.site, note.content, note.top, note.left));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log(stickyNotes.length + " sticky notes loaded");
|
||||||
switchSpecies(currentSpecies);
|
switchSpecies(currentSpecies);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1029,6 +1058,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
currentSpecies: currentSpecies,
|
currentSpecies: currentSpecies,
|
||||||
settings: userSettings
|
settings: userSettings
|
||||||
};
|
};
|
||||||
|
if (stickyNotes.length > 0) {
|
||||||
|
saveData.stickyNotes = stickyNotes.map(note => ({
|
||||||
|
id: note.id,
|
||||||
|
site: note.site,
|
||||||
|
content: note.content,
|
||||||
|
top: note.top,
|
||||||
|
left: note.left
|
||||||
|
}));
|
||||||
|
}
|
||||||
if (isUserScript()) {
|
if (isUserScript()) {
|
||||||
log("Saving data to UserScript storage");
|
log("Saving data to UserScript storage");
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -1070,41 +1108,84 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
return settings().birbMode ? "Birb" : "Bird";
|
return settings().birbMode ? "Birb" : "Bird";
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeStickyNote(top = 500, left = 500) {
|
function newStickyNote() {
|
||||||
|
const id = Date.now().toString();
|
||||||
|
const site = window.location.href;
|
||||||
|
const stickyNote = new StickyNote(id, site, "");
|
||||||
|
const element = renderStickyNote(stickyNote);
|
||||||
|
centerElement(element);
|
||||||
|
stickyNote.top = parseInt(element.style.top, 10);
|
||||||
|
stickyNote.left = parseInt(element.style.left, 10);
|
||||||
|
stickyNotes.push(stickyNote);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {StickyNote} stickyNote
|
||||||
|
* @returns {HTMLElement}
|
||||||
|
*/
|
||||||
|
function renderStickyNote(stickyNote) {
|
||||||
let html = `
|
let html = `
|
||||||
<div class="birb-window-header">
|
<div class="birb-window-header">
|
||||||
<div class="birb-window-title">Sticky Note</div>
|
<div class="birb-window-title">Sticky Note</div>
|
||||||
<div class="birb-window-close">x</div>
|
<div class="birb-window-close">x</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="birb-window-content">
|
<div class="birb-window-content">
|
||||||
<textarea class="birb-sticky-note-input" style="width: 150px;" placeholder="Write your notes here and they'll stick to the page..."></textarea>
|
<textarea class="birb-sticky-note-input" style="width: 150px;" placeholder="Write your notes here and they'll stick to the page...">${stickyNote.content}</textarea>
|
||||||
</div>`
|
</div>`
|
||||||
const stickyNote = makeElement("birb-window");
|
const noteElement = makeElement("birb-window");
|
||||||
stickyNote.classList.add("birb-sticky-note");
|
noteElement.classList.add("birb-sticky-note");
|
||||||
stickyNote.innerHTML = html;
|
noteElement.innerHTML = html;
|
||||||
|
|
||||||
stickyNote.style.top = `${top}px`;
|
noteElement.style.top = `${stickyNote.top}px`;
|
||||||
stickyNote.style.left = `${left}px`;
|
noteElement.style.left = `${stickyNote.left}px`;
|
||||||
document.body.appendChild(stickyNote);
|
document.body.appendChild(noteElement);
|
||||||
|
|
||||||
makeDraggable(stickyNote.querySelector(".birb-window-header"));
|
makeDraggable(noteElement.querySelector(".birb-window-header"), true, (top, left) => {
|
||||||
|
stickyNote.top = top;
|
||||||
|
stickyNote.left = left;
|
||||||
|
save();
|
||||||
|
});
|
||||||
|
|
||||||
const closeButton = stickyNote.querySelector(".birb-window-close");
|
const closeButton = noteElement.querySelector(".birb-window-close");
|
||||||
if (closeButton) {
|
if (closeButton) {
|
||||||
makeClosable(() => {
|
makeClosable(() => {
|
||||||
confirm("Are you sure you want to delete this sticky note?") && stickyNote.remove();
|
if (confirm("Are you sure you want to delete this sticky note?")) {
|
||||||
|
deleteStickyNote(stickyNote);
|
||||||
|
noteElement.remove();
|
||||||
|
}
|
||||||
}, closeButton);
|
}, closeButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
centerElement(stickyNote);
|
const textarea = noteElement.querySelector(".birb-sticky-note-input");
|
||||||
|
if (textarea && textarea instanceof HTMLTextAreaElement) {
|
||||||
|
let saveTimeout;
|
||||||
|
// Save after debounce
|
||||||
|
textarea.addEventListener("input", () => {
|
||||||
|
stickyNote.content = textarea.value;
|
||||||
|
clearTimeout(saveTimeout);
|
||||||
|
saveTimeout = setTimeout(() => {
|
||||||
|
save();
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// On window resize
|
// On window resize
|
||||||
window.addEventListener("resize", () => {
|
window.addEventListener("resize", () => {
|
||||||
const modTop = `${top - Math.min(window.innerHeight - stickyNote.offsetHeight, top)}px`;
|
const modTop = `${stickyNote.top - Math.min(window.innerHeight - noteElement.offsetHeight, stickyNote.top)}px`;
|
||||||
const modLeft = `${left - Math.min(window.innerWidth - stickyNote.offsetWidth, left)}px`;
|
const modLeft = `${stickyNote.left - Math.min(window.innerWidth - noteElement.offsetWidth, stickyNote.left)}px`;
|
||||||
stickyNote.style.transform = `translate(-${modLeft}, -${modTop})`;
|
noteElement.style.transform = `translate(-${modLeft}, -${modTop})`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return noteElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {StickyNote} stickyNote
|
||||||
|
*/
|
||||||
|
function deleteStickyNote(stickyNote) {
|
||||||
|
stickyNotes = stickyNotes.filter(note => note.id !== stickyNote.id);
|
||||||
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
@@ -1159,7 +1240,12 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
makeStickyNote();
|
// Render all sticky notes
|
||||||
|
for (let stickyNote of stickyNotes) {
|
||||||
|
if (stickyNote.site === window.location.href.split("?")[0]) {
|
||||||
|
renderStickyNote(stickyNote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setInterval(update, 1000 / 60);
|
setInterval(update, 1000 / 60);
|
||||||
}
|
}
|
||||||
@@ -1685,8 +1771,9 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
/**
|
/**
|
||||||
* @param {HTMLElement|null} element The element to detect drag events on
|
* @param {HTMLElement|null} element The element to detect drag events on
|
||||||
* @param {boolean} [parent] Whether to move the parent element when the child is dragged
|
* @param {boolean} [parent] Whether to move the parent element when the child is dragged
|
||||||
|
* @param {(top: number, left: number) => void} [callback] Callback for when element is moved
|
||||||
*/
|
*/
|
||||||
function makeDraggable(element, parent = true) {
|
function makeDraggable(element, parent = true, callback = () => {}) {
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1715,11 +1802,19 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("mouseup", () => {
|
document.addEventListener("mouseup", (e) => {
|
||||||
|
if (isMouseDown) {
|
||||||
|
callback(elementToMove.offsetTop, elementToMove.offsetLeft);
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
isMouseDown = false;
|
isMouseDown = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("touchend", () => {
|
document.addEventListener("touchend", (e) => {
|
||||||
|
if (isMouseDown) {
|
||||||
|
callback(elementToMove.offsetTop, elementToMove.offsetLeft);
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
isMouseDown = false;
|
isMouseDown = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user