Split skins script into own file
It's rather large and only used in certain places.
This commit is contained in:
parent
d609891f82
commit
edd0db4807
@ -1710,6 +1710,17 @@
|
||||
"sC" : 3,
|
||||
"tS" : 0
|
||||
},
|
||||
"\/js\/critical-skin-script.min.js" : {
|
||||
"bF" : 0,
|
||||
"ft" : 64,
|
||||
"ma" : 0,
|
||||
"mi" : 1,
|
||||
"oA" : 0,
|
||||
"oAP" : "\/js\/critical-skin-script.min.min.js",
|
||||
"oF" : 0,
|
||||
"sC" : 3,
|
||||
"tS" : 0
|
||||
},
|
||||
"\/js\/customizer.min.js" : {
|
||||
"bF" : 0,
|
||||
"ft" : 64,
|
||||
@ -2334,6 +2345,17 @@
|
||||
"sC" : 3,
|
||||
"tS" : 0
|
||||
},
|
||||
"\/src\/js\/css-skins.js" : {
|
||||
"bF" : 0,
|
||||
"ft" : 64,
|
||||
"ma" : 0,
|
||||
"mi" : 1,
|
||||
"oA" : 0,
|
||||
"oAP" : "\/js\/css-skins.min.js",
|
||||
"oF" : 2,
|
||||
"sC" : 3,
|
||||
"tS" : 0
|
||||
},
|
||||
"\/src\/js\/customizer.js" : {
|
||||
"bF" : 0,
|
||||
"ft" : 64,
|
||||
|
@ -1350,6 +1350,9 @@ function fictioneer_add_custom_scripts() {
|
||||
// User Profile
|
||||
wp_register_script( 'fictioneer-user-profile-scripts', get_template_directory_uri() . '/js/user-profile.min.js', [ 'fictioneer-application-scripts', 'fictioneer-user-scripts'], $cache_bust, $strategy );
|
||||
|
||||
// CSS Skins
|
||||
wp_register_script( 'fictioneer-css-skins-scripts', get_template_directory_uri() . '/js/css-skins.min.js', [ 'fictioneer-application-scripts', 'fictioneer-user-scripts'], $cache_bust, $strategy );
|
||||
|
||||
// Bookmarks
|
||||
wp_register_script( 'fictioneer-bookmarks-scripts', get_template_directory_uri() . '/js/bookmarks.min.js', [ 'fictioneer-application-scripts', 'fictioneer-user-scripts'], $cache_bust, $strategy );
|
||||
|
||||
@ -1438,6 +1441,10 @@ function fictioneer_add_custom_scripts() {
|
||||
|
||||
if ( is_page_template( 'user-profile.php' ) ) {
|
||||
wp_enqueue_script( 'fictioneer-user-profile-scripts' );
|
||||
|
||||
if ( get_option( 'fictioneer_enable_css_skins' ) ) {
|
||||
wp_enqueue_script( 'fictioneer-css-skins-scripts' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
10
js/complete.min.js
vendored
10
js/complete.min.js
vendored
File diff suppressed because one or more lines are too long
1
js/css-skins.min.js
vendored
Normal file
1
js/css-skins.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
js/user-profile.min.js
vendored
2
js/user-profile.min.js
vendored
File diff suppressed because one or more lines are too long
411
src/js/css-skins.js
Normal file
411
src/js/css-skins.js
Normal file
@ -0,0 +1,411 @@
|
||||
/**
|
||||
* Returns the skins JSON from local storage or a default.
|
||||
*
|
||||
* @since 5.26.0
|
||||
* @return {Object} The skins JSON.
|
||||
*/
|
||||
|
||||
function fcn_getSkins() {
|
||||
const fingerprint = fcn_getCookie('fcnLoggedIn');
|
||||
|
||||
if (!fingerprint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const _default = { 'data': {}, 'active': null, 'fingerprint': fingerprint };
|
||||
const skins = fcn_parseJSON(localStorage.getItem('fcnSkins')) ?? _default;
|
||||
|
||||
if (!skins?.fingerprint || fingerprint !== skins.fingerprint) {
|
||||
return _default;
|
||||
}
|
||||
|
||||
if (typeof skins.data !== 'object' || Array.isArray(skins.data)) {
|
||||
skins.data = {};
|
||||
}
|
||||
|
||||
return skins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the skins JSON to local storage.
|
||||
*
|
||||
* @since 5.26.0
|
||||
* @param {Object} skins - The skins to store.
|
||||
*/
|
||||
|
||||
function fcn_setSkins(skins) {
|
||||
if (
|
||||
typeof skins !== 'object' || skins === null ||
|
||||
typeof skins.data !== 'object' || Array.isArray(skins.data)
|
||||
) {
|
||||
fcn_showNotification(fcn_skinTranslations.invalidJson, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!skins?.fingerprint || fcn_getCookie('fcnLoggedIn') !== skins.fingerprint) {
|
||||
fcn_showNotification(fcn_skinTranslations.wrongFingerprint, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem('fcnSkins', JSON.stringify(skins));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns info object about a CSS skin.
|
||||
*
|
||||
* @since 5.26.0
|
||||
* @param {String} css - The CSS to analyze.
|
||||
* @return {Object} CSS info with name, author, and version.
|
||||
*/
|
||||
|
||||
function fcn_getSkinInfo(css) {
|
||||
const nameMatch = css.match(/Name:\s*(.+)/);
|
||||
const authorMatch = css.match(/Author:\s*(.+)/);
|
||||
const versionMatch = css.match(/Version:\s*(.+)/);
|
||||
|
||||
return {
|
||||
name: nameMatch ? fcn_sanitizeHTML(nameMatch[1].trim()) : null,
|
||||
author: authorMatch ? fcn_sanitizeHTML(authorMatch[1].trim()) : null,
|
||||
version: versionMatch ? fcn_sanitizeHTML(versionMatch[1].trim()) : null
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the currently selected skin (custom CSS).
|
||||
*
|
||||
* @since 5.26.0
|
||||
* @param {HTMLElement} target - The clicked element.
|
||||
*/
|
||||
|
||||
function fcn_toggleSkin(target) {
|
||||
const item = target.closest('[data-css-skin-finder="skin-item"]');
|
||||
const skins = fcn_getSkins();
|
||||
|
||||
if (item.classList.contains('active')) {
|
||||
_$$('[data-css-skin-finder="skin-item"]').forEach(element => element.classList.remove('active'));
|
||||
skins.active = null;
|
||||
} else {
|
||||
_$$('[data-css-skin-finder="skin-item"]').forEach(element => element.classList.remove('active'));
|
||||
item.classList.add('active');
|
||||
skins.active = target.dataset.skinId;
|
||||
}
|
||||
|
||||
fcn_setSkins(skins);
|
||||
fcn_applySkin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the skin (custom CSS).
|
||||
*
|
||||
* @since 5.26.0
|
||||
* @param {HTMLElement} target - The clicked element.
|
||||
*/
|
||||
|
||||
function fcn_deleteSkin(target) {
|
||||
const item = target.closest('[data-css-skin-finder="skin-item"]');
|
||||
const skins = fcn_getSkins();
|
||||
|
||||
if (item.classList.contains('active')) {
|
||||
skins.active = null;
|
||||
}
|
||||
|
||||
delete skins.data[target.dataset.skinId];
|
||||
_$('[data-css-skin-target="file"]').value = '';
|
||||
|
||||
fcn_setSkins(skins);
|
||||
fcn_renderSkinList();
|
||||
fcn_applySkin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add skin (custom CSS) to document <head>.
|
||||
*
|
||||
* @since 5.26.0
|
||||
*/
|
||||
|
||||
function fcn_applySkin() {
|
||||
const fingerprint = fcn_getCookie('fcnLoggedIn');
|
||||
|
||||
// Ensure the theme login check is passed
|
||||
if (!fingerprint) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get skins from local storage
|
||||
const skins = fcn_getSkins();
|
||||
|
||||
// Cleanup old style tag (if any)
|
||||
_$$$('fictioneer-active-custom-skin')?.remove();
|
||||
|
||||
// Check fingerprint
|
||||
if (skins?.fingerprint !== fingerprint) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if skins data is valid and an active skin is set
|
||||
if (skins?.data?.[skins.active]?.css) {
|
||||
const styleTag = document.createElement('style');
|
||||
|
||||
styleTag.textContent = skins.data[skins.active].css;
|
||||
styleTag.id = 'fictioneer-active-custom-skin';
|
||||
|
||||
_$('head').appendChild(styleTag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders list of selectable skins.
|
||||
*
|
||||
* @since 5.26.0
|
||||
*/
|
||||
|
||||
function fcn_renderSkinList() {
|
||||
const container = _$('[data-css-skin-target="list"]');
|
||||
const fingerprint = fcn_getCookie('fcnLoggedIn');
|
||||
|
||||
// Ensure the theme login check is passed
|
||||
if (!fingerprint || !container) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get skins from local storage
|
||||
const skins = fcn_getSkins();
|
||||
|
||||
// Clear previous content
|
||||
container.innerHTML = '';
|
||||
|
||||
// Check fingerprint
|
||||
if (skins?.fingerprint !== fingerprint) {
|
||||
_$('[data-css-skin-target="form"]').style.display = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure skins data exists and has entries
|
||||
if (skins?.data && Object.keys(skins.data).length > 0) {
|
||||
// Loop through the skins and render them
|
||||
Object.entries(skins.data).forEach(([key, skin]) => {
|
||||
const template = _$('[data-css-skin-target="template"]').content.cloneNode(true);
|
||||
|
||||
// Active skin?
|
||||
if (skins.active === key) {
|
||||
template.querySelector('[data-css-skin-finder="skin-item"]').classList.add('active');
|
||||
}
|
||||
|
||||
// Fill template with skin data
|
||||
template.querySelector('[data-action="click->css-skin#toggle"]').dataset.skinId = key;
|
||||
template.querySelector('[data-action="click->css-skin#delete"]').dataset.skinId = key;
|
||||
template.querySelector('[data-css-skin-finder="name"]').innerText = skin.name;
|
||||
template.querySelector('[data-css-skin-finder="version"]').innerText = skin.version;
|
||||
template.querySelector('[data-css-skin-finder="author"]').innerText = skin.author;
|
||||
|
||||
// Append the template to the container
|
||||
container.appendChild(template);
|
||||
});
|
||||
|
||||
// Add click events
|
||||
_$$('[data-action="click->css-skin#toggle"]').forEach(button => {
|
||||
button.addEventListener('click', event => fcn_toggleSkin(event.currentTarget));
|
||||
});
|
||||
|
||||
_$$('[data-action="click->css-skin#delete"]').forEach(button => {
|
||||
button.addEventListener('click', event => fcn_deleteSkin(event.currentTarget));
|
||||
});
|
||||
}
|
||||
|
||||
if (Object.keys(skins.data).length > 2) {
|
||||
_$('[data-css-skin-target="form"]').style.display = 'none';
|
||||
} else {
|
||||
_$('[data-css-skin-target="form"]').style.display = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize
|
||||
fcn_renderSkinList();
|
||||
|
||||
// Upload
|
||||
_$('[data-css-skin-target="file"]')?.addEventListener('input', event => {
|
||||
event.preventDefault();
|
||||
|
||||
const input = event.currentTarget;
|
||||
const file = input.files[0];
|
||||
const skins = fcn_getSkins();
|
||||
const fingerprint = fcn_getCookie('fcnLoggedIn');
|
||||
|
||||
console.log(input);
|
||||
|
||||
if (Object.keys(skins.data).length > 2) {
|
||||
fcn_showNotification(fcn_skinTranslations.tooManySkins, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (skins?.fingerprint !== fingerprint) {
|
||||
fcn_showNotification(fcn_skinTranslations.wrongFingerprint, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.size > 200000) {
|
||||
fcn_showNotification(fcn_skinTranslations.fileTooLarge, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.type !== 'text/css') {
|
||||
fcn_showNotification(fcn_skinTranslations.wrongFileType, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = event => {
|
||||
const css = event.target.result;
|
||||
const info = fcn_getSkinInfo(css);
|
||||
const skins = fcn_getSkins();
|
||||
|
||||
if (!fcn_validateCss(css)) {
|
||||
fcn_showNotification(fcn_skinTranslations.invalidCss, 5, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info.name) {
|
||||
fcn_showNotification(fcn_skinTranslations.missingMetaData, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
const key = btoa(info.name);
|
||||
|
||||
skins.data[key] = {
|
||||
name: info.name,
|
||||
version: info.version,
|
||||
author: info.author,
|
||||
css: css
|
||||
};
|
||||
|
||||
fcn_setSkins(skins);
|
||||
fcn_renderSkinList();
|
||||
}
|
||||
|
||||
reader.onerror = () => {
|
||||
console.error(reader.error);
|
||||
fcn_showNotification(reader.error, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
reader.readAsText(file);
|
||||
});
|
||||
|
||||
/**
|
||||
* AJAX: Uploads the skins to the database.
|
||||
*
|
||||
* @since 5.26.0
|
||||
* @param {HTMLElement} trigger - The event trigger element.
|
||||
*/
|
||||
|
||||
function fcn_uploadSkins(trigger) {
|
||||
// Ensure the theme login check is passed
|
||||
if (!fcn_isUserLoggedIn() || trigger.classList.contains('disabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get skins from local storage
|
||||
const skins = fcn_getSkins();
|
||||
|
||||
// Toggle button progress
|
||||
fcn_toggleInProgress(trigger);
|
||||
|
||||
// Request
|
||||
fcn_ajaxPost({
|
||||
'action': 'fictioneer_ajax_save_skins',
|
||||
'fcn_fast_ajax': 1,
|
||||
'skins': JSON.stringify(skins)
|
||||
})
|
||||
.then(response => {
|
||||
if (response.success) {
|
||||
fcn_showNotification(response.data.message, 3, 'success');
|
||||
} else {
|
||||
fcn_showNotification(
|
||||
response.data.failure ?? response.data.error ?? fictioneer_tl.notification.error,
|
||||
3,
|
||||
'warning'
|
||||
);
|
||||
|
||||
// Make sure the actual error (if any) is printed to the console too
|
||||
if (response.data.error || response.data.failure) {
|
||||
console.error('Error:', response.data.error ?? response.data.failure);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.status && error.statusText) {
|
||||
fcn_showNotification(`${error.status}: ${error.statusText}`, 3, 'warning');
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
})
|
||||
.then(() => {
|
||||
fcn_toggleInProgress(trigger);
|
||||
});
|
||||
}
|
||||
|
||||
_$('[data-action="click->css-skin#upload"]')?.addEventListener('click', event => {
|
||||
fcn_uploadSkins(event.currentTarget);
|
||||
});
|
||||
|
||||
/**
|
||||
* AJAX: Downloads the skins from the database.
|
||||
*
|
||||
* @since 5.26.0
|
||||
* @param {HTMLElement} trigger - The event trigger element.
|
||||
*/
|
||||
|
||||
function fcn_downloadSkins(trigger) {
|
||||
// Ensure the theme login check is passed
|
||||
if (!fcn_isUserLoggedIn() || trigger.classList.contains('disabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle button progress
|
||||
fcn_toggleInProgress(trigger);
|
||||
|
||||
// Request
|
||||
fcn_ajaxPost({
|
||||
'action': 'fictioneer_ajax_get_skins',
|
||||
'fcn_fast_ajax': 1
|
||||
})
|
||||
.then(response => {
|
||||
if (response.success) {
|
||||
fcn_showNotification(response.data.message, 3, 'success');
|
||||
fcn_setSkins(JSON.parse(response.data.skins));
|
||||
fcn_renderSkinList();
|
||||
fcn_applySkin()
|
||||
} else {
|
||||
fcn_showNotification(
|
||||
response.data.failure ?? response.data.error ?? fictioneer_tl.notification.error,
|
||||
3,
|
||||
'warning'
|
||||
);
|
||||
|
||||
// Make sure the actual error (if any) is printed to the console too
|
||||
if (response.data.error || response.data.failure) {
|
||||
console.error('Error:', response.data.error ?? response.data.failure);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.status && error.statusText) {
|
||||
fcn_showNotification(`${error.status}: ${error.statusText}`, 3, 'warning');
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
})
|
||||
.then(() => {
|
||||
_$('[data-css-skin-target="file"]').value = '';
|
||||
fcn_toggleInProgress(trigger);
|
||||
});
|
||||
}
|
||||
|
||||
_$('[data-action="click->css-skin#download"]')?.addEventListener('click', event => {
|
||||
fcn_downloadSkins(event.currentTarget);
|
||||
});
|
@ -375,419 +375,3 @@ _$('.button-clear-bookmarks')?.addEventListener(
|
||||
fcn_setBookmarks(fcn_bookmarks);
|
||||
}
|
||||
);
|
||||
|
||||
// =============================================================================
|
||||
// CSS SKINS
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Returns the skins JSON from local storage or a default.
|
||||
*
|
||||
* @since 5.26.0
|
||||
* @return {Object} The skins JSON.
|
||||
*/
|
||||
|
||||
function fcn_getSkins() {
|
||||
const fingerprint = fcn_getCookie('fcnLoggedIn');
|
||||
|
||||
if (!fingerprint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const _default = { 'data': {}, 'active': null, 'fingerprint': fingerprint };
|
||||
const skins = fcn_parseJSON(localStorage.getItem('fcnSkins')) ?? _default;
|
||||
|
||||
if (!skins?.fingerprint || fingerprint !== skins.fingerprint) {
|
||||
return _default;
|
||||
}
|
||||
|
||||
if (typeof skins.data !== 'object' || Array.isArray(skins.data)) {
|
||||
skins.data = {};
|
||||
}
|
||||
|
||||
return skins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the skins JSON to local storage.
|
||||
*
|
||||
* @since 5.26.0
|
||||
* @param {Object} skins - The skins to store.
|
||||
*/
|
||||
|
||||
function fcn_setSkins(skins) {
|
||||
if (
|
||||
typeof skins !== 'object' || skins === null ||
|
||||
typeof skins.data !== 'object' || Array.isArray(skins.data)
|
||||
) {
|
||||
fcn_showNotification(fcn_skinTranslations.invalidJson, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!skins?.fingerprint || fcn_getCookie('fcnLoggedIn') !== skins.fingerprint) {
|
||||
fcn_showNotification(fcn_skinTranslations.wrongFingerprint, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem('fcnSkins', JSON.stringify(skins));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns info object about a CSS skin.
|
||||
*
|
||||
* @since 5.26.0
|
||||
* @param {String} css - The CSS to analyze.
|
||||
* @return {Object} CSS info with name, author, and version.
|
||||
*/
|
||||
|
||||
function fcn_getSkinInfo(css) {
|
||||
const nameMatch = css.match(/Name:\s*(.+)/);
|
||||
const authorMatch = css.match(/Author:\s*(.+)/);
|
||||
const versionMatch = css.match(/Version:\s*(.+)/);
|
||||
|
||||
return {
|
||||
name: nameMatch ? fcn_sanitizeHTML(nameMatch[1].trim()) : null,
|
||||
author: authorMatch ? fcn_sanitizeHTML(authorMatch[1].trim()) : null,
|
||||
version: versionMatch ? fcn_sanitizeHTML(versionMatch[1].trim()) : null
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the currently selected skin (custom CSS).
|
||||
*
|
||||
* @since 5.26.0
|
||||
* @param {HTMLElement} target - The clicked element.
|
||||
*/
|
||||
|
||||
function fcn_toggleSkin(target) {
|
||||
const item = target.closest('[data-css-skin-finder="skin-item"]');
|
||||
const skins = fcn_getSkins();
|
||||
|
||||
if (item.classList.contains('active')) {
|
||||
_$$('[data-css-skin-finder="skin-item"]').forEach(element => element.classList.remove('active'));
|
||||
skins.active = null;
|
||||
} else {
|
||||
_$$('[data-css-skin-finder="skin-item"]').forEach(element => element.classList.remove('active'));
|
||||
item.classList.add('active');
|
||||
skins.active = target.dataset.skinId;
|
||||
}
|
||||
|
||||
fcn_setSkins(skins);
|
||||
fcn_applySkin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the skin (custom CSS).
|
||||
*
|
||||
* @since 5.26.0
|
||||
* @param {HTMLElement} target - The clicked element.
|
||||
*/
|
||||
|
||||
function fcn_deleteSkin(target) {
|
||||
const item = target.closest('[data-css-skin-finder="skin-item"]');
|
||||
const skins = fcn_getSkins();
|
||||
|
||||
if (item.classList.contains('active')) {
|
||||
skins.active = null;
|
||||
}
|
||||
|
||||
delete skins.data[target.dataset.skinId];
|
||||
_$('[data-css-skin-target="file"]').value = '';
|
||||
|
||||
fcn_setSkins(skins);
|
||||
fcn_renderSkinList();
|
||||
fcn_applySkin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add skin (custom CSS) to document <head>.
|
||||
*
|
||||
* @since 5.26.0
|
||||
*/
|
||||
|
||||
function fcn_applySkin() {
|
||||
const fingerprint = fcn_getCookie('fcnLoggedIn');
|
||||
|
||||
// Ensure the theme login check is passed
|
||||
if (!fingerprint) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get skins from local storage
|
||||
const skins = fcn_getSkins();
|
||||
|
||||
// Cleanup old style tag (if any)
|
||||
_$$$('fictioneer-active-custom-skin')?.remove();
|
||||
|
||||
// Check fingerprint
|
||||
if (skins?.fingerprint !== fingerprint) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if skins data is valid and an active skin is set
|
||||
if (skins?.data?.[skins.active]?.css) {
|
||||
const styleTag = document.createElement('style');
|
||||
|
||||
styleTag.textContent = skins.data[skins.active].css;
|
||||
styleTag.id = 'fictioneer-active-custom-skin';
|
||||
|
||||
_$('head').appendChild(styleTag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders list of selectable skins.
|
||||
*
|
||||
* @since 5.26.0
|
||||
*/
|
||||
|
||||
function fcn_renderSkinList() {
|
||||
const container = _$('[data-css-skin-target="list"]');
|
||||
const fingerprint = fcn_getCookie('fcnLoggedIn');
|
||||
|
||||
// Ensure the theme login check is passed
|
||||
if (!fingerprint || !container) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get skins from local storage
|
||||
const skins = fcn_getSkins();
|
||||
|
||||
// Clear previous content
|
||||
container.innerHTML = '';
|
||||
|
||||
// Check fingerprint
|
||||
if (skins?.fingerprint !== fingerprint) {
|
||||
_$('[data-css-skin-target="form"]').style.display = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure skins data exists and has entries
|
||||
if (skins?.data && Object.keys(skins.data).length > 0) {
|
||||
// Loop through the skins and render them
|
||||
Object.entries(skins.data).forEach(([key, skin]) => {
|
||||
const template = _$('[data-css-skin-target="template"]').content.cloneNode(true);
|
||||
|
||||
// Active skin?
|
||||
if (skins.active === key) {
|
||||
template.querySelector('[data-css-skin-finder="skin-item"]').classList.add('active');
|
||||
}
|
||||
|
||||
// Fill template with skin data
|
||||
template.querySelector('[data-action="click->css-skin#toggle"]').dataset.skinId = key;
|
||||
template.querySelector('[data-action="click->css-skin#delete"]').dataset.skinId = key;
|
||||
template.querySelector('[data-css-skin-finder="name"]').innerText = skin.name;
|
||||
template.querySelector('[data-css-skin-finder="version"]').innerText = skin.version;
|
||||
template.querySelector('[data-css-skin-finder="author"]').innerText = skin.author;
|
||||
|
||||
// Append the template to the container
|
||||
container.appendChild(template);
|
||||
});
|
||||
|
||||
// Add click events
|
||||
_$$('[data-action="click->css-skin#toggle"]').forEach(button => {
|
||||
button.addEventListener('click', event => fcn_toggleSkin(event.currentTarget));
|
||||
});
|
||||
|
||||
_$$('[data-action="click->css-skin#delete"]').forEach(button => {
|
||||
button.addEventListener('click', event => fcn_deleteSkin(event.currentTarget));
|
||||
});
|
||||
}
|
||||
|
||||
if (Object.keys(skins.data).length > 2) {
|
||||
_$('[data-css-skin-target="form"]').style.display = 'none';
|
||||
} else {
|
||||
_$('[data-css-skin-target="form"]').style.display = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize
|
||||
fcn_renderSkinList();
|
||||
|
||||
// Upload
|
||||
_$('[data-css-skin-target="file"]')?.addEventListener('input', event => {
|
||||
event.preventDefault();
|
||||
|
||||
const input = event.currentTarget;
|
||||
const file = input.files[0];
|
||||
const skins = fcn_getSkins();
|
||||
const fingerprint = fcn_getCookie('fcnLoggedIn');
|
||||
|
||||
console.log(input);
|
||||
|
||||
if (Object.keys(skins.data).length > 2) {
|
||||
fcn_showNotification(fcn_skinTranslations.tooManySkins, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (skins?.fingerprint !== fingerprint) {
|
||||
fcn_showNotification(fcn_skinTranslations.wrongFingerprint, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.size > 200000) {
|
||||
fcn_showNotification(fcn_skinTranslations.fileTooLarge, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.type !== 'text/css') {
|
||||
fcn_showNotification(fcn_skinTranslations.wrongFileType, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = event => {
|
||||
const css = event.target.result;
|
||||
const info = fcn_getSkinInfo(css);
|
||||
const skins = fcn_getSkins();
|
||||
|
||||
if (!fcn_validateCss(css)) {
|
||||
fcn_showNotification(fcn_skinTranslations.invalidCss, 5, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info.name) {
|
||||
fcn_showNotification(fcn_skinTranslations.missingMetaData, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
const key = btoa(info.name);
|
||||
|
||||
skins.data[key] = {
|
||||
name: info.name,
|
||||
version: info.version,
|
||||
author: info.author,
|
||||
css: css
|
||||
};
|
||||
|
||||
fcn_setSkins(skins);
|
||||
fcn_renderSkinList();
|
||||
}
|
||||
|
||||
reader.onerror = () => {
|
||||
console.error(reader.error);
|
||||
fcn_showNotification(reader.error, 3, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
reader.readAsText(file);
|
||||
});
|
||||
|
||||
/**
|
||||
* AJAX: Uploads the skins to the database.
|
||||
*
|
||||
* @since 5.26.0
|
||||
* @param {HTMLElement} trigger - The event trigger element.
|
||||
*/
|
||||
|
||||
function fcn_uploadSkins(trigger) {
|
||||
// Ensure the theme login check is passed
|
||||
if (!fcn_isUserLoggedIn() || trigger.classList.contains('disabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get skins from local storage
|
||||
const skins = fcn_getSkins();
|
||||
|
||||
// Toggle button progress
|
||||
fcn_toggleInProgress(trigger);
|
||||
|
||||
// Request
|
||||
fcn_ajaxPost({
|
||||
'action': 'fictioneer_ajax_save_skins',
|
||||
'fcn_fast_ajax': 1,
|
||||
'skins': JSON.stringify(skins)
|
||||
})
|
||||
.then(response => {
|
||||
if (response.success) {
|
||||
fcn_showNotification(response.data.message, 3, 'success');
|
||||
} else {
|
||||
fcn_showNotification(
|
||||
response.data.failure ?? response.data.error ?? fictioneer_tl.notification.error,
|
||||
3,
|
||||
'warning'
|
||||
);
|
||||
|
||||
// Make sure the actual error (if any) is printed to the console too
|
||||
if (response.data.error || response.data.failure) {
|
||||
console.error('Error:', response.data.error ?? response.data.failure);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.status && error.statusText) {
|
||||
fcn_showNotification(`${error.status}: ${error.statusText}`, 3, 'warning');
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
})
|
||||
.then(() => {
|
||||
fcn_toggleInProgress(trigger);
|
||||
});
|
||||
}
|
||||
|
||||
_$('[data-action="click->css-skin#upload"]')?.addEventListener('click', event => {
|
||||
fcn_uploadSkins(event.currentTarget);
|
||||
});
|
||||
|
||||
/**
|
||||
* AJAX: Downloads the skins from the database.
|
||||
*
|
||||
* @since 5.26.0
|
||||
* @param {HTMLElement} trigger - The event trigger element.
|
||||
*/
|
||||
|
||||
function fcn_downloadSkins(trigger) {
|
||||
// Ensure the theme login check is passed
|
||||
if (!fcn_isUserLoggedIn() || trigger.classList.contains('disabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle button progress
|
||||
fcn_toggleInProgress(trigger);
|
||||
|
||||
// Request
|
||||
fcn_ajaxPost({
|
||||
'action': 'fictioneer_ajax_get_skins',
|
||||
'fcn_fast_ajax': 1
|
||||
})
|
||||
.then(response => {
|
||||
if (response.success) {
|
||||
fcn_showNotification(response.data.message, 3, 'success');
|
||||
fcn_setSkins(JSON.parse(response.data.skins));
|
||||
fcn_renderSkinList();
|
||||
fcn_applySkin()
|
||||
} else {
|
||||
fcn_showNotification(
|
||||
response.data.failure ?? response.data.error ?? fictioneer_tl.notification.error,
|
||||
3,
|
||||
'warning'
|
||||
);
|
||||
|
||||
// Make sure the actual error (if any) is printed to the console too
|
||||
if (response.data.error || response.data.failure) {
|
||||
console.error('Error:', response.data.error ?? response.data.failure);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.status && error.statusText) {
|
||||
fcn_showNotification(`${error.status}: ${error.statusText}`, 3, 'warning');
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
})
|
||||
.then(() => {
|
||||
_$('[data-css-skin-target="file"]').value = '';
|
||||
fcn_toggleInProgress(trigger);
|
||||
});
|
||||
}
|
||||
|
||||
_$('[data-action="click->css-skin#download"]')?.addEventListener('click', event => {
|
||||
fcn_downloadSkins(event.currentTarget);
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user