2f4da37fdb
Popup: * Enforce 200-800px range for the popup width option Manage: * faster search via cachedStyles.byId * faster restoration of search results on history nav * style name is clickable and opens the editor * animated highlight of style element on update/add/save * expandable extra applies-to targets * remember scroll position on normal history navigation * boz-sizing in #header, also in editor * applies-to targets use structured markup * get*Tab*, enableStyle and deleteStyle are promisified
149 lines
4.6 KiB
JavaScript
149 lines
4.6 KiB
JavaScript
/* globals getStyles, saveStyle, invalidateCache, refreshAllTabs, handleUpdate */
|
|
'use strict';
|
|
|
|
var STYLISH_DUMP_FILE_EXT = '.txt';
|
|
var STYLISH_DUMPFILE_EXTENSION = '.json';
|
|
var STYLISH_DEFAULT_SAVE_NAME = 'stylus-mm-dd-yyyy' + STYLISH_DUMP_FILE_EXT;
|
|
|
|
function importFromFile({fileTypeFilter, file} = {}) {
|
|
return new Promise(resolve => {
|
|
const fileInput = document.createElement('input');
|
|
if (file) {
|
|
readFile();
|
|
return;
|
|
}
|
|
fileInput.style.display = 'none';
|
|
fileInput.type = 'file';
|
|
fileInput.accept = fileTypeFilter || STYLISH_DUMP_FILE_EXT;
|
|
fileInput.acceptCharset = 'utf-8';
|
|
|
|
document.body.appendChild(fileInput);
|
|
fileInput.initialValue = fileInput.value;
|
|
fileInput.onchange = readFile;
|
|
fileInput.click();
|
|
|
|
function readFile() {
|
|
if (file || fileInput.value !== fileInput.initialValue) {
|
|
file = file || fileInput.files[0];
|
|
if (file.size > 100*1000*1000) {
|
|
console.warn("100MB backup? I don't believe you.");
|
|
importFromString('').then(resolve);
|
|
return;
|
|
}
|
|
document.body.style.cursor = 'wait';
|
|
const fReader = new FileReader();
|
|
fReader.onloadend = event => {
|
|
fileInput.remove();
|
|
importFromString(event.target.result).then(numStyles => {
|
|
document.body.style.cursor = '';
|
|
resolve(numStyles);
|
|
});
|
|
};
|
|
fReader.readAsText(file, 'utf-8');
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function importFromString(jsonString) {
|
|
const json = runTryCatch(() => Array.from(JSON.parse(jsonString))) || [];
|
|
const numStyles = json.length;
|
|
|
|
if (numStyles) {
|
|
invalidateCache(true);
|
|
}
|
|
|
|
return new Promise(resolve => {
|
|
proceed();
|
|
function proceed() {
|
|
const nextStyle = json.shift();
|
|
if (nextStyle) {
|
|
saveStyle(nextStyle, {notify: false}).then(style => {
|
|
handleUpdate(style);
|
|
setTimeout(proceed, 0);
|
|
});
|
|
} else {
|
|
refreshAllTabs().then(() => {
|
|
scrollTo(0, 0);
|
|
setTimeout(alert, 100, numStyles + ' styles installed/updated');
|
|
resolve(numStyles);
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function generateFileName() {
|
|
var today = new Date();
|
|
var dd = '0' + today.getDate();
|
|
var mm = '0' + (today.getMonth() + 1);
|
|
var yyyy = today.getFullYear();
|
|
|
|
dd = dd.substr(-2);
|
|
mm = mm.substr(-2);
|
|
|
|
today = mm + '-' + dd + '-' + yyyy;
|
|
|
|
return 'stylus-' + today + STYLISH_DUMPFILE_EXTENSION;
|
|
}
|
|
|
|
document.getElementById('file-all-styles').onclick = () => {
|
|
getStyles({}, function (styles) {
|
|
let text = JSON.stringify(styles, null, '\t');
|
|
let fileName = generateFileName() || STYLISH_DEFAULT_SAVE_NAME;
|
|
|
|
let url = 'data:text/plain;charset=utf-8,' + encodeURIComponent(text);
|
|
// for long URLs; https://github.com/schomery/stylish-chrome/issues/13#issuecomment-284582600
|
|
fetch(url)
|
|
.then(res => res.blob())
|
|
.then(blob => {
|
|
let a = document.createElement('a');
|
|
a.setAttribute('download', fileName);
|
|
a.setAttribute('href', URL.createObjectURL(blob));
|
|
a.dispatchEvent(new MouseEvent('click'));
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
document.getElementById('unfile-all-styles').onclick = () => {
|
|
importFromFile({fileTypeFilter: STYLISH_DUMPFILE_EXTENSION});
|
|
};
|
|
|
|
const dropTarget = Object.assign(document.body, {
|
|
ondragover: event => {
|
|
const hasFiles = event.dataTransfer.types.includes('Files');
|
|
event.dataTransfer.dropEffect = hasFiles || event.target.type == 'search' ? 'copy' : 'none';
|
|
dropTarget.classList.toggle('dropzone', hasFiles);
|
|
if (hasFiles) {
|
|
event.preventDefault();
|
|
clearTimeout(dropTarget.fadeoutTimer);
|
|
dropTarget.classList.remove('fadeout');
|
|
}
|
|
},
|
|
ondragend: event => {
|
|
dropTarget.classList.add('fadeout');
|
|
// transitionend event may not fire if the user switched to another tab so we'll use a timer
|
|
clearTimeout(dropTarget.fadeoutTimer);
|
|
dropTarget.fadeoutTimer = setTimeout(() => {
|
|
dropTarget.classList.remove('dropzone', 'fadeout');
|
|
}, 250);
|
|
},
|
|
ondragleave: event => {
|
|
// Chrome sets screen coords to 0 on Escape key pressed or mouse out of document bounds
|
|
if (!event.screenX && !event.screenX) {
|
|
dropTarget.ondragend();
|
|
}
|
|
},
|
|
ondrop: event => {
|
|
if (event.dataTransfer.files.length) {
|
|
event.preventDefault();
|
|
importFromFile({file: event.dataTransfer.files[0]}).then(() => {
|
|
dropTarget.classList.remove('dropzone');
|
|
});
|
|
} else {
|
|
dropTarget.ondragend();
|
|
}
|
|
},
|
|
});
|