// ==UserScript==
// @name Freedcamp custom image background
// @namespace http://freedcamp.com/
// @version 1.08
// @description set project background image
// @author devops@freedcamp.com
// @match *://freedcamp.com/*
// @match *://*.freedcamp.com/*
// @require https://raw.github.com/odyniec/MonkeyConfig/master/monkeyconfig.js
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addStyle
// @grant GM_registerMenuCommand
// ==/UserScript==
(function () {
"use strict";
let cbKeys = {};
let imageSelectConfig = createMonkeyConfig();
let lastPath, lastProjectId, lastAppName;
run();
window.addEventListener("FC_ROUTE_CHANGED", function () {
const paths = window.location.pathname.split("/");
const isChanged =
lastPath === "dashboard"
? paths[2] !== lastAppName
: lastPath === "view"
? paths[2] !== lastProjectId || paths[3] !== lastAppName
: false;
if (isChanged) {
setTimeout(() => run(), 0);
}
});
function run() {
const isNewUI = checkIsNewUI();
const projectHeader = isNewUI
? document.querySelector(".Header--fk-Header-ProjectName")
: document.querySelector("#project_name");
const projectId = getProjectId(isNewUI);
if (projectId) {
setProject(projectId, isNewUI);
} else {
switchDashboardPages();
}
}
function createMonkeyConfig() {
return new MonkeyConfig({
title: "Config",
menuCommand: true,
params: {
custom_project_background: {
type: "custom",
html: "
",
set: function (value, parent) {
cbKeys = Object.keys(value).length !== 0 ? value : cbKeys;
const isNewUI = checkIsNewUI();
const projectId = getProjectId(isNewUI);
const container = parent.querySelector("#monkey_container");
if (projectId) {
container.innerHTML =
"" +
"" +
"" +
"" +
"" +
"" +
"Restore background(s) from previous version";
container.removeAttribute("style");
let oldConfig = "";
for (let key in cbKeys) {
if (isNaN(key)) {
const val = cbKeys[key];
if ("url" in val && val.url) {
oldConfig += `${key}`;
}
}
}
const link = parent.querySelector("#download_old_config");
if (!isNewUI) {
if (project_unique_name in cbKeys) {
parent
.querySelector("#delete_background")
.removeAttribute("hidden");
}
}
const openText = () => {
const newWindow = window.open();
newWindow.document.write(
"IMAGES FROM PREVIOUS VERSION" + oldConfig
);
};
if (oldConfig) {
link.addEventListener("click", function () {
if (!isNewUI) {
if (project_unique_name in cbKeys) {
const oldProject = cbKeys[project_unique_name];
input[0].value = oldProject.url;
input[1].checked = oldProject.enabled || false;
input[2].checked = oldProject.font_inverted || false;
} else {
openText();
}
} else {
openText();
}
});
link.removeAttribute("hidden");
}
const input = parent.querySelectorAll("input");
if (Object.keys(value).length === 0) {
// "Set defaults"
input[0].value = "";
input[1].checked = false;
input[2].checked = false;
} else if (projectId in value) {
input[0].value = value[projectId].url || "";
input[1].checked = value[projectId].enabled || false;
input[2].checked = value[projectId].font_inverted || false;
}
} else {
try {
const grandParent = parent.parentNode;
const grandGrandParent = grandParent.parentNode;
grandParent.parentNode.removeChild(grandParent);
grandGrandParent.insertAdjacentHTML(
"afterbegin",
"" +
"Open a project page to select a custom background. |
"
);
} catch (e) {
}
}
},
get: function (parent) {
const projectId = getProjectId();
if (projectId) {
const input = parent.querySelectorAll("input");
if (input[3].checked) {
delete cbKeys[project_unique_name];
}
cbKeys[projectId] = {
url: input[0].value,
enabled: input[1].checked,
font_inverted: input[2].checked
};
}
return cbKeys;
},
default: {}
},
default_project_background: {
type: "custom",
html:
"" +
"" +
"" +
"" +
"",
set: function (value, parent) {
const elements = parent.querySelectorAll("input");
elements[0].value = value.url;
elements[1].checked = value.enabled;
elements[2].checked = value.font_inverted;
},
get: function (parent) {
const elements = parent.querySelectorAll("input");
const url = elements[0].value;
const enabled = elements[1].checked;
const fontInverted = elements[2].checked;
return {url: url, enabled: enabled, font_inverted: fontInverted};
},
default: {url: "", enabled: false, font_inverted: false}
},
display_backgrounds_on_project_cards: {
type: "checkbox",
default: false
},
dashboards_background: {
type: "custom",
html:
"" +
"" +
"" +
"" +
"",
set: function (value, parent) {
const elements = parent.querySelectorAll("input");
elements[0].value = value.url;
elements[1].checked = value.enabled;
elements[2].checked = value.font_inverted;
},
get: function (parent) {
const elements = parent.querySelectorAll("input");
const url = elements[0].value;
const enabled = elements[1].checked;
const fontInverted = elements[2].checked;
return {url: url, enabled: enabled, font_inverted: fontInverted};
},
default: {url: "", enabled: false, font_inverted: false}
}
},
onSave: function (values) {
location.reload();
}
});
}
function checkIsNewUI() {
return typeof react_cache_version !== "undefined";
}
function getProjectId(isNewUI = checkIsNewUI()) {
let result = null;
if (isNewUI) {
const paths = window.location.pathname.split("/");
lastPath = paths[1];
if (lastPath === "dashboard") {
lastAppName = paths[2];
} else if (lastPath === "view") {
lastProjectId = paths[2];
lastAppName = paths[3];
result = lastProjectId;
}
} else {
try {
const projectId = fc.project_id.toString();
if (projectId !== "0") {
result = projectId;
}
} catch (e) {
}
}
return result;
}
function viewUrlError(text) {
setTimeout(function () {
alert(
`${text} background image error:\nIncorrect background url! Please change it.`
);
}, 2000);
}
function setProjectBackground(url, fontColor) {
const shadowColor = fontColor === "white" ? "black" : "white";
tryToSetNewButtonsColor(fontColor, shadowColor);
const s = document.body.style;
s.background = `url(${url})`;
s.backgroundSize = "cover";
s.backgroundRepeat = "no-repeat";
s.backgroundPosition = "50% 50%";
s.backgroundAttachment = "fixed";
}
function tryToSetNewButtonsColor(fontColor, shadowColor) {
const buttons = document.querySelectorAll(".Button--fk-Intent-primary");
const shadow = `${fontColor} 0px 1px 8px`;
for (let x = 0; x < buttons.length; x++) {
const button = buttons[x];
const svg = button.querySelector("svg");
const i = button.querySelector("i");
const text = button.querySelector(".Button--fk-Button-Text");
if (svg) {
svg.style.color = fontColor;
}
if (i) {
i.style.color = fontColor;
}
if (text) {
text.style.color = fontColor;
text.style.textShadow = `${shadowColor} 0px 1px 8px`;
}
}
}
function setProjectCardBackground(pBlock, backgroundUrl, fontInverted) {
pBlock.style =
`background:url(${backgroundUrl});` +
"background-size: cover;" +
"background-repeat: no-repeat;" +
"background-position: 50% 50%;" +
"transition-property: none !important;";
const desc = pBlock.querySelector(".project_desc");
const noDesc = pBlock.querySelector(".no_description");
const cogImage = pBlock.querySelector(".cog_image");
const name = pBlock.querySelector(".project_name");
setProjectCardFontColor(name.style, fontInverted, 0, 4);
if (noDesc) {
setProjectCardFontColor(noDesc.style, fontInverted, 1, 2);
} else {
setProjectCardFontColor(desc.style, fontInverted, 1, 2);
}
}
function setProjectCardFontColor(
element,
fontInverted,
marginLeftPx,
shadowPx
) {
element.color = fontInverted ? "black" : "white";
element.marginLeft = `${marginLeftPx}px`;
element.textShadow = `${
fontInverted ? "white" : "black"
} 0px 1px ${shadowPx}px`;
}
function setProject(projectId, isNewUI) {
const cbConfig = imageSelectConfig.get("custom_project_background")[
projectId
];
if (cbConfig && cbConfig.enabled) {
const cbUrl = cbConfig.url;
const cbFontColor = cbConfig.font_inverted ? "black" : "white";
const cbpShadowColor = cbConfig.font_inverted ? "white" : "black";
tryToSetFolderIcon(cbFontColor);
setProjectBackground(cbUrl, cbFontColor);
if (!isNewUI) {
tryToSetSpans(cbFontColor, cbpShadowColor);
}
} else {
const dpbConfig = imageSelectConfig.get("default_project_background");
const dbpEnabled = dpbConfig.enabled;
const dbpFontColor = dpbConfig.font_inverted ? "black" : "white";
const dbpShadowColor = dpbConfig.font_inverted ? "white" : "black";
if (dbpEnabled) {
const dpbUrl = dpbConfig.url;
setProjectBackground(dpbUrl, dbpFontColor);
tryToSetFolderIcon(dbpFontColor);
if (!isNewUI) {
tryToSetSpans(dbpFontColor, dbpShadowColor);
}
}
}
}
function tryToSetFolderIcon(fontColor) {
const folderIcon = document.querySelector('[name="folder-search"]');
if (folderIcon) {
folderIcon.style.color = fontColor;
}
}
function tryToSetSpans(fontColor, shadowColor) {
const spans = document.querySelectorAll("span.sort");
for (let i = 0; i < spans.length; i++) {
let span = spans[i];
span.style.color = fontColor;
span.style.textShadow = `${shadowColor} 0px 1px 8px`;
}
}
function switchDashboardPages() {
let match = window.location.href.match(
/.+\/(dashboard|dashboard\/home|dashboard\/tasks|dashboard\/calendar|dashboard\/widgets|dashboard\/reports)\/?$/
);
if (match) {
const page = match[match.length - 1];
const dbpEnabled = imageSelectConfig.get(
"display_backgrounds_on_project_cards"
);
// switch project cards backgrounds
if (dbpEnabled && page === "dashboard") {
switchDashboardProjectCards();
}
const dbParams = imageSelectConfig.get("dashboards_background");
const dbUrl = dbParams.url;
const dbEnabled = dbParams.enabled;
const dbFontColor = dbParams.font_inverted ? "black" : "white";
const dbShadowColor = dbParams.font_inverted ? "white" : "black";
if (dbEnabled) {
const body = document.body.style;
body.background = `url(${dbUrl})`;
body.backgroundSize = "cover";
body.backgroundRepeat = "no-repeat";
body.backgroundPosition = "50% 50%";
body.backgroundAttachment = "fixed";
switch (page) {
case "dashboard/home":
switchDashboardHome(dbFontColor, dbShadowColor);
break;
case "dashboard":
switchDashboard(dbFontColor, dbShadowColor);
break;
case "dashboard/tasks":
switchDashboardTasks(dbFontColor, dbShadowColor);
break;
case "dashboard/calendar":
switchDashBoardCalendar(dbFontColor, dbShadowColor);
break;
case "dashboard/widgets":
switchDashboardWidgets(dbFontColor);
break;
case "dashboard/reports":
switchDashboardReports(dbFontColor, dbShadowColor);
break;
}
}
}
}
function switchDashboardProjectCards() {
const cpbUrls = imageSelectConfig.get("custom_project_background");
const dpbConfig = imageSelectConfig.get("default_project_background");
let dpbUrlChecked = false;
let dpbUrlVerified = false;
const dpbUrl = dpbConfig.url;
const dpbFontInverted = dpbConfig.font_inverted;
const dpbEnabled = dpbConfig.enabled;
const pBlocks = document.querySelectorAll(".project");
pBlocks.forEach(pBlock => {
const pName = checkIsNewUI()
? pBlock
.querySelector(".Link--link.project_name")
.getAttribute("href")
.split("/")[2]
: pBlock
.querySelector(".favorite_project_action")
.getAttribute("data-id");
if (pName in cpbUrls && cpbUrls[pName].enabled) {
switchDashboardCPBProjectCard(pBlock, pName, cpbUrls);
} else if (dpbEnabled) {
// check default background url only once
if (!dpbUrlChecked) {
dpbUrlChecked = true;
dpbUrlVerified = true;
setProjectCardBackground(pBlock, dpbUrl, dpbFontInverted);
} else if (dpbUrlVerified) {
setProjectCardBackground(pBlock, dpbUrl, dpbFontInverted);
}
}
});
}
function switchDashboardCPBProjectCard(pBlock, pName, cpbUrls) {
const cpbUrl = cpbUrls[pName].url;
const fontInverted = cpbUrls[pName].font_inverted;
setProjectCardBackground(pBlock, cpbUrl, fontInverted);
}
function switchDashboardHome(dbFontColor, dbShadowColor) {
switchDashboardHomeTitles(dbFontColor, dbShadowColor);
switchDashboardHomeHeaders(dbFontColor, dbShadowColor);
switchDashboardHomeDropdownIcon(dbFontColor, dbShadowColor);
}
function switchDashboardHomeTitles(dbFontColor, dbShadowColor) {
const titles = document.querySelectorAll('[class$="-Title"]');
const titleChilds = titles[0].childNodes;
for (let x = 0; x < titleChilds.length; x++) {
try {
const titleChild = titleChilds[x];
titleChild.style.color = dbFontColor;
titleChild.style.textShadow = `${dbShadowColor} 0px 1px 8px`;
} catch (e) {
}
}
for (let i = 0; i < titles.length; i++) {
const title = titles[i];
title.style.color = dbFontColor;
title.style.textShadow = `${dbShadowColor} 0px 1px 8px`;
}
}
function switchDashboardHomeHeaders(dbFontColor, dbShadowColor) {
const headers = document.querySelectorAll(
".HomeBoard--fk-Home-Card-Header"
);
for (let i = 0; i < headers.length; i++) {
const header = headers[i];
const svgs = header.querySelectorAll("svg");
const texts = header.querySelectorAll(".Button--fk-Button-Text");
for (let x = 0; x < svgs.length; x++) {
svgs[x].style.color = dbFontColor;
}
for (let x = 0; x < texts.length; x++) {
texts[x].style.color = dbFontColor;
texts[x].style.textShadow = `${dbShadowColor} 0px 1px 8px`;
}
}
}
function switchDashboardHomeDropdownIcon(dbFontColor, dbShadowColor) {
try {
document
.querySelector("#fk-Home-Projects-Dropdown")
.querySelector("svg").style.color = dbFontColor;
} catch (e) {
}
}
function switchDashboard(dbFontColor, dbShadowColor) {
const subheaders = document.querySelectorAll(".subheader");
subheaders.forEach(subheader => {
const svg = subheader.querySelector("svg");
if (svg) {
svg.style.textShadow = `${dbShadowColor} 0px 1px 14px`;
}
subheader.style.color = dbFontColor;
subheader.style.textShadow = `${dbShadowColor} 0px 1px 14px`;
});
if (checkIsNewUI()) {
const filter = document.querySelector("svg[name=filter]").parentElement
.parentElement.style;
const eye = document.querySelector("svg[name=eye]").style;
filter.color = dbFontColor;
filter.textShadow = `${dbShadowColor} 0px 1px 18px`;
eye.color = dbFontColor;
eye.shadow = `${dbShadowColor} 0px 1px 18px`;
} else {
const greeting = document.querySelector(".greeting.left").style;
greeting.color = dbFontColor;
greeting.textShadow = `${dbShadowColor} 0px 1px 18px`;
}
}
function switchDashboardTasks(dbFontColor, dbShadowColor) {
const header = document.querySelector(".AppHeader--fk-AppHeader.noprint");
if (header) {
const svgs = header.querySelectorAll("svg");
const is = header.querySelectorAll("i");
const texts = header.querySelectorAll(".Button--fk-Button-Text");
for (let x = 0; x < svgs.length; x++) {
svgs[x].style.color = dbFontColor;
}
for (let x = 0; x < is.length; x++) {
is[x].style.color = dbFontColor;
}
for (let x = 0; x < texts.length; x++) {
texts[x].style.color = dbFontColor;
texts[x].style.textShadow = `${dbShadowColor} 0px 1px 8px`;
}
}
}
function switchDashBoardCalendar(dbFontColor, dbShadowColor) {
const filterLabel = document.querySelector(".filter_label").style;
filterLabel.color = dbFontColor;
filterLabel.textShadow = `${dbShadowColor} 0px 1px 8px`;
}
function switchDashboardWidgets(dbFontColor) {
document.querySelector(".no_entries.no_widgets").style.color = dbFontColor;
}
function switchDashboardReports(dbFontColor, dbShadowColor) {
createReportsInterval("#report_text", dbFontColor, dbShadowColor, 18);
createReportsInterval("#report_name_and_date", dbFontColor, dbShadowColor);
createReportsInterval(".fg-slate", dbFontColor, dbShadowColor);
createReportsInterval("#report_created_by", dbFontColor, dbShadowColor);
}
function createReportsInterval(
selector,
dbFontColor,
dbShadowColor,
customRadius = 3
) {
const interval = setInterval(function () {
const el = document.querySelector(selector);
if (el) {
const reportText = el.style;
reportText.color = dbFontColor;
reportText.textShadow = `${dbShadowColor} 0px 1px ${customRadius}px`;
clearInterval(interval);
}
}, 100);
}
})();