From befcd1f74c6123414bb17f54aacc3e31f22aa5a8 Mon Sep 17 00:00:00 2001 From: Kushagra Gour <chinchang457@gmail.com> Date: Mon, 27 Feb 2017 02:36:28 +0530 Subject: [PATCH] add import/export feat. fixes #59 --- src/index.html | 17 +++++++ src/script.js | 135 +++++++++++++++++++++++++++++++++++++++++++++---- src/style.css | 15 ++++-- 3 files changed, 155 insertions(+), 12 deletions(-) diff --git a/src/index.html b/src/index.html index ba720ea..f5247bf 100644 --- a/src/index.html +++ b/src/index.html @@ -377,7 +377,24 @@ <div id="js-saved-items-pane" class="saved-items-pane"> <button class="btn saved-items-pane__close-btn" id="js-saved-items-pane-close-btn">X</button> + <div class="flex flex-v-center" style="justify-content: space-between;"> + <h3>My Library</h3> + <div class="main-header__btn-wrap"> + <a d-click="exportItems" href="" class="btn btn-icon"> +<svg viewBox="0 0 24 24" style="width:14px;height:14px"> + <path d="M6,2C4.89,2 4,2.9 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M13,3.5L18.5,9H13M8.93,12.22H16V19.29L13.88,17.17L11.05,20L8.22,17.17L11.05,14.35" /> +</svg> +Export + </a> + <a d-click="onImportBtnClicked" href="" class="btn btn-icon"> +<svg viewBox="0 0 24 24" style="width:14px;height:14px"> + <path d="M6,2C4.89,2 4,2.9 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M13,3.5L18.5,9H13M10.05,11.22L12.88,14.05L15,11.93V19H7.93L10.05,16.88L7.22,14.05" /> +</svg> +Import + </a> + </div> + </div> <div id="js-saved-items-wrap" class="saved-items-pane__container"> </div> diff --git a/src/script.js b/src/script.js index f006f73..74798b8 100644 --- a/src/script.js +++ b/src/script.js @@ -331,13 +331,19 @@ TextareaAutoComplete */ isSavedItemsPaneOpen = savedItemsPane.classList.contains('is-open'); document.body.classList[isSavedItemsPaneOpen ? 'add' : 'remove']('overlay-visible'); } - function openSavedItemsPane() { + + /** + * Fetches all items from storage + * @param {boolean} shouldSaveGlobally Whether to store the fetched items in global arr for later use. + * @return {promise} Promise. + */ + function fetchItems(shouldSaveGlobally) { + var d = deferred(); chrome.storage.local.get('items', function (result) { var itemIds = Object.getOwnPropertyNames(result.items || {}), items = []; if (!itemIds.length) { - populateItemsInSavedPane([]); - return; + d.resolve([]); } savedItems = savedItems || []; @@ -346,17 +352,26 @@ TextareaAutoComplete */ /* eslint-disable no-loop-func */ chrome.storage.local.get(itemIds[i], function (itemResult) { - savedItems[itemIds[i]] = itemResult[itemIds[i]]; + if (shouldSaveGlobally) { + savedItems[itemIds[i]] = itemResult[itemIds[i]]; + } items.push(itemResult[itemIds[i]]); // Check if we have all items now. if (itemIds.length === items.length) { - populateItemsInSavedPane(items); + d.resolve(items) } }); /* eslint-enable no-loop-func */ } }); + return d.promise; + } + + function openSavedItemsPane() { + fetchItems(true).then(function (items) { + populateItemsInSavedPane(items); + }); } function createNewItem() { @@ -404,6 +419,9 @@ TextareaAutoComplete */ createNewItem(); } }); + // Remove from cached list + delete savedItems[itemId]; + trackEvent('fn', 'itemRemoved'); } @@ -893,22 +911,122 @@ TextareaAutoComplete */ } } - scope.onModalSettingsLinkClick = function () { + scope.onModalSettingsLinkClick = function onModalSettingsLinkClick() { openSettings(); trackEvent('ui', 'onboardSettingsBtnClick'); } - scope.onShowInTabClicked = function () { + scope.onShowInTabClicked = function onShowInTabClicked() { onboardDontShowInTabOptionBtn.classList.remove('selected'); onboardShowInTabOptionBtn.classList.add('selected'); trackEvent('ui', 'onboardShowInTabClick'); } - scope.onDontShowInTabClicked = function () { + scope.onDontShowInTabClicked = function onDontShowInTabClicked() { onboardDontShowInTabOptionBtn.classList.add('selected'); onboardShowInTabOptionBtn.classList.remove('selected'); trackEvent('ui', 'onboardDontShowInTabClick'); } + scope.exportItems = function exportItems(e) { + fetchItems().then(function (items) { + utils.log(9, items); + var d = new Date(); + var fileName = [ 'web-maker-export', d.getFullYear(), (d.getMonth() + 1), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds() ].join('-'); + fileName += '.json'; + var blob = new Blob([ JSON.stringify(items,false,2) ], { type: "application/json;charset=UTF-8" }); + var a = document.createElement('a'); + a.href = window.URL.createObjectURL(blob); + a.download = fileName; + a.style.display = 'none'; + document.body.appendChild(a); + a.click(); + a.remove(); + trackEvent('ui', 'exportBtnClicked'); + }); + e.preventDefault(); + } + + function mergeImportedItems(items) { + var existingItemIds = []; + var toMergeItems = {}; + items.forEach((item) => { + if (savedItems[item.id]) { + // Item already exists + existingItemIds.push(item.id); + } else { + utils.log('merging', item.id); + toMergeItems[item.id] = item; + } + }); + var mergedItemCount = items.length - existingItemIds.length; + if (existingItemIds.length) { + var shouldReplace = confirm(existingItemIds.length + ' creations already exist. Do you want to replace them?'); + if (shouldReplace) { + utils.log('shouldreplace', shouldReplace); + items.forEach((item) => { + toMergeItems[item.id] = item; + mergedItemCount = items.length; + }); + } + } + if (mergedItemCount) { + // save new items + chrome.storage.local.set(toMergeItems, function () { + alertsService.add(mergedItemCount + ' creations imported successfully.'); + }); + // Push in new item IDs + chrome.storage.local.get({ + items: {} + }, function (result) { + + /* eslint-disable guard-for-in */ + for (var id in toMergeItems) { + result.items[id] = true; + chrome.storage.local.set({ + items: result.items + }); + } + + /* eslint-enable guard-for-in */ + }); + alertsService.add(mergedItemCount + ' creations imported successfully.'); + } + // FIXME: Move from here + toggleSavedItemsPane(false); + } + + function onImportFileChange(e) { + var file = e.target.files[0]; + // if (!f.type.match('image.*')) { + // continue; + // } + + var reader = new FileReader(); + reader.onload = function(progressEvent) { + var items; + try { + items = JSON.parse(progressEvent.target.result); + utils.log(items); + mergeImportedItems(items); + } catch (ex) { + alert('Oops! Select file is corrupted.') + } + }; + + reader.readAsText(file, 'utf-8'); + } + + scope.onImportBtnClicked = function exportItems(e) { + var input = document.createElement('input'); + input.type = 'file'; + input.style.display = 'none'; + input.accept = 'accept="application/json'; + document.body.appendChild(input) + input.addEventListener('change', onImportFileChange); + input.click(); + e.preventDefault(); + } + function saveScreenshot(dataURI) { // convert base64 to raw binary data held in a string // doesn't handle URLEncoded DataURIs @@ -1098,7 +1216,6 @@ TextareaAutoComplete */ toggleSavedItemsPane(); } if (e.target.classList.contains('js-saved-item-tile__close-btn')) { - utils.log('removing', e.target.parentElement) removeItem(e.target.parentElement.dataset.itemId); } }); diff --git a/src/style.css b/src/style.css index 2367d36..ebee10a 100644 --- a/src/style.css +++ b/src/style.css @@ -258,7 +258,7 @@ li.CodeMirror-hint-active { background-color: rgba(0, 0, 0, 0.5); color: rgba(255, 255, 255, 0.45); border-top: 1px solid rgba(255,255,255,0.14); - line-height: 20px; + /*line-height: 20px;*/ } .main-header { border: 0; @@ -266,17 +266,26 @@ li.CodeMirror-hint-active { } .main-header__btn-wrap > a { font-size: 0.8em; + line-height: 20px; + height: 20px; + letter-spacing: 0.6px; color: #9297B3; border-radius: 3px; - border: 1px solid rgba(146, 151, 179, 0.33); margin-left: 10px; - padding: 0px 5px; + padding: 0px 8px; + border: 1px solid rgba(0,0,0,.9); + background: linear-gradient(180deg, rgba(0,0,0,0.5) 0, rgba(255,255,255,0.1) 100%); + text-shadow: 0px 1px 1px rgba(0,0,0,1); + box-shadow: 0 -1px 0px 0 rgba(255,255,255,0.15); text-transform: uppercase; } .main-header__btn-wrap > a > svg { fill: #9297B3; margin-right: 4px; } +.main-header__btn-wrap > a.is-marked > svg { + fill: crimson; +} .main-header__btn-wrap > a:hover { border-color: rgba(146, 151, 179, 0.5); }