2022-02-11 15:28:22 +01:00
|
|
|
class Plugins{
|
|
|
|
constructor(...args){
|
|
|
|
this.init(...args)
|
|
|
|
}
|
|
|
|
init(){
|
|
|
|
this.allPlugins = []
|
|
|
|
this.pluginMap = {}
|
|
|
|
this.hashes = []
|
2022-02-17 21:50:07 +01:00
|
|
|
this.startOrder = []
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
2022-02-22 14:23:01 +01:00
|
|
|
add(script, options){
|
|
|
|
options = options || {}
|
2022-02-11 15:28:22 +01:00
|
|
|
var hash = md5.base64(script.toString())
|
2022-02-22 14:23:01 +01:00
|
|
|
var isUrl = typeof script === "string" && !options.raw
|
|
|
|
if(isUrl){
|
|
|
|
hash = "url " + hash
|
|
|
|
}else if(typeof script !== "string"){
|
|
|
|
hash = "class " + hash
|
|
|
|
}
|
|
|
|
var name = options.name
|
|
|
|
if(!name && isUrl){
|
|
|
|
name = script
|
2022-03-03 23:26:17 +01:00
|
|
|
var index = name.lastIndexOf("?")
|
|
|
|
if(index !== -1){
|
|
|
|
name = name.slice(0, index)
|
|
|
|
}
|
2022-02-22 14:23:01 +01:00
|
|
|
var index = name.lastIndexOf("/")
|
|
|
|
if(index !== -1){
|
|
|
|
name = name.slice(index + 1)
|
|
|
|
}
|
|
|
|
if(name.endsWith(".taikoweb.js")){
|
|
|
|
name = name.slice(0, -".taikoweb.js".length)
|
|
|
|
}else if(name.endsWith(".js")){
|
|
|
|
name = name.slice(0, -".js".length)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
name = name || "plugin"
|
2022-02-11 15:28:22 +01:00
|
|
|
if(this.hashes.indexOf(hash) !== -1){
|
|
|
|
console.warn("Skip adding an already addded plugin: " + name)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var baseName = name
|
2022-02-17 21:50:07 +01:00
|
|
|
for(var i = 2; name in this.pluginMap; i++){
|
2022-02-11 15:28:22 +01:00
|
|
|
name = baseName + i.toString()
|
|
|
|
}
|
2022-02-22 14:23:01 +01:00
|
|
|
var plugin = new PluginLoader(script, name, hash, options.raw)
|
|
|
|
plugin.hide = !!options.hide
|
2022-02-11 15:28:22 +01:00
|
|
|
this.allPlugins.push({
|
|
|
|
name: name,
|
|
|
|
plugin: plugin
|
|
|
|
})
|
|
|
|
this.pluginMap[name] = plugin
|
|
|
|
this.hashes.push(hash)
|
|
|
|
return plugin
|
|
|
|
}
|
|
|
|
remove(name){
|
2022-03-03 23:26:17 +01:00
|
|
|
if(name in this.pluginMap){
|
|
|
|
var hash = this.pluginMap[name].hash
|
|
|
|
if(hash){
|
|
|
|
var index = this.hashes.indexOf(hash)
|
|
|
|
if(index !== -1){
|
|
|
|
this.hashes.splice(index, 1)
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
2022-03-03 23:26:17 +01:00
|
|
|
this.unload(name)
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
var index = this.allPlugins.findIndex(obj => obj.name === name)
|
|
|
|
if(index !== -1){
|
|
|
|
this.allPlugins.splice(index, 1)
|
|
|
|
}
|
2022-02-22 14:23:01 +01:00
|
|
|
var index = this.startOrder.indexOf(name)
|
|
|
|
if(index !== -1){
|
|
|
|
this.startOrder.splice(index, 1)
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
delete this.pluginMap[name]
|
|
|
|
}
|
|
|
|
load(name){
|
2022-02-22 14:23:01 +01:00
|
|
|
return this.pluginMap[name].load()
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
loadAll(){
|
|
|
|
for(var i = 0; i < this.allPlugins.length; i++){
|
|
|
|
this.allPlugins[i].plugin.load()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
start(name){
|
2022-02-22 14:23:01 +01:00
|
|
|
return this.pluginMap[name].start()
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
startAll(){
|
|
|
|
for(var i = 0; i < this.allPlugins.length; i++){
|
|
|
|
this.allPlugins[i].plugin.start()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
stop(name){
|
2022-02-22 14:23:01 +01:00
|
|
|
return this.pluginMap[name].stop()
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
stopAll(){
|
2022-02-17 21:50:07 +01:00
|
|
|
for(var i = this.startOrder.length; i--;){
|
|
|
|
this.pluginMap[this.startOrder[i]].stop()
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
unload(name){
|
2022-02-22 14:23:01 +01:00
|
|
|
return this.pluginMap[name].unload()
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
unloadAll(){
|
2022-02-17 21:50:07 +01:00
|
|
|
for(var i = this.startOrder.length; i--;){
|
|
|
|
this.pluginMap[this.startOrder[i]].unload()
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
for(var i = this.allPlugins.length; i--;){
|
|
|
|
this.allPlugins[i].plugin.unload()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unloadImported(){
|
2022-02-17 21:50:07 +01:00
|
|
|
for(var i = this.startOrder.length; i--;){
|
|
|
|
var plugin = this.pluginMap[this.startOrder[i]]
|
|
|
|
if(plugin.imported){
|
|
|
|
plugin.unload()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(var i = this.allPlugins.length; i--;){
|
|
|
|
var obj = this.allPlugins[i]
|
|
|
|
if(obj.plugin.imported){
|
|
|
|
obj.plugin.unload()
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
strFromFunc(func){
|
|
|
|
var output = func.toString()
|
|
|
|
return output.slice(output.indexOf("{") + 1, output.lastIndexOf("}"))
|
|
|
|
}
|
|
|
|
argsFromFunc(func){
|
|
|
|
var output = func.toString()
|
|
|
|
output = output.slice(0, output.indexOf("{"))
|
|
|
|
output = output.slice(output.indexOf("(") + 1, output.lastIndexOf(")"))
|
|
|
|
return output.split(",").map(str => str.trim()).filter(Boolean)
|
|
|
|
}
|
|
|
|
insertBefore(input, insertedText, searchString){
|
|
|
|
var index = input.indexOf(searchString)
|
|
|
|
if(index === -1){
|
|
|
|
throw new Error("searchString not found: " + searchString)
|
|
|
|
}
|
|
|
|
return input.slice(0, index) + insertedText + input.slice(index)
|
|
|
|
}
|
|
|
|
insertAfter(input, searchString, insertedText){
|
|
|
|
var index = input.indexOf(searchString)
|
|
|
|
if(index === -1){
|
|
|
|
throw new Error("searchString not found: " + searchString)
|
|
|
|
}
|
|
|
|
var length = searchString.length
|
|
|
|
return input.slice(0, index + length) + insertedText + input.slice(index + length)
|
|
|
|
}
|
2022-02-23 18:31:52 +01:00
|
|
|
strReplace(input, searchString, insertedText, repeat=1){
|
|
|
|
var position = 0
|
|
|
|
for(var i = 0; i < repeat; i++){
|
|
|
|
var index = input.indexOf(searchString, position)
|
|
|
|
if(index === -1){
|
|
|
|
if(repeat === Infinity){
|
|
|
|
break
|
|
|
|
}else{
|
|
|
|
throw new Error("searchString not found: " + searchString)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
input = input.slice(0, index) + insertedText + input.slice(index + searchString.length)
|
|
|
|
position = index + insertedText.length
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
2022-02-23 18:31:52 +01:00
|
|
|
return input
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
2022-03-03 16:19:16 +01:00
|
|
|
isObject(input){
|
|
|
|
return input && typeof input === "object" && input.constructor === Object
|
|
|
|
}
|
|
|
|
deepMerge(target, ...sources){
|
|
|
|
sources.forEach(source => {
|
|
|
|
if(this.isObject(target) && this.isObject(source)){
|
|
|
|
for(var i in source){
|
|
|
|
if(this.isObject(source[i])){
|
|
|
|
if(!target[i]){
|
|
|
|
target[i] = {}
|
|
|
|
}
|
|
|
|
this.deepMerge(target[i], source[i])
|
|
|
|
}else if(source[i]){
|
|
|
|
target[i] = source[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
return target
|
|
|
|
}
|
|
|
|
arrayDel(array, item){
|
|
|
|
var index = array.indexOf(item)
|
|
|
|
if(index !== -1){
|
|
|
|
array.splice(index, 1)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
|
2022-02-22 15:43:27 +01:00
|
|
|
hasSettings(){
|
|
|
|
for(var i = 0; i < this.allPlugins.length; i++){
|
|
|
|
var plugin = this.allPlugins[i].plugin
|
|
|
|
if(plugin.loaded && (!plugin.hide || plugin.settings())){
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
getSettings(){
|
2022-02-22 14:23:01 +01:00
|
|
|
var items = []
|
2022-02-11 15:28:22 +01:00
|
|
|
for(var i = 0; i < this.allPlugins.length; i++){
|
|
|
|
var obj = this.allPlugins[i]
|
2022-02-15 17:15:29 +01:00
|
|
|
let plugin = obj.plugin
|
2022-02-22 14:23:01 +01:00
|
|
|
if(!plugin.loaded){
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if(!plugin.hide){
|
|
|
|
let description
|
|
|
|
let description_lang
|
|
|
|
var module = plugin.module
|
|
|
|
if(module){
|
|
|
|
description = [
|
|
|
|
module.description,
|
|
|
|
module.author ? strings.plugins.author.replace("%s", module.author) : null,
|
|
|
|
module.version ? strings.plugins.version.replace("%s", module.version) : null
|
|
|
|
].filter(Boolean).join("\n")
|
|
|
|
description_lang = {}
|
|
|
|
languageList.forEach(lang => {
|
|
|
|
description_lang[lang] = [
|
|
|
|
this.getLocalTitle(module.description, module.description_lang, lang),
|
|
|
|
module.author ? allStrings[lang].plugins.author.replace("%s", module.author) : null,
|
|
|
|
module.version ? allStrings[lang].plugins.version.replace("%s", module.version) : null
|
|
|
|
].filter(Boolean).join("\n")
|
|
|
|
})
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
2022-02-22 14:23:01 +01:00
|
|
|
var name = module && module.name || obj.name
|
|
|
|
var name_lang = module && module.name_lang
|
|
|
|
items.push({
|
|
|
|
name: name,
|
|
|
|
name_lang: name_lang,
|
|
|
|
description: description,
|
|
|
|
description_lang: description_lang,
|
|
|
|
type: "toggle",
|
|
|
|
default: true,
|
|
|
|
getItem: () => plugin.started,
|
|
|
|
setItem: value => {
|
2022-03-03 23:26:17 +01:00
|
|
|
if(plugin.name in this.pluginMap){
|
|
|
|
if(plugin.started && !value){
|
|
|
|
this.stop(plugin.name)
|
|
|
|
}else if(!plugin.started && value){
|
|
|
|
this.start(plugin.name)
|
|
|
|
}
|
2022-02-22 14:23:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
var settings = plugin.settings()
|
|
|
|
if(settings){
|
|
|
|
settings.forEach(setting => {
|
|
|
|
if(!setting.name){
|
|
|
|
setting.name = name
|
|
|
|
if(!setting.name_lang){
|
|
|
|
setting.name_lang = name_lang
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(typeof setting.getItem !== "function"){
|
|
|
|
setting.getItem = () => {}
|
|
|
|
}
|
|
|
|
if(typeof setting.setItem !== "function"){
|
|
|
|
setting.setItem = () => {}
|
|
|
|
}
|
|
|
|
if(!("indent" in setting) && !plugin.hide){
|
|
|
|
setting.indent = 1
|
|
|
|
}
|
|
|
|
items.push(setting)
|
|
|
|
})
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return items
|
|
|
|
}
|
2022-02-22 14:23:01 +01:00
|
|
|
getLocalTitle(title, titleLang, lang){
|
2022-02-18 00:44:37 +01:00
|
|
|
if(titleLang){
|
|
|
|
for(var id in titleLang){
|
2022-02-22 14:23:01 +01:00
|
|
|
if(id === (lang || strings.id) && titleLang[id]){
|
2022-02-18 00:44:37 +01:00
|
|
|
return titleLang[id]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return title
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
class PluginLoader{
|
|
|
|
constructor(...args){
|
|
|
|
this.init(...args)
|
|
|
|
}
|
2022-02-22 14:23:01 +01:00
|
|
|
init(script, name, hash, raw){
|
2022-02-11 15:28:22 +01:00
|
|
|
this.name = name
|
|
|
|
this.hash = hash
|
|
|
|
if(typeof script === "string"){
|
2022-02-22 14:23:01 +01:00
|
|
|
if(raw){
|
|
|
|
this.url = URL.createObjectURL(new Blob([script], {
|
|
|
|
type: "application/javascript"
|
|
|
|
}))
|
|
|
|
}else{
|
|
|
|
this.url = script
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
}else{
|
|
|
|
this.class = script
|
|
|
|
}
|
|
|
|
}
|
2022-02-22 14:23:01 +01:00
|
|
|
load(loadErrors){
|
|
|
|
if(this.loaded){
|
2022-02-11 15:28:22 +01:00
|
|
|
return Promise.resolve()
|
2022-02-22 14:23:01 +01:00
|
|
|
}else if(!this.url && !this.class){
|
|
|
|
if(loadErrors){
|
|
|
|
return Promise.reject()
|
|
|
|
}else{
|
|
|
|
return Promise.resolve()
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
}else{
|
|
|
|
return (this.url ? import(this.url) : Promise.resolve({
|
|
|
|
default: this.class
|
|
|
|
})).then(module => {
|
|
|
|
if(this.url){
|
|
|
|
URL.revokeObjectURL(this.url)
|
|
|
|
delete this.url
|
|
|
|
}else{
|
|
|
|
delete this.class
|
|
|
|
}
|
|
|
|
this.loaded = true
|
|
|
|
try{
|
|
|
|
this.module = new module.default()
|
|
|
|
}catch(e){
|
|
|
|
this.error()
|
2022-03-03 23:26:17 +01:00
|
|
|
var error = new Error()
|
|
|
|
error.stack = "Error initializing plugin: " + this.name + "\n" + e.stack
|
|
|
|
if(loadErrors){
|
|
|
|
return Promise.reject(error)
|
|
|
|
}else{
|
|
|
|
console.error(error)
|
|
|
|
return Promise.resolve()
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
2022-02-23 18:31:52 +01:00
|
|
|
var output
|
2022-02-11 15:28:22 +01:00
|
|
|
try{
|
|
|
|
if(this.module.beforeLoad){
|
|
|
|
this.module.beforeLoad(this)
|
|
|
|
}
|
|
|
|
if(this.module.load){
|
2022-02-23 18:31:52 +01:00
|
|
|
output = this.module.load(this)
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
}catch(e){
|
|
|
|
this.error()
|
2022-03-03 23:26:17 +01:00
|
|
|
var error = new Error()
|
|
|
|
error.stack = "Error in plugin load: " + this.name + "\n" + e.stack
|
|
|
|
if(loadErrors){
|
|
|
|
return Promise.reject(error)
|
|
|
|
}else{
|
|
|
|
console.error(error)
|
|
|
|
return Promise.resolve()
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
2022-02-23 18:31:52 +01:00
|
|
|
if(typeof output === "object" && output.constructor === Promise){
|
|
|
|
return output.catch(e => {
|
|
|
|
this.error()
|
2022-03-03 23:26:17 +01:00
|
|
|
var error = new Error()
|
|
|
|
error.stack = "Error in plugin load promise: " + this.name + (e ? "\n" + e.stack : "")
|
|
|
|
if(loadErrors){
|
|
|
|
return Promise.reject(error)
|
|
|
|
}else{
|
|
|
|
console.error(error)
|
|
|
|
return Promise.resolve()
|
|
|
|
}
|
2022-02-23 18:31:52 +01:00
|
|
|
})
|
|
|
|
}
|
2022-02-17 21:50:07 +01:00
|
|
|
}, e => {
|
|
|
|
this.error()
|
2022-07-15 16:00:43 +02:00
|
|
|
plugins.remove(this.name)
|
2022-03-03 23:26:17 +01:00
|
|
|
if(e.name === "SyntaxError"){
|
|
|
|
var error = new SyntaxError()
|
|
|
|
error.stack = "Error in plugin syntax: " + this.name + "\n" + e.stack
|
|
|
|
}else{
|
|
|
|
var error = e
|
|
|
|
}
|
2022-02-22 14:23:01 +01:00
|
|
|
if(loadErrors){
|
2022-03-03 23:26:17 +01:00
|
|
|
return Promise.reject(error)
|
2022-02-22 14:23:01 +01:00
|
|
|
}else{
|
2022-03-03 23:26:17 +01:00
|
|
|
console.error(error)
|
2022-02-22 14:23:01 +01:00
|
|
|
return Promise.resolve()
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2022-07-15 16:00:43 +02:00
|
|
|
start(orderChange, startErrors){
|
2022-02-17 21:50:07 +01:00
|
|
|
if(!orderChange){
|
|
|
|
plugins.startOrder.push(this.name)
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
return this.load().then(() => {
|
|
|
|
if(!this.started && this.module){
|
|
|
|
this.started = true
|
|
|
|
try{
|
|
|
|
if(this.module.beforeStart){
|
|
|
|
this.module.beforeStart()
|
|
|
|
}
|
|
|
|
if(this.module.start){
|
|
|
|
this.module.start()
|
|
|
|
}
|
|
|
|
}catch(e){
|
2022-07-15 16:00:43 +02:00
|
|
|
this.error()
|
2022-03-03 23:26:17 +01:00
|
|
|
var error = new Error()
|
|
|
|
error.stack = "Error in plugin start: " + this.name + "\n" + e.stack
|
2022-07-15 16:00:43 +02:00
|
|
|
if(startErrors){
|
|
|
|
return Promise.reject(error)
|
|
|
|
}else{
|
|
|
|
console.error(error)
|
|
|
|
return Promise.resolve()
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2022-03-03 23:26:17 +01:00
|
|
|
stop(orderChange, noError){
|
2022-02-11 15:28:22 +01:00
|
|
|
if(this.loaded && this.started){
|
2022-02-17 21:50:07 +01:00
|
|
|
if(!orderChange){
|
|
|
|
var stopIndex = plugins.startOrder.indexOf(this.name)
|
|
|
|
if(stopIndex !== -1){
|
|
|
|
plugins.startOrder.splice(stopIndex, 1)
|
|
|
|
for(var i = plugins.startOrder.length; i-- > stopIndex;){
|
|
|
|
plugins.pluginMap[plugins.startOrder[i]].stop(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-11 15:28:22 +01:00
|
|
|
this.started = false
|
|
|
|
try{
|
|
|
|
if(this.module.beforeStop){
|
|
|
|
this.module.beforeStop()
|
|
|
|
}
|
|
|
|
if(this.module.stop){
|
|
|
|
this.module.stop()
|
|
|
|
}
|
|
|
|
}catch(e){
|
2022-03-03 23:26:17 +01:00
|
|
|
var error = new Error()
|
|
|
|
error.stack = "Error in plugin stop: " + this.name + "\n" + e.stack
|
|
|
|
console.error(error)
|
|
|
|
if(!noError){
|
2022-02-11 15:28:22 +01:00
|
|
|
this.error()
|
|
|
|
}
|
|
|
|
}
|
2022-02-17 21:50:07 +01:00
|
|
|
|
|
|
|
if(!orderChange && stopIndex !== -1){
|
|
|
|
for(var i = stopIndex; i < plugins.startOrder.length; i++){
|
|
|
|
plugins.pluginMap[plugins.startOrder[i]].start(true)
|
|
|
|
}
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
unload(error){
|
|
|
|
if(this.loaded){
|
|
|
|
if(this.started){
|
2022-02-17 21:50:07 +01:00
|
|
|
this.stop(false, error)
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
this.loaded = false
|
|
|
|
plugins.remove(this.name)
|
|
|
|
if(this.module){
|
|
|
|
try{
|
|
|
|
if(this.module.beforeUnload){
|
|
|
|
this.module.beforeUnload()
|
|
|
|
}
|
|
|
|
if(this.module.unload){
|
|
|
|
this.module.unload()
|
|
|
|
}
|
|
|
|
}catch(e){
|
2022-03-03 23:26:17 +01:00
|
|
|
var error = new Error()
|
|
|
|
error.stack = "Error in plugin unload: " + this.name + "\n" + e.stack
|
|
|
|
console.error(error)
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
delete this.module
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
error(){
|
|
|
|
if(this.module && this.module.error){
|
|
|
|
try{
|
|
|
|
this.module.error()
|
|
|
|
}catch(e){
|
2022-03-03 23:26:17 +01:00
|
|
|
var error = new Error()
|
|
|
|
error.stack = "Error in plugin error: " + this.name + "\n" + e.stack
|
|
|
|
console.error(error)
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
this.unload(true)
|
|
|
|
}
|
2022-02-22 14:23:01 +01:00
|
|
|
settings(){
|
|
|
|
if(this.module && this.module.settings){
|
|
|
|
try{
|
|
|
|
var settings = this.module.settings()
|
|
|
|
}catch(e){
|
|
|
|
console.error(e)
|
|
|
|
this.error()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if(Array.isArray(settings)){
|
|
|
|
return settings
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
class EditValue{
|
|
|
|
constructor(...args){
|
|
|
|
this.init(...args)
|
|
|
|
}
|
|
|
|
init(parent, name){
|
|
|
|
if(name){
|
2022-02-22 14:23:01 +01:00
|
|
|
if(!parent){
|
|
|
|
throw new Error("Parent is not defined")
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
this.name = [parent, name]
|
|
|
|
this.delete = !(name in parent)
|
|
|
|
}else{
|
|
|
|
this.original = parent
|
|
|
|
}
|
|
|
|
}
|
|
|
|
load(callback){
|
2022-02-17 21:50:07 +01:00
|
|
|
this.loadCallback = callback
|
2022-02-11 15:28:22 +01:00
|
|
|
return this
|
|
|
|
}
|
|
|
|
start(){
|
|
|
|
if(this.name){
|
2022-02-17 21:50:07 +01:00
|
|
|
this.original = this.name[0][this.name[1]]
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
2022-03-03 23:26:17 +01:00
|
|
|
try{
|
|
|
|
var output = this.loadCallback(this.original)
|
|
|
|
}catch(e){
|
|
|
|
console.error(this.loadCallback)
|
|
|
|
var error = new Error()
|
|
|
|
error.stack = "Error editing the value of " + this.getName() + "\n" + e.stack
|
|
|
|
throw error
|
|
|
|
}
|
2022-02-17 21:50:07 +01:00
|
|
|
if(typeof output === "undefined"){
|
2022-03-03 23:26:17 +01:00
|
|
|
console.error(this.loadCallback)
|
|
|
|
throw new Error("Error editing the value of " + this.getName() + ": A value is expected to be returned")
|
2022-02-17 21:50:07 +01:00
|
|
|
}
|
|
|
|
if(this.name){
|
|
|
|
this.name[0][this.name[1]] = output
|
|
|
|
}
|
|
|
|
return output
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
stop(){
|
|
|
|
if(this.name){
|
|
|
|
if(this.delete){
|
|
|
|
delete this.name[0][this.name[1]]
|
|
|
|
}else{
|
|
|
|
this.name[0][this.name[1]] = this.original
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this.original
|
|
|
|
}
|
2022-03-03 23:26:17 +01:00
|
|
|
getName(){
|
|
|
|
var name = "unknown"
|
|
|
|
try{
|
|
|
|
if(this.name){
|
|
|
|
var name = (
|
|
|
|
typeof this.name[0] === "function" && this.name[0].name
|
|
|
|
|| (
|
|
|
|
typeof this.name[0] === "object" && typeof this.name[0].constructor === "function" && (
|
|
|
|
this.name[0] instanceof this.name[0].constructor ? (() => {
|
|
|
|
var consName = this.name[0].constructor.name || ""
|
|
|
|
return consName.slice(0, 1).toLowerCase() + consName.slice(1)
|
|
|
|
})() : this.name[0].constructor.name + ".prototype"
|
|
|
|
)
|
|
|
|
) || name
|
|
|
|
) + (this.name[1] ? "." + this.name[1] : "")
|
|
|
|
}
|
|
|
|
}catch(e){
|
|
|
|
name = "error"
|
|
|
|
}
|
|
|
|
return name
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
unload(){
|
|
|
|
delete this.name
|
|
|
|
delete this.original
|
2022-02-17 21:50:07 +01:00
|
|
|
delete this.loadCallback
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class EditFunction extends EditValue{
|
2022-02-17 21:50:07 +01:00
|
|
|
start(){
|
|
|
|
if(this.name){
|
|
|
|
this.original = this.name[0][this.name[1]]
|
|
|
|
}
|
2022-03-16 07:55:25 +01:00
|
|
|
if(typeof this.original !== "function"){
|
|
|
|
console.error(this.loadCallback)
|
|
|
|
var error = new Error()
|
|
|
|
error.stack = "Error editing the function value of " + this.getName() + ": Original value is not a function"
|
|
|
|
throw error
|
|
|
|
}
|
2022-02-17 21:50:07 +01:00
|
|
|
var args = plugins.argsFromFunc(this.original)
|
2022-03-03 23:26:17 +01:00
|
|
|
try{
|
|
|
|
var output = this.loadCallback(plugins.strFromFunc(this.original), args)
|
|
|
|
}catch(e){
|
|
|
|
console.error(this.loadCallback)
|
|
|
|
var error = new Error()
|
|
|
|
error.stack = "Error editing the function value of " + this.getName() + "\n" + e.stack
|
|
|
|
throw error
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
if(typeof output === "undefined"){
|
2022-03-03 23:26:17 +01:00
|
|
|
console.error(this.loadCallback)
|
|
|
|
throw new Error("Error editing the function value of " + this.getName() + ": A value is expected to be returned")
|
|
|
|
}
|
|
|
|
try{
|
|
|
|
var output = Function(...args, output)
|
|
|
|
}catch(e){
|
|
|
|
console.error(this.loadCallback)
|
|
|
|
var error = new SyntaxError()
|
|
|
|
var blob = new Blob([output], {
|
|
|
|
type: "application/javascript"
|
|
|
|
})
|
|
|
|
var url = URL.createObjectURL(blob)
|
|
|
|
error.stack = "Error editing the function value of " + this.getName() + ": Could not evaluate string, check the full string for errors: " + url + "\n" + e.stack
|
|
|
|
setTimeout(() => {
|
|
|
|
URL.revokeObjectURL(url)
|
|
|
|
}, 5 * 60 * 1000)
|
|
|
|
throw error
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
2022-02-17 21:50:07 +01:00
|
|
|
if(this.name){
|
|
|
|
this.name[0][this.name[1]] = output
|
|
|
|
}
|
|
|
|
return output
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class Patch{
|
2022-03-16 07:55:25 +01:00
|
|
|
constructor(...args){
|
|
|
|
this.init(...args)
|
|
|
|
}
|
|
|
|
init(){
|
|
|
|
this.edits = []
|
|
|
|
this.addedLanguages = []
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
addEdits(...args){
|
|
|
|
args.forEach(arg => this.edits.push(arg))
|
|
|
|
}
|
2022-03-03 16:19:16 +01:00
|
|
|
addLanguage(lang, forceSet, fallback="en"){
|
|
|
|
if(fallback){
|
|
|
|
lang = plugins.deepMerge({}, allStrings[fallback], lang)
|
|
|
|
}
|
|
|
|
this.addedLanguages.push({
|
|
|
|
lang: lang,
|
|
|
|
forceSet: forceSet
|
|
|
|
})
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
beforeStart(){
|
|
|
|
this.edits.forEach(edit => edit.start())
|
2022-03-03 16:19:16 +01:00
|
|
|
this.addedLanguages.forEach(obj => {
|
|
|
|
settings.addLang(obj.lang, obj.forceSet)
|
|
|
|
})
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
beforeStop(){
|
2022-03-03 16:19:16 +01:00
|
|
|
for(var i = this.edits.length; i--;){
|
|
|
|
this.edits[i].stop()
|
|
|
|
}
|
|
|
|
for(var i = this.addedLanguages.length; i--;){
|
|
|
|
settings.removeLang(this.addedLanguages[i].lang)
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
}
|
|
|
|
beforeUnload(){
|
|
|
|
this.edits.forEach(edit => edit.unload())
|
|
|
|
}
|
2022-02-23 18:31:52 +01:00
|
|
|
log(...args){
|
2022-02-11 15:28:22 +01:00
|
|
|
var name = this.name || "Plugin"
|
|
|
|
console.log(
|
2022-02-23 18:31:52 +01:00
|
|
|
"%c[" + name + "]",
|
2022-02-11 15:28:22 +01:00
|
|
|
"font-weight: bold;",
|
2022-02-23 18:31:52 +01:00
|
|
|
...args
|
2022-02-11 15:28:22 +01:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|