fix local name customization for usercss/legacy
This commit is contained in:
parent
34f899fc45
commit
2e1a903cc7
|
@ -250,6 +250,13 @@
|
|||
"message": "Copy to clipboard",
|
||||
"description": "Tooltip for elements which can be copied"
|
||||
},
|
||||
"customNameHint": {
|
||||
"message": "Enter a custom name here to rename the style in UI without breaking its updates"
|
||||
},
|
||||
"customNameResetHint": {
|
||||
"message": "Stop using customized name, switch to the style's own name",
|
||||
"description": "Tooltip of 'x' button shown in editor when changing the name input of a) styles updated from a URL i.e. not locally created, b) UserCSS styles"
|
||||
},
|
||||
"dateInstalled": {
|
||||
"message": "Date installed",
|
||||
"description": "Option text for the user to sort the style by install date"
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
continue;
|
||||
}
|
||||
for (const part in PARTS) {
|
||||
const text = style[part];
|
||||
const text = part === 'name' ? style.customName || style.name : style[part];
|
||||
if (text && PARTS[part](text, rx, words, icase)) {
|
||||
results.push(id);
|
||||
break;
|
||||
|
|
|
@ -61,6 +61,8 @@ const styleManager = (() => {
|
|||
username: ''
|
||||
};
|
||||
|
||||
const DELETE_IF_NULL = ['id', 'customName'];
|
||||
|
||||
handleLivePreviewConnections();
|
||||
|
||||
return Object.assign({
|
||||
|
@ -387,8 +389,10 @@ const styleManager = (() => {
|
|||
if (!style.name) {
|
||||
throw new Error('style name is empty');
|
||||
}
|
||||
if (style.id == null) {
|
||||
delete style.id;
|
||||
for (const key of DELETE_IF_NULL) {
|
||||
if (style[key] == null) {
|
||||
delete style[key];
|
||||
}
|
||||
}
|
||||
if (!style._id) {
|
||||
style._id = uuidv4();
|
||||
|
@ -569,6 +573,16 @@ const styleManager = (() => {
|
|||
touched = true;
|
||||
}
|
||||
}
|
||||
// upgrade the old way of customizing local names
|
||||
const {originalName} = style;
|
||||
if (originalName) {
|
||||
touched = true;
|
||||
if (originalName !== style.name) {
|
||||
style.customName = style.name;
|
||||
style.name = originalName;
|
||||
}
|
||||
delete style.originalName;
|
||||
}
|
||||
return touched;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,7 +116,7 @@
|
|||
}
|
||||
|
||||
function reportSuccess(saved) {
|
||||
log(STATES.UPDATED + ` #${style.id} ${style.name}`);
|
||||
log(STATES.UPDATED + ` #${style.id} ${style.customName || style.name}`);
|
||||
const info = {updated: true, style: saved};
|
||||
if (port) port.postMessage(info);
|
||||
return info;
|
||||
|
@ -139,7 +139,7 @@
|
|||
if (typeof error === 'object' && error.message) {
|
||||
error = error.message;
|
||||
}
|
||||
log(STATES.SKIPPED + ` (${error}) #${style.id} ${style.name}`);
|
||||
log(STATES.SKIPPED + ` (${error}) #${style.id} ${style.customName || style.name}`);
|
||||
const info = {error, STATES, style: getStyleWithNoCode(style)};
|
||||
if (port) port.postMessage(info);
|
||||
return info;
|
||||
|
@ -207,13 +207,6 @@
|
|||
// keep current state
|
||||
delete json.enabled;
|
||||
|
||||
// keep local name customizations
|
||||
if (style.originalName !== style.name && style.name !== json.name) {
|
||||
delete json.name;
|
||||
} else {
|
||||
json.originalName = json.name;
|
||||
}
|
||||
|
||||
const newStyle = Object.assign({}, style, json);
|
||||
if (styleSectionsEqual(json, style, {checkSource: true})) {
|
||||
// update digest even if save === false as there might be just a space added etc.
|
||||
|
|
|
@ -284,7 +284,13 @@
|
|||
<h1 id="heading"> </h1> <!-- nbsp allocates the actual height which prevents page shift -->
|
||||
<section id="basic-info">
|
||||
<div id="basic-info-name">
|
||||
<input id="name" class="style-contributor" spellcheck="false" required>
|
||||
<input id="name" class="style-contributor" spellcheck="false">
|
||||
<a id="reset-name" href="#" i18n-title="customNameResetHint" tabindex="0" hidden>
|
||||
<svg class="svg-icon" viewBox="0 0 20 20">
|
||||
<polygon points="16.2,5.5 14.5,3.8 10,8.3 5.5,3.8 3.8,5.5 8.3,10 3.8,14.5
|
||||
5.5,16.2 10,11.7 14.5,16.2 16.2,14.5 11.7,10 "/>
|
||||
</svg>
|
||||
</a>
|
||||
<a id="url" target="_blank"><svg class="svg-icon"><use xlink:href="#svg-icon-external-link"/></svg></a>
|
||||
</div>
|
||||
<div id="basic-info-enabled">
|
||||
|
|
|
@ -315,7 +315,7 @@ CodeMirror.hint && (() => {
|
|||
}
|
||||
|
||||
// USO vars in usercss mode editor
|
||||
const vars = editor.getStyle().usercssData.vars;
|
||||
const vars = editor.style.usercssData.vars;
|
||||
const list = vars ?
|
||||
Object.keys(vars).filter(name => name.startsWith(leftPart)) : [];
|
||||
return {
|
||||
|
@ -343,7 +343,7 @@ CodeMirror.hint && (() => {
|
|||
string[start + 3] === '[' &&
|
||||
string[pos - 3] === ']' &&
|
||||
string[pos - 4] === ']') {
|
||||
const vars = typeof editor !== 'undefined' && (editor.getStyle().usercssData || {}).vars;
|
||||
const vars = typeof editor !== 'undefined' && (editor.style.usercssData || {}).vars;
|
||||
const name = vars && string.slice(start + 4, pos - 4);
|
||||
if (vars && Object.hasOwnProperty.call(vars, name.endsWith('-rgb') ? name.slice(0, -4) : name)) {
|
||||
token[0] = USO_VALID_VAR;
|
||||
|
|
|
@ -88,6 +88,9 @@ label {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
#reset-name {
|
||||
margin: 0 .25em 0 .5em;
|
||||
}
|
||||
#url {
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
@ -813,11 +816,6 @@ body.linter-disabled .hidden-unless-compact {
|
|||
margin-top: .75rem;
|
||||
}
|
||||
|
||||
.usercss #name {
|
||||
background-color: #eee;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.single-editor {
|
||||
height: 100%;
|
||||
}
|
||||
|
|
208
edit/edit.js
208
edit/edit.js
|
@ -1,7 +1,7 @@
|
|||
/* global CodeMirror onDOMready prefs setupLivePrefs $ $$ $create t tHTML
|
||||
createSourceEditor sessionStorageHash getOwnTab FIREFOX API tryCatch
|
||||
closeCurrentTab messageBox debounce workerUtil
|
||||
initBeautifyButton ignoreChromeError
|
||||
initBeautifyButton ignoreChromeError dirtyReporter
|
||||
moveFocus msg createSectionsEditor rerouteHotkeys CODEMIRROR_THEMES */
|
||||
/* exported showCodeMirrorPopup editorWorker toggleContextMenuDelete */
|
||||
'use strict';
|
||||
|
@ -30,46 +30,72 @@ msg.onExtension(onRuntimeMessage);
|
|||
|
||||
preinit();
|
||||
|
||||
(() => {
|
||||
onDOMready().then(() => {
|
||||
prefs.subscribe(['editor.keyMap'], showHotkeyInTooltip);
|
||||
addEventListener('showHotkeyInTooltip', showHotkeyInTooltip);
|
||||
showHotkeyInTooltip();
|
||||
(async function init() {
|
||||
const [style] = await Promise.all([
|
||||
initStyleData(),
|
||||
onDOMready(),
|
||||
prefs.initializing,
|
||||
]);
|
||||
const usercss = isUsercss(style);
|
||||
const dirty = dirtyReporter();
|
||||
let wasDirty = false;
|
||||
let nameTarget;
|
||||
|
||||
buildThemeElement();
|
||||
buildKeymapElement();
|
||||
prefs.subscribe(['editor.keyMap'], showHotkeyInTooltip);
|
||||
addEventListener('showHotkeyInTooltip', showHotkeyInTooltip);
|
||||
showHotkeyInTooltip();
|
||||
|
||||
setupLivePrefs();
|
||||
buildThemeElement();
|
||||
buildKeymapElement();
|
||||
setupLivePrefs();
|
||||
initNameArea(style, usercss);
|
||||
initBeautifyButton($('#beautify'), () => editor.getEditors());
|
||||
initResizeListener();
|
||||
detectLayout();
|
||||
updateTitle();
|
||||
|
||||
$('#heading').textContent = t(style.id ? 'editStyleHeading' : 'addStyleTitle');
|
||||
$('#preview-label').classList.toggle('hidden', !style.id);
|
||||
|
||||
editor = (usercss ? createSourceEditor : createSectionsEditor)({
|
||||
style,
|
||||
dirty,
|
||||
updateName,
|
||||
toggleStyle,
|
||||
});
|
||||
dirty.onChange(updateDirty);
|
||||
await editor.ready;
|
||||
|
||||
initEditor();
|
||||
// enabling after init to prevent flash of validation failure on an empty name
|
||||
$('#name').required = !usercss;
|
||||
$('#save-button').onclick = editor.save;
|
||||
|
||||
function getCodeMirrorThemes() {
|
||||
if (!chrome.runtime.getPackageDirectoryEntry) {
|
||||
const themes = [
|
||||
chrome.i18n.getMessage('defaultTheme'),
|
||||
...CODEMIRROR_THEMES
|
||||
];
|
||||
localStorage.codeMirrorThemes = themes.join(' ');
|
||||
return Promise.resolve(themes);
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
chrome.runtime.getPackageDirectoryEntry(rootDir => {
|
||||
rootDir.getDirectory('vendor/codemirror/theme', {create: false}, themeDir => {
|
||||
themeDir.createReader().readEntries(entries => {
|
||||
const themes = [
|
||||
chrome.i18n.getMessage('defaultTheme')
|
||||
].concat(
|
||||
entries.filter(entry => entry.isFile)
|
||||
.sort((a, b) => (a.name < b.name ? -1 : 1))
|
||||
.map(entry => entry.name.replace(/\.css$/, ''))
|
||||
);
|
||||
localStorage.codeMirrorThemes = themes.join(' ');
|
||||
resolve(themes);
|
||||
});
|
||||
});
|
||||
});
|
||||
function initNameArea(style, usercss) {
|
||||
const nameEl = $('#name');
|
||||
const resetEl = $('#reset-name');
|
||||
const isCustomName = style.updateUrl || usercss;
|
||||
nameTarget = isCustomName ? 'customName' : 'name';
|
||||
nameEl.placeholder = t(usercss ? 'usercssEditorNamePlaceholder' : 'styleMissingName');
|
||||
nameEl.title = isCustomName ? t('customNameHint') : '';
|
||||
nameEl.addEventListener('input', () => {
|
||||
updateName();
|
||||
resetEl.hidden = false;
|
||||
});
|
||||
resetEl.hidden = !style.customName;
|
||||
resetEl.onclick = () => {
|
||||
const style = editor.style;
|
||||
nameEl.focus();
|
||||
nameEl.select();
|
||||
// trying to make it undoable via Ctrl-Z
|
||||
if (!document.execCommand('insertText', false, style.name)) {
|
||||
nameEl.value = style.name;
|
||||
updateName();
|
||||
}
|
||||
style.customName = null; // to delete it from db
|
||||
resetEl.hidden = true;
|
||||
};
|
||||
const enabledEl = $('#enabled');
|
||||
enabledEl.onchange = () => updateEnabledness(enabledEl.checked);
|
||||
}
|
||||
|
||||
function findKeyForCommand(command, map) {
|
||||
|
@ -88,27 +114,8 @@ preinit();
|
|||
}
|
||||
|
||||
function buildThemeElement() {
|
||||
const themeElement = $('#editor.theme');
|
||||
const themeList = localStorage.codeMirrorThemes;
|
||||
|
||||
const optionsFromArray = options => {
|
||||
const fragment = document.createDocumentFragment();
|
||||
options.forEach(opt => fragment.appendChild($create('option', opt)));
|
||||
themeElement.appendChild(fragment);
|
||||
};
|
||||
|
||||
if (themeList) {
|
||||
optionsFromArray(themeList.split(/\s+/));
|
||||
} else {
|
||||
// Chrome is starting up and shows our edit.html, but the background page isn't loaded yet
|
||||
const theme = prefs.get('editor.theme');
|
||||
optionsFromArray([theme === 'default' ? t('defaultTheme') : theme]);
|
||||
getCodeMirrorThemes().then(() => {
|
||||
const themes = (localStorage.codeMirrorThemes || '').split(/\s+/);
|
||||
optionsFromArray(themes);
|
||||
themeElement.selectedIndex = Math.max(0, themes.indexOf(theme));
|
||||
});
|
||||
}
|
||||
CODEMIRROR_THEMES.unshift(chrome.i18n.getMessage('defaultTheme'));
|
||||
$('#editor.theme').append(...CODEMIRROR_THEMES.map(s => $create('option', s)));
|
||||
}
|
||||
|
||||
function buildKeymapElement() {
|
||||
|
@ -159,59 +166,56 @@ preinit();
|
|||
}
|
||||
}
|
||||
|
||||
function initEditor() {
|
||||
return Promise.all([
|
||||
initStyleData(),
|
||||
onDOMready(),
|
||||
prefs.initializing,
|
||||
])
|
||||
.then(([style]) => {
|
||||
const usercss = isUsercss(style);
|
||||
$('#heading').textContent = t(style.id ? 'editStyleHeading' : 'addStyleTitle');
|
||||
$('#name').placeholder = t(usercss ? 'usercssEditorNamePlaceholder' : 'styleMissingName');
|
||||
$('#name').title = usercss ? t('usercssReplaceTemplateName') : '';
|
||||
$('#preview-label').classList.toggle('hidden', !style.id);
|
||||
initBeautifyButton($('#beautify'), () => editor.getEditors());
|
||||
const {onBoundsChanged} = chrome.windows || {};
|
||||
if (onBoundsChanged) {
|
||||
// * movement is reported even if the window wasn't resized
|
||||
// * fired just once when done so debounce is not needed
|
||||
onBoundsChanged.addListener(wnd => {
|
||||
// getting the current window id as it may change if the user attached/detached the tab
|
||||
chrome.windows.getCurrent(ownWnd => {
|
||||
if (wnd.id === ownWnd.id) rememberWindowSize();
|
||||
});
|
||||
});
|
||||
}
|
||||
window.addEventListener('resize', () => {
|
||||
if (!onBoundsChanged) debounce(rememberWindowSize, 100);
|
||||
detectLayout();
|
||||
function initResizeListener() {
|
||||
const {onBoundsChanged} = chrome.windows || {};
|
||||
if (onBoundsChanged) {
|
||||
// * movement is reported even if the window wasn't resized
|
||||
// * fired just once when done so debounce is not needed
|
||||
onBoundsChanged.addListener(wnd => {
|
||||
// getting the current window id as it may change if the user attached/detached the tab
|
||||
chrome.windows.getCurrent(ownWnd => {
|
||||
if (wnd.id === ownWnd.id) rememberWindowSize();
|
||||
});
|
||||
detectLayout();
|
||||
editor = (usercss ? createSourceEditor : createSectionsEditor)({
|
||||
style,
|
||||
onTitleChanged: updateTitle
|
||||
});
|
||||
editor.dirty.onChange(updateDirty);
|
||||
return Promise.resolve(editor.ready && editor.ready())
|
||||
.then(updateDirty);
|
||||
});
|
||||
}
|
||||
window.addEventListener('resize', () => {
|
||||
if (!onBoundsChanged) debounce(rememberWindowSize, 100);
|
||||
detectLayout();
|
||||
});
|
||||
}
|
||||
|
||||
function updateTitle() {
|
||||
if (editor) {
|
||||
const styleName = editor.getStyle().name;
|
||||
const isDirty = editor.dirty.isDirty();
|
||||
document.title = (isDirty ? '* ' : '') + styleName;
|
||||
}
|
||||
function toggleStyle() {
|
||||
$('#enabled').checked = !style.enabled;
|
||||
updateEnabledness(!style.enabled);
|
||||
}
|
||||
|
||||
function updateDirty() {
|
||||
const isDirty = editor.dirty.isDirty();
|
||||
document.body.classList.toggle('dirty', isDirty);
|
||||
$('#save-button').disabled = !isDirty;
|
||||
const isDirty = dirty.isDirty();
|
||||
if (wasDirty !== isDirty) {
|
||||
wasDirty = isDirty;
|
||||
document.body.classList.toggle('dirty', isDirty);
|
||||
$('#save-button').disabled = !isDirty;
|
||||
}
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
function updateEnabledness(enabled) {
|
||||
dirty.modify('enabled', style.enabled, enabled);
|
||||
style.enabled = enabled;
|
||||
editor.updateLivePreview();
|
||||
}
|
||||
|
||||
function updateName() {
|
||||
if (!editor) return;
|
||||
const {value} = $('#name');
|
||||
dirty.modify('name', style[nameTarget] || style.name, value);
|
||||
style[nameTarget] = value;
|
||||
updateTitle({});
|
||||
}
|
||||
|
||||
function updateTitle() {
|
||||
document.title = `${dirty.isDirty() ? '* ' : ''}${style.customName || style.name}`;
|
||||
}
|
||||
})();
|
||||
|
||||
function preinit() {
|
||||
|
@ -295,7 +299,7 @@ function onRuntimeMessage(request) {
|
|||
switch (request.method) {
|
||||
case 'styleUpdated':
|
||||
if (
|
||||
editor.getStyleId() === request.style.id &&
|
||||
editor.style.id === request.style.id &&
|
||||
!['editPreview', 'editPreviewEnd', 'editSave', 'config']
|
||||
.includes(request.reason)
|
||||
) {
|
||||
|
@ -309,7 +313,7 @@ function onRuntimeMessage(request) {
|
|||
}
|
||||
break;
|
||||
case 'styleDeleted':
|
||||
if (editor.getStyleId() === request.style.id) {
|
||||
if (editor.style.id === request.style.id) {
|
||||
document.removeEventListener('visibilitychange', beforeUnload);
|
||||
document.removeEventListener('beforeunload', beforeUnload);
|
||||
closeCurrentTab();
|
||||
|
|
|
@ -1,41 +1,24 @@
|
|||
/* global dirtyReporter showHelp toggleContextMenuDelete createSection
|
||||
/* global showHelp toggleContextMenuDelete createSection
|
||||
CodeMirror linter createLivePreview showCodeMirrorPopup
|
||||
sectionsToMozFormat messageBox clipString
|
||||
rerouteHotkeys $ $$ $create t FIREFOX API
|
||||
$ $$ $create t FIREFOX API
|
||||
debounce */
|
||||
/* exported createSectionsEditor */
|
||||
'use strict';
|
||||
|
||||
function createSectionsEditor({style, onTitleChanged}) {
|
||||
function createSectionsEditor(editorBase) {
|
||||
const {style, dirty} = editorBase;
|
||||
|
||||
let INC_ID = 0; // an increment id that is used by various object to track the order
|
||||
const dirty = dirtyReporter();
|
||||
|
||||
const container = $('#sections');
|
||||
const sections = [];
|
||||
|
||||
container.classList.add('section-editor');
|
||||
|
||||
const nameEl = $('#name');
|
||||
nameEl.addEventListener('input', () => {
|
||||
dirty.modify('name', style.name, nameEl.value);
|
||||
style.name = nameEl.value;
|
||||
onTitleChanged();
|
||||
});
|
||||
|
||||
const enabledEl = $('#enabled');
|
||||
enabledEl.addEventListener('change', () => {
|
||||
dirty.modify('enabled', style.enabled, enabledEl.checked);
|
||||
style.enabled = enabledEl.checked;
|
||||
updateLivePreview();
|
||||
});
|
||||
|
||||
updateHeader();
|
||||
rerouteHotkeys(true);
|
||||
|
||||
$('#to-mozilla').addEventListener('click', showMozillaFormat);
|
||||
$('#to-mozilla-help').addEventListener('click', showToMozillaHelp);
|
||||
$('#from-mozilla').addEventListener('click', () => showMozillaFormatImport());
|
||||
$('#save-button').addEventListener('click', saveStyle);
|
||||
|
||||
document.addEventListener('wheel', scrollEntirePageOnCtrlShift, {passive: false});
|
||||
CodeMirror.defaults.extraKeys['Shift-Ctrl-Wheel'] = 'scrollWindow';
|
||||
|
@ -65,30 +48,27 @@ function createSectionsEditor({style, onTitleChanged}) {
|
|||
|
||||
let sectionOrder = '';
|
||||
let headerOffset; // in compact mode the header is at the top so it reduces the available height
|
||||
const initializing = initSections(style.sections.slice());
|
||||
const ready = initSections(style.sections.slice());
|
||||
|
||||
const livePreview = createLivePreview();
|
||||
livePreview.show(Boolean(style.id));
|
||||
|
||||
return {
|
||||
ready: () => initializing,
|
||||
return Object.assign({}, editorBase, {
|
||||
ready,
|
||||
replaceStyle,
|
||||
dirty,
|
||||
getStyle: () => style,
|
||||
getEditors,
|
||||
scrollToEditor,
|
||||
getStyleId: () => style.id,
|
||||
getEditorTitle: cm => {
|
||||
const index = sections.filter(s => !s.isRemoved()).findIndex(s => s.cm === cm);
|
||||
return `${t('sectionCode')} ${index + 1}`;
|
||||
},
|
||||
save: saveStyle,
|
||||
toggleStyle,
|
||||
save,
|
||||
nextEditor,
|
||||
prevEditor,
|
||||
closestVisible,
|
||||
getSearchableInputs,
|
||||
};
|
||||
updateLivePreview,
|
||||
});
|
||||
|
||||
function fitToContent(section) {
|
||||
const {cm, cm: {display: {wrapper, sizer}}} = section;
|
||||
|
@ -246,14 +226,6 @@ function createSectionsEditor({style, onTitleChanged}) {
|
|||
return sections.filter(s => !s.isRemoved()).map(s => s.cm);
|
||||
}
|
||||
|
||||
function toggleStyle() {
|
||||
const newValue = !style.enabled;
|
||||
dirty.modify('enabled', style.enabled, newValue);
|
||||
style.enabled = newValue;
|
||||
enabledEl.checked = newValue;
|
||||
updateLivePreview();
|
||||
}
|
||||
|
||||
function nextEditor(cm, cycle = true) {
|
||||
if (!cycle && findLast(sections, s => !s.isRemoved()).cm === cm) {
|
||||
return;
|
||||
|
@ -417,7 +389,7 @@ function createSectionsEditor({style, onTitleChanged}) {
|
|||
}
|
||||
|
||||
function validate() {
|
||||
if (!nameEl.reportValidity()) {
|
||||
if (!$('#name').reportValidity()) {
|
||||
messageBox.alert(t('styleMissingName'));
|
||||
return false;
|
||||
}
|
||||
|
@ -435,7 +407,7 @@ function createSectionsEditor({style, onTitleChanged}) {
|
|||
return true;
|
||||
}
|
||||
|
||||
function saveStyle() {
|
||||
function save() {
|
||||
if (!dirty.isDirty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -464,10 +436,10 @@ function createSectionsEditor({style, onTitleChanged}) {
|
|||
}
|
||||
|
||||
function updateHeader() {
|
||||
nameEl.value = style.name || '';
|
||||
enabledEl.checked = style.enabled !== false;
|
||||
$('#name').value = style.customName || style.name || '';
|
||||
$('#enabled').checked = style.enabled !== false;
|
||||
$('#url').href = style.url || '';
|
||||
onTitleChanged();
|
||||
editorBase.updateName();
|
||||
}
|
||||
|
||||
function updateLivePreview() {
|
||||
|
@ -609,6 +581,7 @@ function createSectionsEditor({style, onTitleChanged}) {
|
|||
}
|
||||
|
||||
function replaceStyle(newStyle, codeIsUpdated) {
|
||||
dirty.clear('name');
|
||||
// FIXME: avoid recreating all editors?
|
||||
reinit().then(() => {
|
||||
Object.assign(style, newStyle);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global dirtyReporter
|
||||
/* global
|
||||
createAppliesToLineWidget messageBox
|
||||
sectionsToMozFormat
|
||||
createMetaCompiler linter createLivePreview cmFactory $ $create API prefs t
|
||||
|
@ -6,17 +6,14 @@
|
|||
/* exported createSourceEditor */
|
||||
'use strict';
|
||||
|
||||
function createSourceEditor({style, onTitleChanged}) {
|
||||
$('#name').disabled = true;
|
||||
$('#save-button').disabled = true;
|
||||
function createSourceEditor(editorBase) {
|
||||
const {style, dirty} = editorBase;
|
||||
|
||||
$('#mozilla-format-container').remove();
|
||||
$('#save-button').onclick = save;
|
||||
$('#header').addEventListener('wheel', headerOnScroll);
|
||||
$('#sections').textContent = '';
|
||||
$('#sections').appendChild($create('.single-editor'));
|
||||
|
||||
const dirty = dirtyReporter();
|
||||
|
||||
// normalize style
|
||||
if (!style.id) setupNewStyle(style);
|
||||
|
||||
|
@ -28,13 +25,6 @@ function createSourceEditor({style, onTitleChanged}) {
|
|||
const livePreview = createLivePreview(preprocess);
|
||||
livePreview.show(Boolean(style.id));
|
||||
|
||||
$('#enabled').onchange = function () {
|
||||
const value = this.checked;
|
||||
dirty.modify('enabled', style.enabled, value);
|
||||
style.enabled = value;
|
||||
updateLivePreview();
|
||||
};
|
||||
|
||||
cm.on('changes', () => {
|
||||
dirty.modify('sourceGeneration', savedGeneration, cm.changeGeneration());
|
||||
updateLivePreview();
|
||||
|
@ -162,14 +152,15 @@ function createSourceEditor({style, onTitleChanged}) {
|
|||
}
|
||||
|
||||
function updateMeta() {
|
||||
$('#name').value = style.name;
|
||||
$('#name').value = style.customName || style.name;
|
||||
$('#enabled').checked = style.enabled;
|
||||
$('#url').href = style.url;
|
||||
onTitleChanged();
|
||||
editorBase.updateName();
|
||||
return cm.setPreprocessor((style.usercssData || {}).preprocessor);
|
||||
}
|
||||
|
||||
function replaceStyle(newStyle, codeIsUpdated) {
|
||||
dirty.clear('name');
|
||||
const sameCode = newStyle.sourceCode === cm.getValue();
|
||||
if (sameCode) {
|
||||
savedGeneration = cm.changeGeneration();
|
||||
|
@ -210,14 +201,6 @@ function createSourceEditor({style, onTitleChanged}) {
|
|||
}
|
||||
}
|
||||
|
||||
function toggleStyle() {
|
||||
const value = !style.enabled;
|
||||
dirty.modify('enabled', style.enabled, value);
|
||||
style.enabled = value;
|
||||
updateMeta();
|
||||
$('#enabled').dispatchEvent(new Event('change', {bubbles: true}));
|
||||
}
|
||||
|
||||
function save() {
|
||||
if (!dirty.isDirty()) return;
|
||||
const code = cm.getValue();
|
||||
|
@ -226,6 +209,7 @@ function createSourceEditor({style, onTitleChanged}) {
|
|||
id: style.id,
|
||||
enabled: style.enabled,
|
||||
sourceCode: code,
|
||||
customName: style.customName,
|
||||
}))
|
||||
.then(replaceStyle)
|
||||
.catch(err => {
|
||||
|
@ -372,19 +356,17 @@ function createSourceEditor({style, onTitleChanged}) {
|
|||
(mode.helperType || '');
|
||||
}
|
||||
|
||||
return {
|
||||
return Object.assign({}, editorBase, {
|
||||
ready: Promise.resolve(),
|
||||
replaceStyle,
|
||||
dirty,
|
||||
getStyle: () => style,
|
||||
getEditors: () => [cm],
|
||||
scrollToEditor: () => {},
|
||||
getStyleId: () => style.id,
|
||||
getEditorTitle: () => '',
|
||||
save,
|
||||
toggleStyle,
|
||||
prevEditor: cm => nextPrevMozDocument(cm, -1),
|
||||
nextEditor: cm => nextPrevMozDocument(cm, 1),
|
||||
closestVisible: () => cm,
|
||||
getSearchableInputs: () => []
|
||||
};
|
||||
getSearchableInputs: () => [],
|
||||
updateLivePreview,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -243,7 +243,7 @@
|
|||
(!dup ?
|
||||
Promise.resolve(true) :
|
||||
messageBox.confirm(t('styleInstallOverwrite', [
|
||||
data.name,
|
||||
data.name + (dup.customName ? ` (${dup.customName})` : ''),
|
||||
dupData.version,
|
||||
data.version,
|
||||
]))
|
||||
|
|
|
@ -23,7 +23,7 @@ function configDialog(style) {
|
|||
vars.forEach(renderValueState);
|
||||
|
||||
return messageBox({
|
||||
title: `${style.name} v${data.version}`,
|
||||
title: `${style.customName || style.name} v${data.version}`,
|
||||
className: 'config-dialog' + (isPopup ? ' stylus-popup' : ''),
|
||||
contents: [
|
||||
$create('.config-heading', data.supportURL &&
|
||||
|
|
|
@ -137,10 +137,14 @@ function initGlobalEvents() {
|
|||
|
||||
function showStyles(styles = [], matchUrlIds) {
|
||||
const sorted = sorter.sort({
|
||||
styles: styles.map(style => ({
|
||||
style,
|
||||
name: (style.name || '').toLocaleLowerCase() + '\n' + style.name,
|
||||
})),
|
||||
styles: styles.map(style => {
|
||||
const name = style.customName || style.name || '';
|
||||
return {
|
||||
style,
|
||||
// sort case-insensitively the whole list then sort dupes like `Foo` and `foo` case-sensitively
|
||||
name: name.toLocaleLowerCase() + '\n' + name,
|
||||
};
|
||||
}),
|
||||
});
|
||||
let index = 0;
|
||||
let firstRun = true;
|
||||
|
@ -187,7 +191,7 @@ function showStyles(styles = [], matchUrlIds) {
|
|||
}
|
||||
|
||||
|
||||
function createStyleElement({style, name}) {
|
||||
function createStyleElement({style, name: nameLC}) {
|
||||
// query the sub-elements just once, then reuse the references
|
||||
if ((createStyleElement.parts || {}).newUI !== newUI.enabled) {
|
||||
const entry = template[`style${newUI.enabled ? 'Compact' : ''}`];
|
||||
|
@ -216,8 +220,9 @@ function createStyleElement({style, name}) {
|
|||
}
|
||||
const parts = createStyleElement.parts;
|
||||
const configurable = style.usercssData && style.usercssData.vars && Object.keys(style.usercssData.vars).length > 0;
|
||||
const name = style.customName || style.name;
|
||||
parts.checker.checked = style.enabled;
|
||||
parts.nameLink.textContent = tWordBreak(style.name);
|
||||
parts.nameLink.textContent = tWordBreak(name);
|
||||
parts.nameLink.href = parts.editLink.href = parts.editHrefBase + style.id;
|
||||
parts.homepage.href = parts.homepage.title = style.url || '';
|
||||
if (!newUI.enabled) {
|
||||
|
@ -234,7 +239,7 @@ function createStyleElement({style, name}) {
|
|||
const entry = parts.entry.cloneNode(true);
|
||||
entry.id = ENTRY_ID_PREFIX_RAW + style.id;
|
||||
entry.styleId = style.id;
|
||||
entry.styleNameLowerCase = name || style.name.toLocaleLowerCase();
|
||||
entry.styleNameLowerCase = nameLC || name.toLocaleLowerCase() + '\n' + name;
|
||||
entry.styleMeta = style;
|
||||
entry.className = parts.entryClassBase + ' ' +
|
||||
(style.enabled ? 'enabled' : 'disabled') +
|
||||
|
@ -437,7 +442,7 @@ Object.assign(handleEvent, {
|
|||
animateElement(entry);
|
||||
messageBox({
|
||||
title: t('deleteStyleConfirm'),
|
||||
contents: entry.styleMeta.name,
|
||||
contents: entry.styleMeta.customName || entry.styleMeta.name,
|
||||
className: 'danger center',
|
||||
buttons: [t('confirmDelete'), t('confirmCancel')],
|
||||
})
|
||||
|
|
|
@ -130,7 +130,7 @@ const sorter = (() => {
|
|||
const sorted = sort({
|
||||
styles: current.map(entry => ({
|
||||
entry,
|
||||
name: entry.styleNameLowerCase + '\n' + entry.styleMeta.name,
|
||||
name: entry.styleNameLowerCase,
|
||||
style: entry.styleMeta,
|
||||
}))
|
||||
});
|
||||
|
|
|
@ -310,7 +310,7 @@ function sortStyles(entries) {
|
|||
return entries.sort(({styleMeta: a}, {styleMeta: b}) =>
|
||||
Boolean(a.frameUrl) - Boolean(b.frameUrl) ||
|
||||
enabledFirst && Boolean(b.enabled) - Boolean(a.enabled) ||
|
||||
a.name.localeCompare(b.name));
|
||||
(a.customName || a.name).localeCompare(b.customName || b.name));
|
||||
}
|
||||
|
||||
function showStyles(frameResults) {
|
||||
|
@ -408,7 +408,7 @@ function createStyleElement(style) {
|
|||
$('.checker', entry).checked = style.enabled;
|
||||
|
||||
const styleName = $('.style-name', entry);
|
||||
styleName.lastChild.textContent = style.name;
|
||||
styleName.lastChild.textContent = style.customName || style.name;
|
||||
setTimeout(() => {
|
||||
styleName.title = entry.styleMeta.sloppy ?
|
||||
t('styleNotAppliedRegexpProblemTooltip') :
|
||||
|
|
Loading…
Reference in New Issue
Block a user