mirror of
https://github.com/stashapp/CommunityScripts.git
synced 2025-12-14 13:03:19 -06:00
142 lines
5.4 KiB
JavaScript
142 lines
5.4 KiB
JavaScript
// CommunityScripts UI Library
|
|
// cs-ui-lib.js
|
|
(function () {
|
|
// get base URL for graphQL queries
|
|
const baseURL = document.querySelector("base")?.getAttribute("href") ?? "/";
|
|
|
|
/**
|
|
* This is a wrapped GraphQL (GQL) query caller
|
|
* @param {...Object} reqData
|
|
* @param {Object} reqData.query - GraphQL query
|
|
* @param {Object}= reqData.variables - GraphQL variables
|
|
* @returns {Object} - GQL response data with the `data` wrapper removed
|
|
*
|
|
* @example
|
|
* // fetch the count of organized scenes
|
|
* const filter = { organized: true };
|
|
* const query = `query findScenes($filter: SceneFilter) { findScenes(filter: $filter) { count } }`;
|
|
* const variables = { filter };
|
|
* const response = await callGQL({ query, variables });
|
|
* // response = { findScenes: { count: 3 } }
|
|
*/
|
|
const callGQL = (reqData) =>
|
|
fetch(`${baseURL}graphql`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(reqData),
|
|
})
|
|
.then((res) => res.json())
|
|
.then((res) => res.data);
|
|
|
|
/**
|
|
* Get configuration of a plugin from the server via GraphQL
|
|
* @param {string} pluginId - The ID of the plugin as it is registered in the server
|
|
* @param {*}= fallback - Fallback value if the configuration is not found. Defaults to an empty object
|
|
* @returns {Object} - The configuration object of the plugin as it is stored in the server
|
|
*
|
|
* @example
|
|
* // set default config
|
|
* const defaultConfig = { enabled: true, theme: 'light' };
|
|
* // fetch config from the server
|
|
* const config = await getConfiguration('CommunityScriptsUIPlugin', defaultConfig);
|
|
* // config = { theme: 'dark' }
|
|
* // merge fetched with default config
|
|
* const pluginConfig = {
|
|
* ...defaultConfig
|
|
* ...config
|
|
* };
|
|
* // pluginConfig = { enabled: true, theme: 'dark' }
|
|
* }
|
|
*/
|
|
const getConfiguration = async (pluginId, fallback = {}) => {
|
|
const query = `query Configuration { configuration { plugins }}`;
|
|
const response = await callGQL({ query });
|
|
return response.configuration.plugins?.[pluginId] ?? fallback;
|
|
};
|
|
|
|
/**
|
|
* Set configuration of a plugin in the server via GraphQL
|
|
* @param {string} pluginId - The ID of the plugin as it is registered in the server
|
|
* @param {*} values - The configuration object with the values you want to save in the server
|
|
* @returns {Object} - The configuration object of the plugin as it is stored in the server after update
|
|
*
|
|
* @example
|
|
* // fetch config from the server
|
|
* const config = await getConfiguration('CommunityScriptsUIPlugin', defaultConfig);
|
|
* // config = { theme: 'dark' }
|
|
* // update the config based on user input
|
|
* // config = { theme: 'light' }
|
|
* // save config in the server
|
|
* await setConfiguration('CommunityScriptsUIPlugin', config);
|
|
* }
|
|
*/
|
|
const setConfiguration = async (pluginId, values) => {
|
|
const query = `mutation ConfigurePlugin($pluginId: ID!, $input: Map!) { configurePlugin(plugin_id: $pluginId, input: $input) }`;
|
|
const queryBody = {
|
|
query: query,
|
|
variables: {
|
|
pluginId: pluginId,
|
|
input: values,
|
|
},
|
|
};
|
|
const response = await csLib.callGQL({ ...queryBody });
|
|
return response.configurePlugin;
|
|
};
|
|
|
|
/**
|
|
* Waits for an element to be available in the DOM and runs the callback function once it is
|
|
* @param {string} selector - The CSS selector of the element to wait for
|
|
* @param {function} callback - The function to be called once the element is available (with the element as an argument)
|
|
* @returns
|
|
*
|
|
* @example
|
|
* // wait for the element with the class 'my-element' to be available
|
|
* // and change its color to red
|
|
* function myCallback(el) {
|
|
* el.style.color = 'red';
|
|
* };
|
|
* waitForElement('.my-element', myCallback);
|
|
*/
|
|
function waitForElement(selector, callback) {
|
|
var el = document.querySelector(selector);
|
|
if (el) return callback(el);
|
|
setTimeout(waitForElement, 100, selector, callback);
|
|
}
|
|
|
|
/**
|
|
* Wait for a specific element to be available on a specific path
|
|
* This combines the `waitForElement` and `PluginApi.Event.addEventListener` functions to only trigger on certain pages
|
|
*
|
|
* @param {string} path - The path to listen for
|
|
* @param {string} element - The CSS selector of the element to wait for
|
|
* @param {function} callback - The function to be called once the element is available (with the element as an argument)
|
|
*
|
|
* @example
|
|
* // wait for the element with the class 'my-element' to be available, but only on the `/scene/#` path
|
|
* function myCallback(el) {
|
|
* el.style.color = 'red';
|
|
* };
|
|
* PathElementListener('/scene/', '.my-element', myCallback);
|
|
* // this will only trigger the callback function when the user is on the `/scene/` path AND the element is available
|
|
*/
|
|
const PathElementListener = (path, element, callback) => {
|
|
// startup location
|
|
if (window.location.pathname.startsWith(path))
|
|
waitForElement(element, callback);
|
|
PluginApi.Event.addEventListener("stash:location", (e) => {
|
|
if (e.detail.data.location.pathname.startsWith(path))
|
|
waitForElement(element, callback);
|
|
});
|
|
};
|
|
|
|
// export to window
|
|
window.csLib = {
|
|
baseURL,
|
|
callGQL,
|
|
getConfiguration,
|
|
setConfiguration,
|
|
waitForElement,
|
|
PathElementListener,
|
|
};
|
|
})();
|