2017-11-27 06:56:22 +00:00
|
|
|
/* global messageBox makeLink */
|
2017-09-05 20:26:01 +00:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
function configDialog(style) {
|
2017-11-27 11:51:51 +00:00
|
|
|
const varsHash = deepCopy(style.usercssData.vars) || {};
|
|
|
|
const varNames = Object.keys(varsHash);
|
|
|
|
const vars = varNames.map(name => varsHash[name]);
|
|
|
|
const elements = [];
|
2017-11-27 06:56:22 +00:00
|
|
|
const colorpicker = window.colorpicker();
|
2017-09-05 20:26:01 +00:00
|
|
|
|
2017-11-27 11:51:51 +00:00
|
|
|
buildConfigForm();
|
|
|
|
renderValues();
|
|
|
|
|
2017-09-05 20:26:01 +00:00
|
|
|
return messageBox({
|
2017-10-14 19:03:01 +00:00
|
|
|
title: `${style.name} v${style.usercssData.version}`,
|
2017-09-05 20:26:01 +00:00
|
|
|
className: 'config-dialog',
|
2017-10-14 19:03:01 +00:00
|
|
|
contents: [
|
|
|
|
$element({
|
|
|
|
className: 'config-heading',
|
|
|
|
appendChild: style.usercssData.supportURL && makeLink({
|
|
|
|
className: 'external-support',
|
|
|
|
href: style.usercssData.supportURL,
|
|
|
|
textContent: t('externalFeedback')
|
|
|
|
})
|
|
|
|
}),
|
|
|
|
$element({
|
|
|
|
className: 'config-body',
|
2017-11-27 11:51:51 +00:00
|
|
|
appendChild: elements
|
2017-10-14 19:03:01 +00:00
|
|
|
})
|
|
|
|
],
|
2017-09-05 20:26:01 +00:00
|
|
|
buttons: [
|
|
|
|
t('confirmSave'),
|
|
|
|
{
|
|
|
|
textContent: t('confirmDefault'),
|
2017-11-27 11:51:51 +00:00
|
|
|
onclick: useDefault
|
2017-09-05 20:26:01 +00:00
|
|
|
},
|
|
|
|
t('confirmCancel')
|
|
|
|
]
|
2017-11-27 11:51:51 +00:00
|
|
|
}).then(({button, esc}) => {
|
2017-11-27 05:16:42 +00:00
|
|
|
if (button !== 1) {
|
|
|
|
colorpicker.hide();
|
|
|
|
}
|
2017-11-27 11:51:51 +00:00
|
|
|
if (button > 0 || esc || !vars.length || !vars.some(va => va.dirty)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
style.reason = 'config';
|
|
|
|
const styleVars = style.usercssData.vars;
|
|
|
|
const bgStyle = BG.cachedStyles.byId.get(style.id);
|
|
|
|
const bgVars = bgStyle && (bgStyle.usercssData || {}).vars || {};
|
|
|
|
const invalid = [];
|
|
|
|
let numValid = 0;
|
|
|
|
for (const va of vars) {
|
|
|
|
const bgva = bgVars[va.name];
|
|
|
|
let error;
|
|
|
|
if (!bgva) {
|
2017-11-27 12:57:32 +00:00
|
|
|
error = 'deleted';
|
|
|
|
delete styleVars[va.name];
|
2017-11-27 11:51:51 +00:00
|
|
|
} else
|
|
|
|
if (bgva.type !== va.type) {
|
2017-11-27 12:57:32 +00:00
|
|
|
error = ['type ', '*' + va.type, ' != ', '*' + bgva.type];
|
2017-11-27 11:51:51 +00:00
|
|
|
} else
|
|
|
|
if ((va.type === 'select' || va.type === 'dropdown') &&
|
2017-11-27 12:22:49 +00:00
|
|
|
va.value !== null && va.value !== undefined &&
|
2017-11-27 11:51:51 +00:00
|
|
|
bgva.options.every(o => o.name !== va.value)) {
|
2017-11-27 12:57:32 +00:00
|
|
|
error = `'${va.value}' not in the updated '${va.type}' list`;
|
2017-11-27 11:51:51 +00:00
|
|
|
} else if (!va.dirty) {
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
styleVars[va.name].value = va.value;
|
|
|
|
numValid++;
|
|
|
|
continue;
|
|
|
|
}
|
2017-11-27 12:57:32 +00:00
|
|
|
invalid.push(['*' + va.name, ': ', ...error].map(e =>
|
|
|
|
e[0] === '*' && $element({tag: 'b', textContent: e.slice(1)}) || e));
|
|
|
|
if (bgva) {
|
|
|
|
styleVars[va.name].value = deepCopy(bgva);
|
|
|
|
}
|
2017-11-27 11:51:51 +00:00
|
|
|
}
|
|
|
|
if (invalid.length) {
|
|
|
|
messageBox.alert([
|
|
|
|
$element({textContent: t('usercssConfigIncomplete'), style: 'max-width: 34em'}),
|
|
|
|
$element({
|
|
|
|
tag: 'ol',
|
2017-11-27 12:57:32 +00:00
|
|
|
style: 'text-align: left',
|
|
|
|
appendChild: invalid.map(msg => $element({tag: 'li', appendChild: msg})),
|
2017-11-27 11:51:51 +00:00
|
|
|
}),
|
|
|
|
]);
|
2017-09-05 20:26:01 +00:00
|
|
|
}
|
2017-11-27 11:51:51 +00:00
|
|
|
return numValid && BG.usercssHelper.save(style);
|
2017-09-05 20:26:01 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
function buildConfigForm() {
|
2017-11-27 11:51:51 +00:00
|
|
|
for (const va of vars) {
|
2017-09-05 20:26:01 +00:00
|
|
|
let appendChild;
|
2017-11-09 01:00:46 +00:00
|
|
|
switch (va.type) {
|
|
|
|
case 'color':
|
2017-11-27 06:56:22 +00:00
|
|
|
appendChild = [$element({
|
|
|
|
className: 'cm-colorview',
|
|
|
|
appendChild: va.inputColor = $element({
|
|
|
|
va,
|
|
|
|
className: 'color-swatch',
|
2017-11-27 11:51:51 +00:00
|
|
|
onclick: showColorpicker,
|
2017-11-27 06:56:22 +00:00
|
|
|
})
|
|
|
|
})];
|
2017-11-09 01:00:46 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'checkbox':
|
|
|
|
va.input = $element({tag: 'input', type: 'checkbox'});
|
|
|
|
va.input.onchange = () => {
|
|
|
|
va.dirty = true;
|
|
|
|
va.value = String(Number(va.input.checked));
|
|
|
|
};
|
|
|
|
appendChild = [
|
|
|
|
$element({tag: 'span', className: 'onoffswitch', appendChild: [
|
|
|
|
va.input,
|
|
|
|
$element({tag: 'span'})
|
|
|
|
]})
|
|
|
|
];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'select':
|
|
|
|
case 'dropdown':
|
|
|
|
case 'image':
|
|
|
|
// TODO: a image picker input?
|
|
|
|
va.input = $element({
|
|
|
|
tag: 'select',
|
|
|
|
appendChild: va.options.map(o => $element({
|
|
|
|
tag: 'option', value: o.name, textContent: o.label
|
|
|
|
}))
|
|
|
|
});
|
|
|
|
va.input.onchange = () => {
|
|
|
|
va.dirty = true;
|
|
|
|
va.value = va.input.value;
|
|
|
|
};
|
|
|
|
appendChild = [va.input];
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
va.input = $element({tag: 'input', type: 'text'});
|
|
|
|
va.input.oninput = () => {
|
|
|
|
va.dirty = true;
|
|
|
|
va.value = va.input.value;
|
|
|
|
};
|
|
|
|
appendChild = [va.input];
|
|
|
|
break;
|
2017-09-05 20:26:01 +00:00
|
|
|
}
|
2017-11-27 11:51:51 +00:00
|
|
|
elements.push($element({
|
2017-09-05 20:26:01 +00:00
|
|
|
tag: 'label',
|
|
|
|
className: `config-${va.type}`,
|
2017-11-27 11:51:51 +00:00
|
|
|
appendChild: [
|
|
|
|
$element({tag: 'span', appendChild: va.label}),
|
|
|
|
...appendChild,
|
|
|
|
],
|
2017-09-05 20:26:01 +00:00
|
|
|
}));
|
|
|
|
}
|
2017-11-27 11:51:51 +00:00
|
|
|
}
|
2017-09-05 20:26:01 +00:00
|
|
|
|
2017-11-27 11:51:51 +00:00
|
|
|
function renderValues() {
|
|
|
|
for (const va of vars) {
|
|
|
|
const useDefault = va.value === null || va.value === undefined;
|
|
|
|
const value = useDefault ? va.default : va.value;
|
|
|
|
if (va.type === 'color') {
|
|
|
|
va.inputColor.style.backgroundColor = value;
|
|
|
|
if (colorpicker.options.va === va) {
|
|
|
|
colorpicker.setColor(value);
|
2017-09-05 20:26:01 +00:00
|
|
|
}
|
2017-11-27 11:51:51 +00:00
|
|
|
} else if (va.type === 'checkbox') {
|
|
|
|
va.input.checked = Number(value);
|
|
|
|
} else {
|
|
|
|
va.input.value = value;
|
2017-09-05 20:26:01 +00:00
|
|
|
}
|
|
|
|
}
|
2017-11-27 11:51:51 +00:00
|
|
|
}
|
2017-09-05 20:26:01 +00:00
|
|
|
|
2017-11-27 11:51:51 +00:00
|
|
|
function useDefault() {
|
|
|
|
for (const va of vars) {
|
|
|
|
const hasValue = va.value !== null && va.value !== undefined;
|
|
|
|
va.dirty = hasValue && va.value !== va.default;
|
|
|
|
va.value = null;
|
2017-09-05 20:26:01 +00:00
|
|
|
}
|
2017-11-27 11:51:51 +00:00
|
|
|
renderValues();
|
|
|
|
}
|
2017-09-05 20:26:01 +00:00
|
|
|
|
2017-11-27 11:51:51 +00:00
|
|
|
function showColorpicker() {
|
|
|
|
window.removeEventListener('keydown', messageBox.listeners.key, true);
|
|
|
|
const box = $('#message-box-contents');
|
|
|
|
colorpicker.show({
|
|
|
|
va: this.va,
|
|
|
|
color: this.va.value || this.va.default,
|
|
|
|
top: this.getBoundingClientRect().bottom - 5,
|
|
|
|
left: box.getBoundingClientRect().left - 360,
|
|
|
|
hideDelay: 1e6,
|
|
|
|
guessBrightness: box,
|
|
|
|
callback: onColorChanged,
|
|
|
|
});
|
|
|
|
}
|
2017-09-05 20:26:01 +00:00
|
|
|
|
2017-11-27 11:51:51 +00:00
|
|
|
function onColorChanged(newColor) {
|
|
|
|
if (newColor) {
|
|
|
|
this.va.dirty = true;
|
|
|
|
this.va.value = newColor;
|
|
|
|
this.va.inputColor.style.backgroundColor = newColor;
|
2017-11-27 06:56:22 +00:00
|
|
|
}
|
2017-11-27 11:51:51 +00:00
|
|
|
debounce(restoreEscInDialog);
|
|
|
|
}
|
2017-11-27 06:56:22 +00:00
|
|
|
|
2017-11-27 11:51:51 +00:00
|
|
|
function restoreEscInDialog() {
|
|
|
|
if (!$('.colorpicker-popup') && messageBox.element) {
|
|
|
|
window.addEventListener('keydown', messageBox.listeners.key, true);
|
|
|
|
}
|
2017-09-05 20:26:01 +00:00
|
|
|
}
|
|
|
|
}
|