mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
185 lines
5.5 KiB
JavaScript
185 lines
5.5 KiB
JavaScript
export function onlyUnique(value, index, array) {
|
|
return array.indexOf(value) === index;
|
|
}
|
|
|
|
export function shuffle(array) {
|
|
let currentIndex = array.length,
|
|
randomIndex;
|
|
|
|
while (currentIndex != 0) {
|
|
randomIndex = Math.floor(Math.random() * currentIndex);
|
|
currentIndex--;
|
|
[array[currentIndex], array[randomIndex]] = [
|
|
array[randomIndex],
|
|
array[currentIndex],
|
|
];
|
|
}
|
|
return array;
|
|
}
|
|
|
|
export function download(content, fileName, contentType) {
|
|
const a = document.createElement("a");
|
|
const file = new Blob([content], { type: contentType });
|
|
a.href = URL.createObjectURL(file);
|
|
a.download = fileName;
|
|
a.click();
|
|
}
|
|
|
|
export async function urlContentToDataUri(url, params) {
|
|
const response = await fetch(url, params);
|
|
const blob = await response.blob();
|
|
return await new Promise(callback => {
|
|
let reader = new FileReader();
|
|
reader.onload = function () { callback(this.result); };
|
|
reader.readAsDataURL(blob);
|
|
});
|
|
}
|
|
|
|
export function getBase64Async(file) {
|
|
return new Promise((resolve, reject) => {
|
|
const reader = new FileReader();
|
|
reader.readAsDataURL(file);
|
|
reader.onload = function () {
|
|
resolve(reader.result);
|
|
};
|
|
reader.onerror = function (error) {
|
|
reject(error);
|
|
};
|
|
});
|
|
}
|
|
|
|
export async function parseJsonFile(file) {
|
|
return new Promise((resolve, reject) => {
|
|
const fileReader = new FileReader();
|
|
fileReader.onload = event => resolve(JSON.parse(event.target.result));
|
|
fileReader.onerror = error => reject(error);
|
|
fileReader.readAsText(file);
|
|
});
|
|
}
|
|
|
|
export function getStringHash(str, seed = 0) {
|
|
let h1 = 0xdeadbeef ^ seed,
|
|
h2 = 0x41c6ce57 ^ seed;
|
|
for (let i = 0, ch; i < str.length; i++) {
|
|
ch = str.charCodeAt(i);
|
|
h1 = Math.imul(h1 ^ ch, 2654435761);
|
|
h2 = Math.imul(h2 ^ ch, 1597334677);
|
|
}
|
|
|
|
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
|
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
|
|
|
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
|
};
|
|
|
|
export function debounce(func, timeout = 300) {
|
|
let timer;
|
|
return (...args) => {
|
|
clearTimeout(timer);
|
|
timer = setTimeout(() => { func.apply(this, args); }, timeout);
|
|
};
|
|
}
|
|
|
|
export function getUniqueName(name, exists) {
|
|
let i = 1;
|
|
let baseName = name;
|
|
while (exists(name)) {
|
|
name = `${baseName} (${i})`;
|
|
i++;
|
|
}
|
|
return name;
|
|
}
|
|
|
|
export const delay = (ms) => new Promise((res) => setTimeout(res, ms));
|
|
export const isSubsetOf = (a, b) => (Array.isArray(a) && Array.isArray(b)) ? b.every(val => a.includes(val)) : false;
|
|
|
|
export function incrementString(str) {
|
|
// Find the trailing number or it will match the empty string
|
|
const count = str.match(/\d*$/);
|
|
|
|
// Take the substring up until where the integer was matched
|
|
// Concatenate it to the matched count incremented by 1
|
|
return str.substr(0, count.index) + (++count[0]);
|
|
};
|
|
|
|
export function stringFormat(format) {
|
|
const args = Array.prototype.slice.call(arguments, 1);
|
|
return format.replace(/{(\d+)}/g, function (match, number) {
|
|
return typeof args[number] != 'undefined'
|
|
? args[number]
|
|
: match
|
|
;
|
|
});
|
|
};
|
|
|
|
// Save the caret position in a contenteditable element
|
|
export function saveCaretPosition(element) {
|
|
// Get the current selection
|
|
const selection = window.getSelection();
|
|
|
|
// If the selection is empty, return null
|
|
if (selection.rangeCount === 0) {
|
|
return null;
|
|
}
|
|
|
|
// Get the range of the current selection
|
|
const range = selection.getRangeAt(0);
|
|
|
|
// If the range is not within the specified element, return null
|
|
if (!element.contains(range.commonAncestorContainer)) {
|
|
return null;
|
|
}
|
|
|
|
// Return an object with the start and end offsets of the range
|
|
const position = {
|
|
start: range.startOffset,
|
|
end: range.endOffset
|
|
};
|
|
|
|
console.log('Caret saved', position);
|
|
|
|
return position;
|
|
}
|
|
|
|
// Restore the caret position in a contenteditable element
|
|
export function restoreCaretPosition(element, position) {
|
|
// If the position is null, do nothing
|
|
if (!position) {
|
|
return;
|
|
}
|
|
|
|
console.log('Caret restored', position);
|
|
|
|
// Create a new range object
|
|
const range = new Range();
|
|
|
|
// Set the start and end positions of the range within the element
|
|
range.setStart(element.childNodes[0], position.start);
|
|
range.setEnd(element.childNodes[0], position.end);
|
|
|
|
// Create a new selection object and set the range
|
|
const selection = window.getSelection();
|
|
selection.removeAllRanges();
|
|
selection.addRange(range);
|
|
}
|
|
|
|
export async function resetScrollHeight(element) {
|
|
$(element).css('height', '0px');
|
|
$(element).css('height', $(element).prop('scrollHeight') + 3 + 'px');
|
|
}
|
|
|
|
export async function initScrollHeight(element) {
|
|
await delay(1);
|
|
|
|
const curHeight = Number($(element).css("height").replace('px', ''));
|
|
const curScrollHeight = Number($(element).prop("scrollHeight"));
|
|
const diff = curScrollHeight - curHeight;
|
|
|
|
if (diff < 3) { return } //happens when the div isn't loaded yet
|
|
|
|
const newHeight = curHeight + diff + 3; //the +3 here is to account for padding/line-height on text inputs
|
|
//console.log(`init height to ${newHeight}`);
|
|
$(element).css("height", "");
|
|
$(element).css("height", `${newHeight}px`);
|
|
//resetScrollHeight(element);
|
|
} |