diff --git a/background/background.js b/background/background.js index 8fa4b8e0..6d15e8d4 100644 --- a/background/background.js +++ b/background/background.js @@ -19,6 +19,7 @@ window.API_METHODS = Object.assign(window.API_METHODS || {}, { importStyle: styleManager.importStyle, styleExists: styleManager.styleExists, getStyle: styleManager.get, + getAllStyles: styleManager.getAllStyles, // used by importer getTabUrlPrefix() { return this.sender.tab.url.match(/^([\w-]+:\/+[^/#]+)/)[1]; diff --git a/background/style-manager.js b/background/style-manager.js index 28026482..a276c911 100644 --- a/background/style-manager.js +++ b/background/style-manager.js @@ -56,8 +56,12 @@ const styleManager = (() => { port = null; if (id) { const style = styles.get(id); + if (!style) { + // maybe deleted + return; + } style.preview = null; - broadcastStyleUpdated(style.data, 'editPreview'); + broadcastStyleUpdated(style.data, 'editPreviewEnd'); } }); }); @@ -128,7 +132,7 @@ const styleManager = (() => { function importStyle(data) { // FIXME: is it a good idea to save the data directly? return saveStyle(data) - .then(newData => handleSave(newData)); + .then(newData => handleSave(newData, 'import')); } function installStyle(data) { diff --git a/manage/import-export.js b/manage/import-export.js index d15cd409..dc94f9ed 100644 --- a/manage/import-export.js +++ b/manage/import-export.js @@ -56,19 +56,14 @@ function importFromFile({fileTypeFilter, file} = {}) { } -function importFromString(jsonString, oldStyles) { - if (!oldStyles) { - return API.getStylesInfo().then(styles => importFromString(jsonString, styles)); - } +function importFromString(jsonString) { const json = tryJSONparse(jsonString); if (!Array.isArray(json)) { return Promise.reject(new Error('the backup is not a valid JSON file')); } - const oldStylesById = new Map( - oldStyles.map(style => [style.id, style])); - const oldStylesByName = json.length && new Map( - oldStyles.map(style => [style.name.trim(), style])); - + let oldStyles; + let oldStylesById; + let oldStylesByName; const stats = { added: {names: [], ids: [], legend: 'importReportLegendAdded'}, unchanged: {names: [], ids: [], legend: 'importReportLegendIdentical'}, @@ -78,27 +73,25 @@ function importFromString(jsonString, oldStyles) { invalid: {names: [], legend: 'importReportLegendInvalid'}, }; - let index = 0; - let lastRenderTime = performance.now(); - const renderQueue = []; - const RENDER_NAP_TIME_MAX = 1000; // ms - const RENDER_QUEUE_MAX = 50; // number of styles - return proceed(); - - function proceed() { - while (index < json.length) { - const item = json[index++]; - const info = analyze(item); - if (!info) { - continue; + return API.getAllStyles().then(styles => { + // make a copy of the current database, that may be used when we want to + // undo + oldStyles = styles; + oldStylesById = new Map( + oldStyles.map(style => [style.id, style])); + oldStylesByName = json.length && new Map( + oldStyles.map(style => [style.name.trim(), style])); + return Promise.all(json.map((item, i) => { + const info = analyze(item, i); + if (info) { + return API.importStyle(item) + .then(style => updateStats(style, info)); } - return API.importStyle(item) - .then(style => account({style, info})); - } - return done(); - } + })); + }) + .then(done); - function analyze(item) { + function analyze(item, index) { if (typeof item !== 'object' || !item || !item.name || @@ -142,18 +135,6 @@ function importFromString(jsonString, oldStyles) { .some(field => oldStyle[field] && oldStyle[field] === newStyle[field]); } - function account({style, info}) { - renderQueue.push(style); - if (performance.now() - lastRenderTime > RENDER_NAP_TIME_MAX - || renderQueue.length > RENDER_QUEUE_MAX) { - setTimeout(scrollElementIntoView, 0, $('#style-' + renderQueue.pop().id)); - renderQueue.length = 0; - lastRenderTime = performance.now(); - } - updateStats(style, info); - return proceed(); - } - function updateStats(style, {oldStyle, metaEqual, codeEqual}) { if (!oldStyle) { stats.added.names.push(style.name); diff --git a/manage/manage.js b/manage/manage.js index e13c8865..619bd9b0 100644 --- a/manage/manage.js +++ b/manage/manage.js @@ -48,7 +48,8 @@ function onRuntimeMessage(msg) { switch (msg.method) { case 'styleUpdated': case 'styleAdded': - handleUpdate(msg.style, msg); + API.getStylesInfo({id: msg.style.id}) + .then(([style]) => handleUpdate(style, msg)); break; case 'styleDeleted': handleDelete(msg.style.id); @@ -521,7 +522,7 @@ function handleUpdate(style, {reason, method} = {}) { if (reason === 'editPreview') return; // the style was toggled and refreshAllTabs() sent a mini-notification, // but we've already processed 'styleUpdated' sent directly from notifyAllTabs() - if (!style.sections) return; + // if (!style.sections) return; let entry; let oldEntry = $(ENTRY_ID_PREFIX + style.id); if (oldEntry && method === 'styleUpdated') { diff --git a/popup/popup.js b/popup/popup.js index 6dbc7591..4d253e63 100644 --- a/popup/popup.js +++ b/popup/popup.js @@ -25,10 +25,14 @@ getActiveTab() ) .then(url => Promise.all([ (tabURL = URLS.supported(url) ? url : '') && - API.getStylesInfoByUrl(tabURL), + API.getStylesInfoByUrl(tabURL), onDOMready().then(initPopup), ])) .then(([results]) => { + if (!results) { + // unsupported URL; + return; + } showStyles(results.map(r => Object.assign(r.data, r))); }) .catch(console.error);