added cut,copy,paste,select all context menu for inputs
This commit is contained in:
parent
3d168cd359
commit
9185f75110
2 changed files with 284 additions and 233 deletions
|
@ -212,6 +212,9 @@
|
||||||
"podcast.episodes": "Episodes",
|
"podcast.episodes": "Episodes",
|
||||||
"podcast.playEpisode": "Play Episode",
|
"podcast.playEpisode": "Play Episode",
|
||||||
"podcast.website": "Podcast Website",
|
"podcast.website": "Podcast Website",
|
||||||
|
"action.cut": "Cut",
|
||||||
|
"action.paste": "Paste",
|
||||||
|
"action.selectAll": "Select All",
|
||||||
"action.edit": "Edit",
|
"action.edit": "Edit",
|
||||||
"action.done": "Done",
|
"action.done": "Done",
|
||||||
"action.editTracklist": "Edit Tracklist",
|
"action.editTracklist": "Edit Tracklist",
|
||||||
|
|
|
@ -1,292 +1,340 @@
|
||||||
var notyf = new Notyf();
|
var notyf = new Notyf();
|
||||||
|
|
||||||
const MusicKitObjects = {
|
const MusicKitObjects = {
|
||||||
LibraryPlaylist: function () {
|
LibraryPlaylist: function () {
|
||||||
this.id = ""
|
this.id = "";
|
||||||
this.type = "library-playlist-folders"
|
this.type = "library-playlist-folders";
|
||||||
this.href = ""
|
this.href = "";
|
||||||
this.attributes = {
|
this.attributes = {
|
||||||
dateAdded: "",
|
dateAdded: "",
|
||||||
name: ""
|
name: "",
|
||||||
}
|
};
|
||||||
this.playlists = []
|
this.playlists = [];
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
// limit an array to a certain number of items
|
// limit an array to a certain number of items
|
||||||
Array.prototype.limit = function (n) {
|
Array.prototype.limit = function (n) {
|
||||||
return this.slice(0, n);
|
return this.slice(0, n);
|
||||||
};
|
};
|
||||||
|
|
||||||
Vue.component('animated-number', {
|
Vue.component("animated-number", {
|
||||||
|
template: "<div style='display: inline-block;'>{{ displayNumber }}</div>",
|
||||||
|
props: { number: { default: 0 } },
|
||||||
|
|
||||||
template: "<div style='display: inline-block;'>{{ displayNumber }}</div>",
|
data() {
|
||||||
props: { 'number': { default: 0 } },
|
return {
|
||||||
|
displayNumber: 0,
|
||||||
|
interval: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
ready() {
|
||||||
return {
|
this.displayNumber = this.number ? this.number : 0;
|
||||||
displayNumber: 0,
|
},
|
||||||
interval: false
|
|
||||||
|
watch: {
|
||||||
|
number() {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
|
||||||
|
if (this.number == this.displayNumber) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.interval = window.setInterval(() => {
|
||||||
|
if (this.displayNumber != this.number) {
|
||||||
|
var change = (this.number - this.displayNumber) / 10;
|
||||||
|
change = change >= 0 ? Math.ceil(change) : Math.floor(change);
|
||||||
|
this.displayNumber = this.displayNumber + change;
|
||||||
}
|
}
|
||||||
|
}, 20);
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
ready() {
|
Vue.component("sidebar-library-item", {
|
||||||
this.displayNumber = this.number ? this.number : 0;
|
template: "#sidebar-library-item",
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
},
|
},
|
||||||
|
page: {
|
||||||
watch: {
|
type: String,
|
||||||
number() {
|
required: true,
|
||||||
clearInterval(this.interval);
|
},
|
||||||
|
svgIcon: {
|
||||||
if (this.number == this.displayNumber) {
|
type: String,
|
||||||
return;
|
required: false,
|
||||||
}
|
default: "",
|
||||||
|
},
|
||||||
this.interval = window.setInterval(() => {
|
cdClick: {
|
||||||
if (this.displayNumber != this.number) {
|
type: Function,
|
||||||
var change = (this.number - this.displayNumber) / 10;
|
required: false,
|
||||||
change = change >= 0 ? Math.ceil(change) : Math.floor(change);
|
},
|
||||||
this.displayNumber = this.displayNumber + change;
|
},
|
||||||
}
|
data: function () {
|
||||||
}, 20);
|
return {
|
||||||
}
|
app: app,
|
||||||
|
svgIconData: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
if (this.svgIcon) {
|
||||||
|
this.svgIconData = await this.app.getSvgIcon(this.svgIcon);
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
methods: {},
|
||||||
Vue.component('sidebar-library-item', {
|
|
||||||
template: '#sidebar-library-item',
|
|
||||||
props: {
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
page: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
svgIcon: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
cdClick: {
|
|
||||||
type: Function,
|
|
||||||
required: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data: function () {
|
|
||||||
return {
|
|
||||||
app: app,
|
|
||||||
svgIconData: ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async mounted() {
|
|
||||||
if (this.svgIcon) {
|
|
||||||
this.svgIconData = await this.app.getSvgIcon(this.svgIcon)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function fallbackinitMusicKit() {
|
function fallbackinitMusicKit() {
|
||||||
const request = new XMLHttpRequest();
|
const request = new XMLHttpRequest();
|
||||||
|
|
||||||
function loadAlternateKey() {
|
function loadAlternateKey() {
|
||||||
let parsedJson = JSON.parse(this.responseText)
|
let parsedJson = JSON.parse(this.responseText);
|
||||||
MusicKit.configure({
|
MusicKit.configure({
|
||||||
developerToken: parsedJson.developerToken,
|
developerToken: parsedJson.developerToken,
|
||||||
app: {
|
app: {
|
||||||
name: 'Apple Music',
|
name: "Apple Music",
|
||||||
build: '1978.4.1',
|
build: "1978.4.1",
|
||||||
version: "1.0"
|
version: "1.0",
|
||||||
},
|
},
|
||||||
sourceType: 24,
|
sourceType: 24,
|
||||||
suppressErrorDialog: true
|
suppressErrorDialog: true,
|
||||||
})
|
|
||||||
setTimeout(() => {
|
|
||||||
app.init()
|
|
||||||
if (app.cfg.visual.window_background_style == "mica" && !app.isDev) {
|
|
||||||
app.spawnMica()
|
|
||||||
}
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
request.addEventListener("load", loadAlternateKey);
|
|
||||||
request.open("GET", "https://raw.githubusercontent.com/lujjjh/LitoMusic/main/token.json");
|
|
||||||
request.send();
|
|
||||||
}
|
|
||||||
document.addEventListener('musickitloaded', function () {
|
|
||||||
console.log('MusicKit loaded')
|
|
||||||
// MusicKit global is now defined
|
|
||||||
function initMusicKit() {
|
|
||||||
let parsedJson = JSON.parse(this.responseText)
|
|
||||||
MusicKit.configure({
|
|
||||||
developerToken: parsedJson.token,
|
|
||||||
app: {
|
|
||||||
name: 'Apple Music',
|
|
||||||
build: '1978.4.1',
|
|
||||||
version: "1.0"
|
|
||||||
},
|
|
||||||
sourceType: 24,
|
|
||||||
suppressErrorDialog: true
|
|
||||||
}).then(() => {
|
|
||||||
function waitForApp() {
|
|
||||||
if (typeof app.init !== "undefined") {
|
|
||||||
app.init()
|
|
||||||
if (app.cfg.visual.window_background_style == "mica") {
|
|
||||||
app.spawnMica()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setTimeout(waitForApp, 250);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
waitForApp()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const request = new XMLHttpRequest();
|
|
||||||
request.timeout = 5000;
|
|
||||||
request.addEventListener("load", initMusicKit);
|
|
||||||
request.onreadystatechange = function (aEvt) {
|
|
||||||
if (request.readyState == 4) {
|
|
||||||
if (request.status != 200)
|
|
||||||
fallbackinitMusicKit()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
request.open("GET", "https://api.cider.sh/v1/");
|
|
||||||
request.send();
|
|
||||||
|
|
||||||
// check for widevine failure and reconfigure the instance.
|
|
||||||
window.addEventListener("drmUnsupported", function () {
|
|
||||||
initMusicKit()
|
|
||||||
});
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
app.init();
|
||||||
|
if (app.cfg.visual.window_background_style == "mica" && !app.isDev) {
|
||||||
|
app.spawnMica();
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
request.addEventListener("load", loadAlternateKey);
|
||||||
|
request.open(
|
||||||
|
"GET",
|
||||||
|
"https://raw.githubusercontent.com/lujjjh/LitoMusic/main/token.json"
|
||||||
|
);
|
||||||
|
request.send();
|
||||||
|
}
|
||||||
|
document.addEventListener("musickitloaded", function () {
|
||||||
|
console.log("MusicKit loaded");
|
||||||
|
// MusicKit global is now defined
|
||||||
|
function initMusicKit() {
|
||||||
|
let parsedJson = JSON.parse(this.responseText);
|
||||||
|
MusicKit.configure({
|
||||||
|
developerToken: parsedJson.token,
|
||||||
|
app: {
|
||||||
|
name: "Apple Music",
|
||||||
|
build: "1978.4.1",
|
||||||
|
version: "1.0",
|
||||||
|
},
|
||||||
|
sourceType: 24,
|
||||||
|
suppressErrorDialog: true,
|
||||||
|
}).then(() => {
|
||||||
|
function waitForApp() {
|
||||||
|
if (typeof app.init !== "undefined") {
|
||||||
|
app.init();
|
||||||
|
if (app.cfg.visual.window_background_style == "mica") {
|
||||||
|
app.spawnMica();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setTimeout(waitForApp, 250);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
waitForApp();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = new XMLHttpRequest();
|
||||||
|
request.timeout = 5000;
|
||||||
|
request.addEventListener("load", initMusicKit);
|
||||||
|
request.onreadystatechange = function (aEvt) {
|
||||||
|
if (request.readyState == 4) {
|
||||||
|
if (request.status != 200) fallbackinitMusicKit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
request.open("GET", "https://api.cider.sh/v1/");
|
||||||
|
request.send();
|
||||||
|
|
||||||
|
// check for widevine failure and reconfigure the instance.
|
||||||
|
window.addEventListener("drmUnsupported", function () {
|
||||||
|
initMusicKit();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if ("serviceWorker" in navigator) {
|
||||||
|
// Use the window load event to keep the page load performant
|
||||||
|
window.addEventListener("load", () => {
|
||||||
if ('serviceWorker' in navigator) {
|
navigator.serviceWorker.register("sw.js?v=1");
|
||||||
// Use the window load event to keep the page load performant
|
});
|
||||||
window.addEventListener('load', () => {
|
|
||||||
navigator.serviceWorker.register('sw.js?v=1');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getBase64FromUrl = async (url) => {
|
const getBase64FromUrl = async (url) => {
|
||||||
const data = await fetch(url);
|
const data = await fetch(url);
|
||||||
const blob = await data.blob();
|
const blob = await data.blob();
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.readAsDataURL(blob);
|
reader.readAsDataURL(blob);
|
||||||
reader.onloadend = () => {
|
reader.onloadend = () => {
|
||||||
const base64data = reader.result;
|
const base64data = reader.result;
|
||||||
resolve(base64data);
|
resolve(base64data);
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function Clone(obj) {
|
function Clone(obj) {
|
||||||
return JSON.parse(JSON.stringify(obj));
|
return JSON.parse(JSON.stringify(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
function uuidv4() {
|
function uuidv4() {
|
||||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
|
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
|
||||||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
(
|
||||||
);
|
c ^
|
||||||
|
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))
|
||||||
|
).toString(16)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function xmlToJson(xml) {
|
function xmlToJson(xml) {
|
||||||
|
// Create the return object
|
||||||
|
let obj = {};
|
||||||
|
|
||||||
// Create the return object
|
if (xml.nodeType == 1) {
|
||||||
let obj = {};
|
// element
|
||||||
|
// do attributes
|
||||||
if (xml.nodeType == 1) { // element
|
if (xml.attributes.length > 0) {
|
||||||
// do attributes
|
obj["@attributes"] = {};
|
||||||
if (xml.attributes.length > 0) {
|
for (var j = 0; j < xml.attributes.length; j++) {
|
||||||
obj["@attributes"] = {};
|
let attribute = xml.attributes.item(j);
|
||||||
for (var j = 0; j < xml.attributes.length; j++) {
|
obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
|
||||||
let attribute = xml.attributes.item(j);
|
}
|
||||||
obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (xml.nodeType == 3) { // text
|
|
||||||
obj = xml.nodeValue;
|
|
||||||
}
|
}
|
||||||
|
} else if (xml.nodeType == 3) {
|
||||||
|
// text
|
||||||
|
obj = xml.nodeValue;
|
||||||
|
}
|
||||||
|
|
||||||
// do children
|
// do children
|
||||||
if (xml.hasChildNodes()) {
|
if (xml.hasChildNodes()) {
|
||||||
for (var i = 0; i < xml.childNodes.length; i++) {
|
for (var i = 0; i < xml.childNodes.length; i++) {
|
||||||
var item = xml.childNodes.item(i);
|
var item = xml.childNodes.item(i);
|
||||||
var nodeName = item.nodeName;
|
var nodeName = item.nodeName;
|
||||||
if (typeof (obj[nodeName]) == "undefined") {
|
if (typeof obj[nodeName] == "undefined") {
|
||||||
obj[nodeName] = xmlToJson(item);
|
obj[nodeName] = xmlToJson(item);
|
||||||
} else {
|
} else {
|
||||||
if (typeof (obj[nodeName].push) == "undefined") {
|
if (typeof obj[nodeName].push == "undefined") {
|
||||||
var old = obj[nodeName];
|
var old = obj[nodeName];
|
||||||
obj[nodeName] = [];
|
obj[nodeName] = [];
|
||||||
obj[nodeName].push(old);
|
obj[nodeName].push(old);
|
||||||
}
|
|
||||||
obj[nodeName].push(xmlToJson(item));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
obj[nodeName].push(xmlToJson(item));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
console.log(obj);
|
}
|
||||||
return obj;
|
console.log(obj);
|
||||||
};
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
async function asyncForEach(array, callback) {
|
async function asyncForEach(array, callback) {
|
||||||
for (let index = 0; index < array.length; index++) {
|
for (let index = 0; index < array.length; index++) {
|
||||||
await callback(array[index], index, array);
|
await callback(array[index], index, array);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var checkIfScrollIsStatic = setInterval(() => {
|
var checkIfScrollIsStatic = setInterval(() => {
|
||||||
try {
|
try {
|
||||||
if (position === document.getElementsByClassName('lyric-body')[0].scrollTop) {
|
if (
|
||||||
clearInterval(checkIfScrollIsStatic)
|
position === document.getElementsByClassName("lyric-body")[0].scrollTop
|
||||||
// do something
|
) {
|
||||||
}
|
clearInterval(checkIfScrollIsStatic);
|
||||||
position = document.getElementsByClassName('lyric-body')[0].scrollTop
|
// do something
|
||||||
} catch (e) {
|
|
||||||
}
|
}
|
||||||
|
position = document.getElementsByClassName("lyric-body")[0].scrollTop;
|
||||||
|
} catch (e) {}
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|
||||||
// WebGPU Console Notification
|
// WebGPU Console Notification
|
||||||
async function webGPU() {
|
async function webGPU() {
|
||||||
try {
|
try {
|
||||||
const currentGPU = await navigator.gpu.requestAdapter()
|
const currentGPU = await navigator.gpu.requestAdapter();
|
||||||
console.log("WebGPU enabled on", currentGPU.name, "with feature ID", currentGPU.features.size)
|
console.log(
|
||||||
} catch (e) {
|
"WebGPU enabled on",
|
||||||
console.log("WebGPU disabled / WebGPU initialization failed")
|
currentGPU.name,
|
||||||
}
|
"with feature ID",
|
||||||
|
currentGPU.features.size
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("WebGPU disabled / WebGPU initialization failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isJson(item) {
|
function isJson(item) {
|
||||||
item = typeof item !== "string"
|
item = typeof item !== "string" ? JSON.stringify(item) : item;
|
||||||
? JSON.stringify(item)
|
|
||||||
: item;
|
|
||||||
|
|
||||||
try {
|
|
||||||
item = JSON.parse(item);
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof item === "object" && item !== null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
item = JSON.parse(item);
|
||||||
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof item === "object" && item !== null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
webGPU().then()
|
webGPU().then();
|
||||||
|
|
||||||
let screenWidth = screen.width;
|
let screenWidth = screen.width;
|
||||||
let screenHeight = screen.height;
|
let screenHeight = screen.height;
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', async function () {
|
document.addEventListener("DOMContentLoaded", async function () {
|
||||||
// app.oobeInit()
|
// app.oobeInit()
|
||||||
})
|
});
|
||||||
|
|
||||||
|
document.addEventListener(
|
||||||
|
"contextmenu",
|
||||||
|
function (e) {
|
||||||
|
if (
|
||||||
|
e.target.tagName.toLowerCase() == "textarea" ||
|
||||||
|
(e.target.tagName.toLowerCase() == "input" &&
|
||||||
|
e.target.type != "checkbox" &&
|
||||||
|
e.target.type != "radio" &&
|
||||||
|
e.target.disabled == false)
|
||||||
|
) {
|
||||||
|
e.preventDefault();
|
||||||
|
const menuPanel = {
|
||||||
|
items: {
|
||||||
|
cut: {
|
||||||
|
name: app.getLz("action.cut"),
|
||||||
|
action: function () {
|
||||||
|
document.execCommand("cut");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
copy: {
|
||||||
|
name: app.getLz("action.copy"),
|
||||||
|
action: function () {
|
||||||
|
document.execCommand("copy");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
paste: {
|
||||||
|
name: app.getLz("action.paste"),
|
||||||
|
action: function () {
|
||||||
|
document.execCommand("paste");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
selectAll: {
|
||||||
|
name: app.getLz("action.selectAll"),
|
||||||
|
action: function () {
|
||||||
|
document.execCommand("selectAll");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
app.showMenuPanel(menuPanel, e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue