// ==UserScript==
// @name Camamba Chat Tweaks
// @namespace dannysaurus.camamba
// @version 0.1
// @description tweaks layout of the chat
// @license MIT License
// @include https://www.camamba.com/chat/
// @include https://www.de.camamba.com/chat/
// @grant GM.getValue
// @grant GM.setValue
// ==/UserScript==
/* jslint esnext: true */
(function() {
'use strict';
// --- initial sizes ---
const SIZES = {
FONT_EM: {
userList: 1.2,
chatBox: 1.8,
},
WIDTH_EM: {
sidebarLeft: 10,
sidebarRight: 14,
},
};
// --- HTML Selector Helpers ---
const containers = (() => {
const SELECTORS = {
ID: {
userList: 'userList',
chatBox: 'chatBox',
chatWindow: 'chatWindow',
mediaContainer1 : 'mediaContainer1',
mediaContainer2 : 'mediaContainer2',
mediaContainer3 : 'mediaContainer3',
mediaContainer4 : 'mediaContainer4',
mediaContainer5 : 'mediaContainer5',
mediaContainer6 : 'mediaContainer6',
mediaContainer7 : 'mediaContainer7',
mediaContainer8 : 'mediaContainer8',
},
CLASS: {
noTextSelect: 'noTextSelect',
borderBox: 'borderBox',
camBox: 'camBox'
}
};
let userList, chatBox, sidebars, camslots;
return {
get userList() {
if (typeof userList === "undefined") {
userList = document.getElementById(SELECTORS.ID.userList);
}
return userList;
},
get chatBox() {
if (typeof chatBox === "undefined") {
chatBox = document.getElementById(SELECTORS.ID.chatBox);
}
return chatBox;
},
get sidebars() {
if (typeof sidebars === "undefined") {
sidebars = document.getElementById(SELECTORS.ID.chatWindow).querySelectorAll(`.${SELECTORS.CLASS.noTextSelect}`);
}
return sidebars;
},
get sidebarLeft() {
return this.sidebars[0];
},
get sidebarTop() {
return this.sidebars[1];
},
get sidebarRight() {
return this.sidebars[2];
},
get camslots() {
if (typeof camslots === "undefined") {
const parentContainers = [
SELECTORS.ID.mediaContainer1,
SELECTORS.ID.mediaContainer2,
SELECTORS.ID.mediaContainer3,
SELECTORS.ID.mediaContainer4,
SELECTORS.ID.mediaContainer5,
SELECTORS.ID.mediaContainer6,
SELECTORS.ID.mediaContainer7,
SELECTORS.ID.mediaContainer8,
]
.map(id => document.getElementById(id))
.filter(el => el !== null)
.map(el => el.parentNode);
camslots = [ ...new Set(parentContainers)];
}
return camslots;
}
};
})();
// --- HTML Create Element Helpers ---
const addNewInput = ({ parentElement, type, id, initialValue, labelText }) => {
const div = parentElement.appendChild(document.createElement('div'));
const input = document.createElement('input');
input.type = type;
input.id = id;
input.style.backgroundColor = 'rgba(39,62,77,1)';
const label = document.createElement('label');
label.htmlFor = id;
label.appendChild(document.createTextNode(labelText));
div.appendChild(input);
div.appendChild(label);
return input;
};
const addNewInputPersistent = ({ parentElement, type, id, initialValue, labelText }) => {
const input = addNewInput({ parentElement, type, id, initialValue, labelText });
input.updateValue = () => GM.getValue(input.id, initialValue).then(value => {
input.value = value;
});
input.addEventListener('input', () => {
GM.setValue(input.id, input.value);
});
return input;
};
const addNewCheckbox = ({ parentElement, id, initialChecked, labelText }) => {
const checkbox = addNewInput({ parentElement, type:'checkbox', id, initialValue: '', labelText });
checkbox.updateValue = () => GM.getValue(checkbox.id, !!initialChecked).then(isChecked => {
checkbox.checked = !!isChecked;
});
checkbox.addEventListener('click', () => {
GM.setValue(checkbox.id, checkbox.checked);
});
return checkbox;
};
const addNewSpinner = ({ parentElement, id, initialValue, min, max, step, labelText }) => {
const spinner = addNewInputPersistent({ parentElement, type:'number', id, initialValue, labelText });
spinner.min = min;
spinner.max = max;
spinner.step = step;
return spinner;
};
// --- Main ---
const layoutPatcher = new class {
constructor() {
this.historyCamslotsRemoved = [];
}
initControls() {
const sidebarLeftCenter = containers.sidebarLeft.children[1];
sidebarLeftCenter.innerHTML = "";
const container = sidebarLeftCenter.appendChild(document.createElement('div'));
// checkbox camslots on/off
const cbCamslots = addNewCheckbox({
parentElement: container,
id: 'cb-camslots',
initialChecked: true,
labelText: 'camslots'
});
const updateCbCamslots = () => {
if (cbCamslots.checked) {
this.showCamslots();
} else {
this.hideCamslots();
}
};
cbCamslots.addEventListener('click', () => updateCbCamslots());
cbCamslots.updateValue().then(() => updateCbCamslots());
// spinner userlist font
const spinnerUserlistFont = addNewSpinner({
parentElement: container,
id: 'spinner-userlist-font',
initialValue: SIZES.FONT_EM.userList,
min: 1.0,
max: 2.2,
step: 0.1,
labelText: 'users'
});
const updateSpinnerUserlistFont = () => {
const fontSize = `${spinnerUserlistFont.value}em`;
this.setFontSizeOfUserList(fontSize);
};
spinnerUserlistFont.addEventListener('input', () => updateSpinnerUserlistFont());
spinnerUserlistFont.updateValue().then(() => updateSpinnerUserlistFont());
// spinner chat font
const spinnerChatFont = addNewSpinner({
parentElement: container,
id: 'spinner-chat-font',
initialValue: SIZES.FONT_EM.chatBox,
min: 1.0,
max: 2.2,
step: 0.1,
labelText: 'chat'
});
const updateSpinnerChatFont = () => {
const fontSize = `${spinnerChatFont.value}em`;
this.setFontSizeOfChat(fontSize);
};
spinnerChatFont.addEventListener('input', () => updateSpinnerChatFont());
spinnerChatFont.updateValue().then(() => updateSpinnerChatFont());
}
patchSizes() {
// this.setWidthOfSidebarLeft(`${SIZES.WIDTH_EM.sidebarLeft}em`);
this.setWidthOfSidebarRight(`${SIZES.WIDTH_EM.sidebarRight}em`);
return this;
}
setFontSizeOfUserList(fontSize) {
containers.userList.style.fontSize = fontSize;
return this;
}
setFontSizeOfChat(fontSize) {
containers.chatBox.style.fontSize = fontSize;
return this;
}
setWidthOfSidebarLeft(width) {
containers.sidebarLeft.style.width = width;
return this;
}
setWidthOfSidebarRight(width) {
containers.sidebarLeft.style.width = width;
return this;
}
showCamslots() {
for (let i = 0; i < this.historyCamslotsRemoved.length; i++) {
const { parent, index, element } = this.historyCamslotsRemoved.pop();
parent.insertBefore(element, parent.children[index]);
}
return this;
}
hideCamslots() {
for (let element of containers.camslots) {
const parent = element.parentNode;
if (parent) {
let index = Array.from(parent.children).indexOf(element);
parent.removeChild(element);
this.historyCamslotsRemoved.push({ parent, index, element });
}
}
return this;
}
}();
const hookIntoInitSettings = (onInitSettings, timeOutRetryMillis) => {
if (typeof initSettings === "undefined") {
setTimeout(() => {
hookIntoInitSettings();
}, timeOutRetryMillis);
}
/* eslint-disable no-undef */
const originalInitSettings = initSettings;
initSettings = () => {
/* eslint-enable no-undef */
originalInitSettings();
onInitSettings();
};
};
hookIntoInitSettings(() => {
layoutPatcher.patchSizes();
}, 350);
layoutPatcher.patchSizes();
layoutPatcher.initControls();
})();