diff --git a/wallabagger.crx b/wallabagger.crx index 026c3c2..ff17266 100644 Binary files a/wallabagger.crx and b/wallabagger.crx differ diff --git a/wallabagger.nex b/wallabagger.nex index 026c3c2..ff17266 100644 Binary files a/wallabagger.nex and b/wallabagger.nex differ diff --git a/wallabagger.zip b/wallabagger.zip index 346f2e0..39aed55 100644 Binary files a/wallabagger.zip and b/wallabagger.zip differ diff --git a/wallabagger/css/popup.css b/wallabagger/css/popup.css index abe7938..cb8dd1a 100644 --- a/wallabagger/css/popup.css +++ b/wallabagger/css/popup.css @@ -48,7 +48,8 @@ span.icon { } #card-image { - height: 250px; + max-width: 444px; + max-height: 250px; overflow: hidden; } diff --git a/wallabagger/js/background.js b/wallabagger/js/background.js index 26e361f..ef73f37 100644 --- a/wallabagger/js/background.js +++ b/wallabagger/js/background.js @@ -1,9 +1,49 @@ -/* globals WallabagApi */ +//* globals WallabagApi */ + +// declarations + if (typeof (browser) === 'undefined' && typeof (chrome) === 'object') { browser = chrome; } -const icon = { +let Port = null; +let portConnected = false; + +var CacheType = function (enable) { + this.enabled = enable; + this._cache = []; +}; + +CacheType.prototype = { + _cache: null, + enabled: null, + + str: function (some) { + return btoa(JSON.stringify(some)); + }, + + set: function (key, data) { + if (this.enabled) { + this._cache[this.str(key)] = data; + } + }, + + clear: function (key) { + if (this.enabled) { + delete this._cache[this.str(key)]; + } + }, + + check: function (key) { + return this.enabled && (this._cache[this.str(key)] !== undefined); + }, + + get: function (key) { + return this.enabled ? this._cache[this.str(key)] : undefined; + } +}; + +const icons = { 'default': browser.runtime.getManifest().browser_action.default_icon, 'good': 'img/wallabagger-green.svg', 'wip': 'img/wallabagger-yellow.svg', @@ -11,197 +51,431 @@ const icon = { }; -const GetApi = () => { - const api = new WallabagApi(); - return api.init() - .then(data => { - if (api.needNewAppToken()) { - return api.GetAppToken() - .then(r => api); - } - return api; - }) - .catch(error => { - throw error; - }); +const wallabagContextMenus = [ + { + id: 'wallabagger-add-link', + title: 'Wallabag it!', + contexts: ['link', 'page'] + }, + { + type: 'separator', + contexts: ['browser_action'] + }, + { + id: 'unread', + title: 'Unread articles', + contexts: ['browser_action'] + }, + { + id: 'starred', + title: 'Starred articles', + contexts: ['browser_action'] + }, + { + id: 'archive', + title: 'Archived articles', + contexts: ['browser_action'] + }, + { + id: 'all', + title: 'All articles', + contexts: ['browser_action'] + }, + { + id: 'tag', + title: 'Tag list', + contexts: ['browser_action'] + } +]; + +const existStates = { + exists: 'exists', + notexists: 'notexists', + wip: 'wip' }; -browser.contextMenus.create({ - id: 'wallabagger-add-link', - title: 'Wallabag it!', - contexts: ['link', 'page'] -}); +const cache = new CacheType(true); // TODO - here checking option +const dirtyCache = new CacheType(true); +const existCache = new CacheType(true); -browser.contextMenus.create({ - type: 'separator', - contexts: ['browser_action'] -}); +const api = new WallabagApi(); -browser.contextMenus.create({ - id: 'Unread-articles', - title: 'Unread articles', - contexts: ['browser_action'] -}); +// Code -browser.contextMenus.create({ - id: 'Favorite-articles', - title: 'Starred articles', - contexts: ['browser_action'] +api.init().then(data => { + addExistCheckListeners(api.data.AllowExistCheck); + api.GetTags().then(tags => { cache.set('allTags', tags); }); }); -browser.contextMenus.create({ - id: 'Archived-articles', - title: 'Archived articles', - contexts: ['browser_action'] -}); +addListeners(); +createContextMenus(); -browser.contextMenus.create({ - id: 'All-articles', - title: 'All articles', - contexts: ['browser_action'] -}); +// Functions +function createContextMenus () { + wallabagContextMenus.map(menu => { browser.contextMenus.create(menu); }); +} -browser.contextMenus.create({ - id: 'Tag-list', - title: 'Tag list', - contexts: ['browser_action'] -}); +function onTabActivatedListener (activeInfo) { + setIcon(icons.default); + const { tabId } = activeInfo; + browser.tabs.get(tabId, function (tab) { + checkExist(tab.url); + }); +} -function savePageToWallabag (url) { - browser.browserAction.setIcon({ path: icon.wip }); - - GetApi().then(api => api.SavePage(url)) - .then(r => { - browser.browserAction.setIcon({ path: icon.good }); - setTimeout(function () { browser.browserAction.setIcon({ path: icon.default }); }, 5000); - }) - .catch(e => { - browser.browserAction.setIcon({ path: icon.bad }); - setTimeout(function () { browser.browserAction.setIcon({ path: icon.default }); }, 5000); - }); -}; +function onTabCreatedListener (tab) { + setIcon(icons.default); +} + +function onTabUpdatedListener (tabId, changeInfo, tab) { + if (changeInfo.status === 'loading' && tab.active) { + saveExistFlag(tab.url, existStates.notexists); + requestExists(tab.url); + } +} -browser.contextMenus.onClicked.addListener(function (info) { +function addExistCheckListeners (enable) { + if (enable) { + browser.tabs.onActivated.addListener(onTabActivatedListener); + browser.tabs.onCreated.addListener(onTabCreatedListener); + browser.tabs.onUpdated.addListener(onTabUpdatedListener); + } else { + if (browser.tab && browser.tab.onActivated.hasListener(onTabActivatedListener)) { + browser.tab.onActivated.removeListener(onTabActivatedListener); + } + if (browser.tab && browser.tabs.onCreated.hasListener(onTabCreatedListener)) { + browser.tabs.onCreated.removeListener(onTabCreatedListener); + } + if (browser.tab && browser.tabs.onUpdated.hasListener(onTabUpdatedListener)) { + browser.tabs.onUpdated.remoneListener(onTabUpdatedListener); + } + } +} + +function onContextMenusClicked (info) { switch (info.menuItemId) { case 'wallabagger-add-link': - const url = typeof (info.linkUrl) === 'string' ? info.linkUrl : info.pageUrl; - savePageToWallabag(url); - break; - case 'Unread-articles': - GotoWallabag('unread'); - break; - case 'Favorite-articles': - GotoWallabag('starred'); - break; - case 'Archived-articles': - GotoWallabag('archive'); - break; - case 'All-articles': - GotoWallabag('all'); + if (info.linkUrl.length > 0) { + savePageToWallabag(info.linkUrl, true); + } else { + savePageToWallabag(info.pageUrl, false); + } break; - case 'Tag-list': - GotoWallabag('tag'); + case 'unread': + case 'starred': + case 'archive': + case 'all': + case 'tag': + GotoWallabag(info.menuItemId); break; } -}); - -const GotoWallabag = (part) => - GetApi().then(api => browser.tabs.create({ url: `${api.data.Url}/${part}/list` })); +} -browser.commands.onCommand.addListener(function (command) { +function onCommandsCommand (command) { if (command === 'wallabag-it') { - browser.tabs.query({ 'active': true }, function (tabs) { + browser.tabs.query({ 'active': true, 'currentWindow': true }, function (tabs) { if (tabs[0] != null) { - savePageToWallabag(tabs[0].url); + savePageToWallabag(tabs[0].url, false); } }); } -}); +} -GetApi().then(api => { - api.resetDebug(); - if (api.data.AllowExistCheck) { - browser.tabs.onActivated.addListener(function (activeInfo) { - browser.browserAction.setIcon({ path: icon.default }); - const { tabId } = activeInfo; - browser.tabs.get(tabId, function (tab) { - checkExist(tab.url); - }); - }); +function postIfConnected (obj) { + portConnected && Port.postMessage(obj); + api.data.Debug && console.log(`postMessage: ${JSON.stringify(obj)}`); +} +function onPortMessage (msg) { + try { + switch (msg.request) { + case 'save': + savePageToWallabag(msg.tabUrl); + break; + case 'tags': + if (!cache.check('allTags')) { + api.GetTags() + .then(data => { + postIfConnected({ response: 'tags', tags: data }); + cache.set('allTags', data); + }); + } else { + postIfConnected({ response: 'tags', tags: cache.get('allTags') }); + } + break; + case 'saveTitle': + if (msg.articleId !== -1) { + api.SaveTitle(msg.articleId, msg.title).then(data => { + postIfConnected({ response: 'title', title: data.title }); + cache.set(msg.tabUrl, data); + }); + } else { + dirtyCacheSet(msg.tabUrl, {title: msg.title}); + } + break; + case 'deleteArticle': + if (msg.articleId !== -1) { + api.DeleteArticle(msg.articleId).then(data => { + cache.clear(msg.tabUrl); + }); + } else { + dirtyCacheSet(msg.tabUrl, {deleted: true}); + } + setIcon(icons.default); + saveExistFlag(msg.tabUrl, existStates.notexists); + break; + case 'setup': + postIfConnected({ response: 'setup', data: api.data }); + break; + case 'setup-save': + api.setsave(msg.data); + postIfConnected({ response: 'setup-save', data: api.data }); + addExistCheckListeners(msg.data.AllowExistCheck); + break; + case 'setup-gettoken': + api.setsave(msg.data); + api.GetAppToken() + .then(a => { + api.save(); + postIfConnected({ response: 'setup-gettoken', data: api.data, result: true }); + if (!cache.check('allTags')) { + api.GetTags() + .then(data => { cache.set('allTags', data); }); + } + }) + .catch(a => { + postIfConnected({ response: 'setup-gettoken', data: api.data, result: false }); + }); + break; + case 'setup-checkurl': + api.setsave(msg.data); + api.CheckUrl() + .then(a => { + postIfConnected({ response: 'setup-checkurl', data: api.data, result: true }); + }) + .catch(a => { + api.clear(); + // api.save(); + postIfConnected({ response: 'setup-checkurl', data: api.data, result: false }); + }); + break; + case 'deleteArticleTag': + if (msg.articleId !== -1) { + api.DeleteArticleTag(msg.articleId, msg.tagId).then(data => { + postIfConnected({ response: 'articleTags', tags: data.tags }); + cache.set(msg.tabUrl, data); + }); + } else { + dirtyCacheSet(msg.tabUrl, {tagList: msg.tags}); + } + break; + case 'saveTags': + if (msg.articleId !== -1) { + api.SaveTags(msg.articleId, msg.tags).then(data => { + postIfConnected({ response: 'articleTags', tags: data.tags }); + cache.set(msg.tabUrl, data); + }); + } else { + dirtyCacheSet(msg.tabUrl, {tagList: msg.tags}); + } + break; + case 'SaveStarred': + case 'SaveArchived': + if (msg.articleId !== -1) { + api[msg.request](msg.articleId, msg.value ? 1 : 0).then(data => { + postIfConnected({ response: 'action', value: {starred: data.is_starred === 1, archived: data.is_archived === 1} }); + cache.set(msg.tabUrl, data); + }); + } else { + dirtyCacheSet(msg.tabUrl, (msg.request === 'SaveStarred') ? {is_starred: msg.value ? 1 : 0} : {is_archived: msg.value ? 1 : 0}); + } + break; + default: { + console.log(`unknown request ${JSON.stringify(msg)}`); + } + } + } catch (error) { + setIcon(icons.bad); + setTimeout(function () { setIcon(icons.default); }, 5000); + postIfConnected({ response: 'error', error: error }); + } +} - browser.tabs.onCreated.addListener(function (tab) { - browser.browserAction.setIcon({ path: icon.default }); - }); +function onRuntimeConnect (port) { + Port = port; + portConnected = true; + + Port.onDisconnect.addListener(function () { portConnected = false; }); + Port.onMessage.addListener(onPortMessage); +} + +function addListeners () { + browser.contextMenus.onClicked.addListener(onContextMenusClicked); + browser.commands.onCommand.addListener(onCommandsCommand); + browser.runtime.onConnect.addListener(onRuntimeConnect); +} + +function setIcon (icon) { + browser.browserAction.setIcon({ path: icon }); +} + +function dirtyCacheSet (key, obj) { + dirtyCache.set(key, Object.assign(dirtyCache.check(key) ? dirtyCache.get(key) : {}, obj)); + dirtyCache.set(key, Object.assign(dirtyCache.check(key) ? dirtyCache.get(key) : {}, { id: -1, url: key })); +} - browser.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { - if (changeInfo.status === 'loading' && tab.active) { - requestExists(tab.url); +function applyDirtyCacheLight (key, data) { + if (dirtyCache.check(key)) { + const dirtyObject = dirtyCache.get(key); + if (!dirtyObject.deleted) { + if ((dirtyObject.title !== undefined) || (dirtyObject.is_archived !== undefined) || + (dirtyObject.is_starred !== undefined) || (dirtyObject.tagList !== undefined)) { + data.changed = true; } + data.title = dirtyObject.title !== undefined ? dirtyObject.title : data.title; + data.is_archived = dirtyObject.is_archived !== undefined ? dirtyObject.is_archived : data.is_archived; + data.is_starred = dirtyObject.is_starred !== undefined ? dirtyObject.is_starred : data.is_starred; + data.tagList = + (dirtyObject.tagList !== undefined ? dirtyObject.tagList.split(',') : []) + .concat(data.tags.map(t => t.label)) + .filter((v, i, a) => a.indexOf(v) === i) + .join(','); + } else { + data.deleted = true; + } + } + return data; +} + +function applyDirtyCacheReal (key, data) { + if (dirtyCache.check(key)) { + const dirtyObject = dirtyCache.get(key); + if (dirtyObject.deleted !== undefined) { + return api.DeleteArticle(data.id).then(a => { dirtyCache.clear(key); }); + } else { + if (data.changed !== undefined) { + return api.PatchArticle(data.id, { title: data.title, starred: data.is_starred, archive: data.is_archived, tags: data.tagList }) + .then(data => cache.set(key, data)) + .then(a => { dirtyCache.clear(key); }); + } + } + } + return data; +} +function cutArticle (data) { + return Object.assign({}, { + id: data.id, + is_starred: data.is_starred, + is_archived: data.is_archived, + title: data.title, + url: data.url, + tags: data.tags, + domain_name: data.domain_name, + preview_picture: data.preview_picture + }); +} + +function moveToDirtyCache (url) { + if (cache.check(url)) { + let art = cache.get(url); + // api.data.Debug && console.log(`article to move to dirtyCache ${JSON.stringify(art)}`); + dirtyCacheSet(url, { + title: art.title, + tagList: art.tags.map(tag => tag.label).join(','), + is_archived: art.is_archived, + is_starred: art.is_starred }); + cache.clear(url); + } +} + +function savePageToWallabag (url, resetIcon) { + if (isServicePage(url)) { + return; + } + // if WIP and was some dirty changes, return dirtyCache + let exists = existCache.check(url) ? existCache.get(url) : existStates.notexists; + if (exists === existStates.wip) { + if (dirtyCache.check(url)) { + let dc = dirtyCache.get(url); + postIfConnected({ response: 'article', article: cutArticle(dc) }); + } + return; + } - browser.runtime.onMessage.addListener(function (request, sender, sendResponse) { - const {type, url} = request; - switch (type) { - case 'begin' : - browser.browserAction.setIcon({ path: icon.wip }); - break; - case 'success' : - browser.browserAction.setIcon({ path: icon.good }); - saveExistFlag(url, true); - break; - case 'error' : - browser.browserAction.setIcon({ path: icon.bad }); - setTimeout(function () { browser.browserAction.setIcon({ path: icon.default }); }, 5000); - break; + // if article was saved, return cache + if (cache.check(url)) { + postIfConnected({ response: 'article', article: cutArticle(cache.get(url)) }); + // check if article was deleted via web interface + requestExists(url) + .then(exists => { + if (!exists) { + moveToDirtyCache(url); + savePageToWallabag(url, resetIcon); } }); - }; -}); + return; + } -const checkExist = (url) => { - if (isServicePage(url)) { return; } - existWasChecked(url) - .then(wasChecked => { - if (wasChecked) { - getExistFlag(url) - .then(exists => { - if (exists) { - browser.browserAction.setIcon({ path: icon.good }); + // real saving + setIcon(icons.wip); + existCache.set(url, existStates.wip); + postIfConnected({ response: 'info', text: 'Saving the page to wallabag ...' }); + api.SavePage(url) + .then(data => applyDirtyCacheLight(url, data)) + .then(data => { + if (!data.deleted) { + setIcon(icons.good); + postIfConnected({ response: 'article', article: cutArticle(data) }); + cache.set(url, data); + saveExistFlag(url, existStates.exists); + if (api.data.AllowExistCheck === null || resetIcon) { + setTimeout(function () { setIcon(icons.default); }, 5000); + } + } else { + cache.clear(url); } + return data; + }) + .then(data => applyDirtyCacheReal(url, data)) + .catch(error => { + setIcon(icons.bad); + setTimeout(function () { setIcon(icons.default); }, 5000); + saveExistFlag(url, existStates.notexists); + throw error; }); - } else { - requestExists(url); - } - }); }; -const requestExists = (url) => - GetApi() - .then(api => api.EntryExists(url)) - .then(data => { - const existsIcon = data.exists ? icon.good : icon.default; - browser.browserAction.setIcon({ path: existsIcon }); - saveExistFlag(url, data.exists); - }); +const GotoWallabag = (part) => api.checkParams() && browser.tabs.create({ url: `${api.data.Url}/${part}/list` }); -const saveExistFlag = (url, exists) => { - browser.storage.local.set({[btoa(url)]: JSON.stringify(exists)}); +const checkExist = (url) => { + if (isServicePage(url)) { return; } + if (existCache.check(url)) { + const existsFlag = existCache.get(url); + if (existsFlag === existStates.exists) { + setIcon(icons.good); + } + if (existsFlag === existStates.wip) { + setIcon(icons.wip); + } + } else { + requestExists(url); + } }; -const getExistFlag = (url) => - new Promise((resolve, reject) => { - browser.storage.local.get(btoa(url), function (item) { - resolve(JSON.parse(item[btoa(url)])); - }); - }); - -const existWasChecked = (url) => - new Promise((resolve, reject) => { - browser.storage.local.get(null, function (items) { - resolve(btoa(url) in items); +const requestExists = (url) => + api.EntryExists(url) + .then(data => { + let icon = icons.default; + if (data.exists) { + icon = icons.good; + } + setIcon(icon); + saveExistFlag(url, data.exists ? existStates.exists : existStates.notexists); + return data.exists; }); - }); -// const slash = (url) => url.match(/(\w+)\.html?$/) ? url : url.replace(/\/?$/, '/'); +const saveExistFlag = (url, exists) => { + existCache.set(url, exists); +}; const isServicePage = (url) => /^(chrome|about|browser):(.*)/.test(url); diff --git a/wallabagger/js/fetch-api.js b/wallabagger/js/fetch-api.js index 223ba2c..91369b5 100644 --- a/wallabagger/js/fetch-api.js +++ b/wallabagger/js/fetch-api.js @@ -3,13 +3,16 @@ var FetchApi = function () {}; FetchApi.prototype = { getRequestOptions: function (method, token, content) { - return { + let options = { method: method, headers: this.getHeaders(token), mode: 'cors', - cache: 'default', - body: content + cache: 'default' }; + if (content !== '') { + options = Object.assign(options, { body: JSON.stringify(content) }); + } + return options; }, getHeaders: function (token) { @@ -44,9 +47,9 @@ FetchApi.prototype = { Fetch: function (url, method, token, content) { let options = this.getRequestOptions(method, token, content); - return this.isEdge + return this.isEdge() ? this.xhrFetch(url, options) - : this.apiFetchurl(url, options); + : this.apiFetch(url, options); }, apiFetch: (url, options) => fetch(url, options).then(response => response.ok ? response.json() : response.json().then(err => Promise.reject(err))), diff --git a/wallabagger/js/options.js b/wallabagger/js/options.js index 5b2ce11..20606a6 100644 --- a/wallabagger/js/options.js +++ b/wallabagger/js/options.js @@ -12,15 +12,7 @@ var OptionsController = function () { this.userLogin_ = document.getElementById('userlogin-input'); this.userPassword_ = document.getElementById('userpassword-input'); this.getAppTokenButton_ = document.getElementById('getapptoken-button'); - - // this.appTokenInput_ = document.getElementById("apptoken-input"); this.tokenLabel_ = document.getElementById('apitoken-label'); - // this.checkTokenButton_ = document.getElementById("checktoken-button"); - - // this.refrTokenInput_ = document.getElementById("refreshtoken-input"); - // this.refreshTokenButton_ = document.getElementById("refreshtoken-button"); - - // this.tokenExpiresInput = document.getElementById("tokenexpired-input"); this.allowSpaceCheck = document.getElementById('allow-space-checkbox'); this.allowExistCheck = document.getElementById('allow-exist-checkbox'); this.debugEl = document.getElementById('debug'); @@ -28,8 +20,6 @@ var OptionsController = function () { this.loadFromFileButton = document.getElementById('loadFromFile-button'); this.clearButton = document.getElementById('clear-button'); this.openFileDialog = document.getElementById('openFile-dialog'); - // this.saveToLocalButton = document.getElementById("saveToLocal-button"); - // this.loadFromLocalButton = document.getElementById("loadFromLocal-button"); this.httpsMessage = document.getElementById('https-message'); this.httpsButton = document.getElementById('https-button'); this.addListeners_(); @@ -40,7 +30,6 @@ OptionsController.prototype = { protocolCheck_: null, protocolLabel_: null, wallabagurlinput_: null, - // savebutton_: null, checkurlbutton_: null, versionLabel_: null, _debug: false, @@ -51,18 +40,11 @@ OptionsController.prototype = { userLogin_: null, userPassword_: null, getAppTokenButton_: null, - // appTokenInput_: null, tokenLabel_: null, - // checkTokenButton_: null, - // refrTokenInput_: null, - // refreshTokenButton_: null, - // tokenExpiresInput: null, saveToFileButton: null, loadFromFileButton: null, openFileDialog: null, clearButton: null, - // saveToLocalButton: null, - // loadFromLocalButton: null, allowSpaceCheck: null, allowExistCheck: null, @@ -70,24 +52,19 @@ OptionsController.prototype = { httpsButton: null, httpsMessage: null, - api: null, + data: null, + port: null, addListeners_: function () { this.allowSpaceCheck.addEventListener('click', this.allowSpaceCheckClick.bind(this)); this.allowExistCheck.addEventListener('click', this.allowExistCheckClick.bind(this)); this.debugEl.addEventListener('click', this.debugClick.bind(this)); this.protocolCheck_.addEventListener('click', this.handleProtocolClick.bind(this)); - // this.savebutton_.addEventListener('click', this.saveClick_.bind(this)); this.checkurlbutton_.addEventListener('click', this.checkUrlClick.bind(this)); this.getAppTokenButton_.addEventListener('click', this.getAppTokenClick.bind(this)); - // this.checkTokenButton_.addEventListener('click', this.checkTokenClick.bind(this)); - // this.refreshTokenButton_.addEventListener('click', this.refreshTokenClick.bind(this)); this.saveToFileButton.addEventListener('click', this.saveToFileClick.bind(this)); this.loadFromFileButton.addEventListener('click', this.loadFromFileClick.bind(this)); this.clearButton.addEventListener('click', this.clearClick.bind(this)); - // this.saveToLocalButton.addEventListener('click', this.saveToLocal.bind(this)); - // this.loadFromLocalButton.addEventListener('click', this.loadFromLocal.bind(this)); - this.openFileDialog.addEventListener('change', this.loadFromFile.bind(this)); this.httpsButton.addEventListener('click', this.httpsButtonClick.bind(this)); }, @@ -95,16 +72,6 @@ OptionsController.prototype = { httpsButtonClick: function () { this.httpsMessage.classList.remove('active'); }, - // saveToLocal: function () { - // localStorage.setItem("wallabagger", JSON.stringify(this.api.data)); - // }, - - // loadFromLocal: function () { - // let obj = JSON.parse(localStorage.getItem("wallabagger")); - // this.api.set(obj); - // this.setFields(obj); - // this.api.save(); - // }, clearClick: function () { this.userLogin_.value = ''; @@ -128,20 +95,20 @@ OptionsController.prototype = { fileReader.onload = function (fileLoadedEvent) { let textFromFileLoaded = fileLoadedEvent.target.result; let obj = JSON.parse(textFromFileLoaded); - if(this.api.data.Debug === true) { + if (this.debugEl.checked) { console.log(textFromFileLoaded); console.log(obj); } - this.api.set(obj); - this.setFields(obj); - this.api.save(); + this.data = Object.assign({}, obj); + this.setFields(); + this.port.postMessage({request: 'setup-save', data: this.data}); }.bind(this); fileReader.readAsText(fileToLoad, 'UTF-8'); } }, saveToFileClick: function () { - let textToSave = JSON.stringify(this.api.data); + let textToSave = JSON.stringify(this.data); let textToSaveAsBlob = new Blob([textToSave], { type: 'text/plain' }); let textToSaveAsURL = window.URL.createObjectURL(textToSaveAsBlob); let fileNameToSaveAs = 'wallabag.json'; @@ -156,14 +123,14 @@ OptionsController.prototype = { }, allowSpaceCheckClick: function (e) { - this.api.set({ AllowSpaceInTags: this.allowSpaceCheck.checked }); - this.api.save(); + Object.assign(this.data, { AllowSpaceInTags: this.allowSpaceCheck.checked }); + this.port.postMessage({request: 'setup-save', data: this.data}); }, allowExistCheckClick: function (e) { if (this.protocolCheck_.checked) { - this.api.set({ AllowExistCheck: this.allowExistCheck.checked }); - this.api.save(); + Object.assign(this.data, { AllowExistCheck: this.allowExistCheck.checked }); + this.port.postMessage({request: 'setup-save', data: this.data}); } else { this.allowExistCheck.checked = false; this.httpsMessage.classList.add('active'); @@ -171,21 +138,15 @@ OptionsController.prototype = { }, debugClick: function () { - this.api.set({ Debug: this.debugEl.checked }); - this.api.save(); + Object.assign(this.data, { Debug: this.debugEl.checked }); + this.port.postMessage({request: 'setup-save', data: this.data}); }, wallabagApiTokenGot: function () { - this.api.save(); - this._green(this.clientId_); this._green(this.clientSecret_); this._green(this.userLogin_); this._green(this.userPassword_); - // this.appTokenInput_.value = this.api.data.ApiToken; - // this.refrTokenInput_.value = this.api.data.RefreshToken; - // let expireDate = this.api.data.ExpireDateMs; - // this.tokenExpiresInput.value = new Date( expireDate ); this.tokenLabel_.textContent = 'Granted'; }, @@ -194,10 +155,6 @@ OptionsController.prototype = { this._red(this.clientSecret_); this._red(this.userLogin_); this._red(this.userPassword_); - // this.appTokenInput_.value = ''; - // this.refrTokenInput_.value = ''; - // chrome.storage.local.set({ 'wallabagapptoken': '' }); - // chrome.storage.local.set({ 'wallabagrefreshtoken': '' }); this.tokenLabel_.textContent = 'Not granted'; }, @@ -207,21 +164,18 @@ OptionsController.prototype = { if (this.clientId_.value === '') { this._red(this.clientId_); } else { - // chrome.storage.local.set({ 'wallabagclientid': this.clientId_.value }); this._green(this.clientId_); } if (this.clientSecret_.value === '') { this._red(this.clientSecret_); } else { - // chrome.storage.local.set({ 'wallabagclientsecret': this.clientSecret_.value }); this._green(this.clientSecret_); } if (this.userLogin_.value === '') { this._red(this.userLogin_); } else { - // chrome.storage.local.set({ 'wallabaguserlogin': this.userLogin_.value }); this._green(this.userLogin_); } @@ -232,24 +186,14 @@ OptionsController.prototype = { } if (this.clientId_.value !== '' && this.clientSecret_.value !== '' && this.userLogin_.value && this.userPassword_.value) { - // wallabagGetAppToken: wallabagGetAppToken: function(aUrl, clientId, clientSecret, userId, userPassword){ - this.api.set({ + Object.assign(this.data, { Url: this.protocolLabel_.textContent + this.wallabagurlinput_.value, ClientId: this.clientId_.value, ClientSecret: this.clientSecret_.value, UserLogin: this.userLogin_.value, UserPassword: this.userPassword_.value - } - ); - this.api.GetAppToken(this.userPassword_.value) - .then(data => { - // console.log('wallabag api token get: ' + JSON.stringify(data)); - this.wallabagApiTokenGot(); - }) - .catch(() => { - // console.log('wallabag api token get error: ' + error); - this.wallabagApiTokenNotGot(); - }); + }); + this.port.postMessage({request: 'setup-gettoken', data: this.data}); } }, @@ -286,12 +230,9 @@ OptionsController.prototype = { }, wallabagUrlChecked: function () { - if (this.api.data.ApiVersion !== '') { - this.versionLabel_.textContent = this.api.data.ApiVersion; - // chrome.storage.local.set({ 'wallabagapiversion': this.api.data.ApiVersion }); - this.api.save(); - if (this.api.data.ApiVersion.split('.')[0] === '2') { - // chrome.storage.local.set({ 'wallabagchecked': 'OK' }); + if (this.data.ApiVersion !== '') { + this.versionLabel_.textContent = this.data.ApiVersion; + if (this.data.ApiVersion.split('.')[0] === '2') { this.checkedLabel_.textContent = 'OK'; this._green(this.wallabagurlinput_); this._show(this.tokenSection_); @@ -300,8 +241,6 @@ OptionsController.prototype = { }, wallabagUrlNotChecked: function () { - this.api.clear(); - this.api.save(); this._red(this.wallabagurlinput_); this._hide(this.tokenSection_); this.checkedLabel_.textContent = 'Not checked'; @@ -312,24 +251,20 @@ OptionsController.prototype = { e.preventDefault(); if (this.wallabagurlinput_.value !== '') { - this.api.set({ Url: this.protocolLabel_.textContent + this.wallabagurlinput_.value }); - - this.api.CheckUrl() - .then(data => { - // console.log('wallabag url checked: ' + JSON.stringify(data)); - this.wallabagUrlChecked(); - }) - .catch(() => { - // console.log('wallabag url check error: ' + error); - this.wallabagUrlNotChecked(); - }); + this.wallabagurlinput_.value = this._urlSanitized(this.wallabagurlinput_.value); + Object.assign(this.data, { Url: this.protocolLabel_.textContent + this.wallabagurlinput_.value }); + this.port.postMessage({request: 'setup-checkurl', data: this.data}); } }, - setFields: function (data) { + _urlSanitized: function (url) { + return url.replace(/\/$/, ''); + }, + + setFields: function () { const re = /^(http|https):\/\/(.*)/; - if (re.test(data.Url)) { - const res = re.exec(data.Url); + if (re.test(this.data.Url)) { + const res = re.exec(this.data.Url); this.protocolCheck_.checked = (res[1] === 'https'); this.protocolLabel_.textContent = res[1] + '://'; this.wallabagurlinput_.value = res[2]; @@ -339,44 +274,84 @@ OptionsController.prototype = { this._show(this.tokenSection_); } - if (data.ApiVersion) { - this.versionLabel_.textContent = data.ApiVersion; - if (data.ApiVersion.split('.')[0] === '2') { + if (this.data.ApiVersion) { + this.versionLabel_.textContent = this.data.ApiVersion; + if (this.data.ApiVersion.split('.')[0] === '2') { this.checkedLabel_.textContent = 'OK'; this._green(this.wallabagurlinput_); this._show(this.tokenSection_); } } - this.clientId_.value = data.ClientId || ''; - this.clientSecret_.value = data.ClientSecret || ''; - this.userLogin_.value = data.UserLogin || ''; - this.userPassword_.value = data.UserPassword || ''; + this.clientId_.value = this.data.ClientId || ''; + this.clientSecret_.value = this.data.ClientSecret || ''; + this.userLogin_.value = this.data.UserLogin || ''; + this.userPassword_.value = this.data.UserPassword || ''; - if (data.ApiToken) { + if (this.data.ApiToken) { this.tokenLabel_.textContent = 'Granted'; } - if (this.api.data.ExpireDateMs && this.api.expired) { + if (this.data.ExpireDateMs && this.expired) { this.tokenLabel_.textContent = 'Expired'; } - this.allowSpaceCheck.checked = data.AllowSpaceInTags; - this.allowExistCheck.checked = data.AllowExistCheck; - this.debugEl.checked = data.Debug; + this.allowSpaceCheck.checked = this.data.AllowSpaceInTags; + this.allowExistCheck.checked = this.data.AllowExistCheck; + this.debugEl.checked = this.data.Debug; }, - init: function () { - this.api = new WallabagApi(); + expired: function () { + return (this.data.ExpireDateMs != null) && (Date.now() > this.data.ExpireDateMs); + }, + + messageListener: function (msg) { + switch (msg.response) { + case 'setup': + this.data = Object.assign({}, msg.data); + this.setFields(); + break; + case 'setup-checkurl': + Object.assign(this.data, msg.data); + if (msg.result) { + this.wallabagUrlChecked(); + } else { + this.wallabagUrlNotChecked(); + } + break; + case 'setup-gettoken': + Object.assign(this.data, msg.data); + if (msg.result) { + this.wallabagApiTokenGot(); + } else { + this.wallabagApiTokenNotGot(); + } + break; + case 'setup-save': + Object.assign(this.data, msg.data); + if (this.data.Debug) { + console.log(`setup saved: ${msg.data}`); + } + break; + default: + if (this.data.Debug) { + console.log(`unknown message: ${msg}`); + } + }; + }, - this.api.init().then(data => { - this.setFields(data); - }).catch(data => { }); + init: function () { + this.port = browser.runtime.connect({name: 'setup'}); + this.port.onMessage.addListener(this.messageListener.bind(this)); + this.port.postMessage({request: 'setup'}); } }; document.addEventListener('DOMContentLoaded', function () { + if (typeof (browser) === 'undefined' && typeof (chrome) === 'object') { + browser = chrome; + } const PC = new OptionsController(); PC.init(); }); diff --git a/wallabagger/js/popup.js b/wallabagger/js/popup.js index 884ddd1..07edef7 100644 --- a/wallabagger/js/popup.js +++ b/wallabagger/js/popup.js @@ -1,4 +1,3 @@ -/* globals WallabagApi */ var PopupController = function () { this.mainCard = document.getElementById('main-card'); this.errorToast = document.getElementById('error-toast'); @@ -22,7 +21,7 @@ var PopupController = function () { this.cardHeader = document.getElementById('card-header'); this.cardBody = document.getElementById('card-body'); this.starredIcon = document.getElementById('starred-icon'); - + this.articleId = -1; this.addListeners(); }; @@ -31,6 +30,7 @@ PopupController.prototype = { mainCard: null, errorToast: null, infoToast: null, + apiUrl: null, entryUrl: null, cardTitle: null, cardImage: null, @@ -38,13 +38,7 @@ PopupController.prototype = { tagsInput: null, tagsAutoCompleteList: null, - wallabagUrl: null, - appToken: null, - refreshToken: null, - tokenExpireDate: null, - articleId: null, - api: null, editIcon: null, saveTitleButton: null, cancelTitleButton: null, @@ -61,12 +55,17 @@ PopupController.prototype = { starredIcon: null, articleTags: [], + allTags: [], dirtyTags: [], foundTags: [], starred: false, archived: false, tmpTagId: 0, + AllowSpaceInTags: false, + tabUrl: null, + + port: null, getSaveHtml: function (param) { let map = { '&': '&', '\'': ''', '"': '"', '<': '<', '>': '>' }; @@ -74,8 +73,8 @@ PopupController.prototype = { }, addListeners: function () { - this.cardTitle.addEventListener('click', this.cardTitleClick); - this.entryUrl.addEventListener('click', this.entryUrlClick); + this.cardTitle.addEventListener('click', this.openUrl); + this.entryUrl.addEventListener('click', this.openUrl); this.editIcon.addEventListener('click', this.editIconClick.bind(this)); this.saveTitleButton.addEventListener('click', this.saveTitleClick.bind(this)); this.cancelTitleButton.addEventListener('click', this.cancelTitleClick.bind(this)); @@ -94,17 +93,10 @@ PopupController.prototype = { onIconClick: function (event) { event.preventDefault(); - this.toggleIcon(event.currentTarget); - let actionKey = false; - if (event.currentTarget.id === 'starred-icon') { - actionKey = 'starred'; - this.toggleAction(actionKey, 'SaveStarred'); - } - if (event.currentTarget.id === 'archived-icon') { - actionKey = 'archived'; - this.toggleAction(actionKey, 'SaveArchived'); - } - this.setIconTitle(event.currentTarget, !this[actionKey]); + let icon = event.currentTarget; + this.toggleIcon(icon); + this.toggleAction(icon); + this.setIconTitle(icon); this.tagsInput.focus(); }, @@ -118,22 +110,17 @@ PopupController.prototype = { icon.dataset.isset = JSON.stringify(currentState); }, - setIconTitle: function (icon, state) { - icon.title = state ? icon.dataset.unseticonTitle : icon.dataset.seticonTitle; + setIconTitle: function (icon) { + icon.title = icon.dataset.isset ? icon.dataset.unseticonTitle : icon.dataset.seticonTitle; }, - toggleAction: function (actionVar, actionApi) { - this.api[actionApi](this.articleId, !this[actionVar]).then(d => { - this[actionVar] = !this[actionVar]; - }).catch(error => { - this.hide(this.infoToast); - this.showError(error.message); - }); + toggleAction: function (icon) { + this.port.postMessage({request: icon.dataset.apicall, articleId: this.articleId, value: icon.dataset.isset, tabUrl: this.tabUrl}); }, onTagsInputKeyUp: function (event) { if (event.key === 'ArrowRight') this.addFirstFoundTag(); - if ((event.key === 'Enter') && (this.api.data.AllowSpaceInTags)) { + if ((event.key === 'Enter') && (this.AllowSpaceInTags)) { this.addTag(this.tmpTagId, this.tagsInput.value.trim()); }; }, @@ -170,24 +157,14 @@ PopupController.prototype = { label: taglabel, slug: taglabel }); - this.tagsInputContainer.insertBefore( this.createTagChip(tagid, taglabel), this.tagsInput); - this.enableTagsInput(); - if (tagid <= 0) { this.tmpTagId = this.tmpTagId - 1; } - - this.api.SaveTags(this.articleId, this.getSaveHtml(this.getTagsStr())) - .then(data => this.loadArticleTags(data)) - .catch(error => { - this.hide(this.infoToast); - this.showError(error.message); - }); - + this.port.postMessage({request: 'saveTags', articleId: this.articleId, tags: this.getSaveHtml(this.getTagsStr()), tabUrl: this.tabUrl}); this.checkAutocompleteState(); } else { this.tagsInput.placeholder = 'Duplicate tag!!!'; @@ -199,19 +176,11 @@ PopupController.prototype = { deleteTag: function (ev) { let chip = ev.currentTarget.parentNode; let tagid = chip.dataset.tagid; - this.dirtyTags = this.dirtyTags.filter(tag => tag.id !== tagid); - chip.parentNode.removeChild(chip); - - this.api.DeleteArticleTag(this.articleId, tagid) - .then(data => this.loadArticleTags(data)) - .catch(error => { - this.hide(this.infoToast); - this.showError(error.message); - }); - + this.port.postMessage({request: 'deleteArticleTag', articleId: this.articleId, tagId: tagid, tags: this.getSaveHtml(this.getTagsStr()), tabUrl: this.tabUrl}); this.checkAutocompleteState(); + this.tagsInput.focus(); }, getTagsStr: function () { @@ -229,7 +198,7 @@ PopupController.prototype = { }, findTags: function (search) { - this.foundTags = this.api.tags.filter(tag => (this.articleTags.concat(this.dirtyTags).map(t => t.id).indexOf(tag.id) === -1) && + this.foundTags = this.allTags.filter(tag => (this.articleTags.concat(this.dirtyTags).map(t => t.id).indexOf(tag.id) === -1) && (this.tagsInput.value.length >= 3 && tag.label.toUpperCase().indexOf(this.tagsInput.value.toUpperCase()) !== -1) || (this.tagsInput.value === tag.label) && @@ -255,7 +224,7 @@ PopupController.prototype = { if (this.tagsInput.value !== '') { const lastChar = this.tagsInput.value.slice(-1); const value = this.tagsInput.value.slice(0, -1); - if ((lastChar === ',') || (lastChar === ';') || ((lastChar === ' ') && (!this.api.data.AllowSpaceInTags))) { + if ((lastChar === ',') || (lastChar === ';') || ((lastChar === ' ') && (!this.AllowSpaceInTags))) { if (value !== '') { this.addTag(this.tmpTagId, this.tagsInput.value.slice(0, -1)); } @@ -269,15 +238,9 @@ PopupController.prototype = { deleteArticle: function (e) { e.preventDefault(); - this.api.DeleteArticle(this.articleId) - .then(data => { - this.deleteConfirmationCard.classList.remove('active'); - window.close(); - }).catch(error => { - this.hide(this.infoToast); - this.showError(error.message); - }); - // .catch(error=>{ console.log(error) }); + this.port.postMessage({ request: 'deleteArticle', articleId: this.articleId, tabUrl: this.tabUrl }); + this.deleteConfirmationCard.classList.remove('active'); + window.close(); }, cancelDelete: function (e) { @@ -299,17 +262,10 @@ PopupController.prototype = { saveTitleClick: function (e) { e.preventDefault(); + this.port.postMessage({request: 'saveTitle', articleId: this.articleId, title: this.getSaveHtml(this.titleInput.value), tabUrl: this.tabUrl}); this.cardTitle.textContent = this.titleInput.value; - this.api.SaveTitle(this.articleId, this.getSaveHtml(this.cardTitle.textContent)) - .then(data => { - this.hide(this.cardBody); - this.show(this.cardHeader); - }) - .catch(error => { - this.hide(this.infoToast); - this.showError(error); - }); - this.tagsInput.focus(); + this.hide(this.cardBody); + this.show(this.cardHeader); }, cancelTitleClick: function (e) { @@ -319,21 +275,15 @@ PopupController.prototype = { this.tagsInput.focus(); }, - cardTitleClick: function (e) { + openUrl: function (e) { e.preventDefault(); + browser.tabs.create({url: this.href}); window.close(); - chrome.tabs.create({url: this.href}); - }, - - entryUrlClick: function (e) { - e.preventDefault(); - window.close(); - chrome.tabs.create({url: this.href}); }, activeTab: function () { return new Promise((resolve, reject) => { - chrome.tabs.query({ 'active': true, 'currentWindow': true }, function (tabs) { + browser.tabs.query({ 'active': true, 'currentWindow': true }, function (tabs) { if (tabs[0] != null) { return resolve(tabs[0]); } else { @@ -343,18 +293,18 @@ PopupController.prototype = { }); }, - _createContainerEl: function(id, label) { + _createContainerEl: function (id, label) { const container = document.createElement('div'); - container.setAttribute("class", "chip-sm"); - container.setAttribute("data-tagid", id); - container.setAttribute("data-taglabel", label); + container.setAttribute('class', 'chip-sm'); + container.setAttribute('data-tagid', id); + container.setAttribute('data-taglabel', label); container.appendChild(this._createTagEl(label)); return container; }, _createTagEl: (label) => { const tag = document.createElement('span'); - tag.setAttribute("class", "chip-name"); + tag.setAttribute('class', 'chip-name'); tag.textContent = label; return tag; }, @@ -363,7 +313,7 @@ PopupController.prototype = { const container = this._createContainerEl(id, label); const button = document.createElement('button'); - button.setAttribute("class", "btn btn-clear"); + button.setAttribute('class', 'btn btn-clear'); button.addEventListener('click', this.deleteTag.bind(this)); container.appendChild(button); @@ -374,7 +324,7 @@ PopupController.prototype = { createTagChipNoClose: function (id, label) { const container = this._createContainerEl(id, label); container.addEventListener('click', this.onFoundTagChipClick.bind(this)); - container.setAttribute("style", "cursor: pointer;"); + container.setAttribute('style', 'cursor: pointer;'); return container; }, @@ -393,86 +343,101 @@ PopupController.prototype = { }); }, - loadArticleTags: function (data) { - return this.api.GetArticleTags(this.articleId).then(data => this.createTags(data)); - }, + setArticle: function (data) { + this.articleId = data.id; + if (data.title !== undefined) { this.cardTitle.textContent = data.title; } + this.cardTitle.href = data.id === -1 ? '#' : `${this.apiUrl}/view/${this.articleId}`; + if (data.domain_name !== undefined) { this.entryUrl.textContent = data.domain_name; } + this.entryUrl.href = data.url; - init: function () { - browser.runtime.sendMessage({type: 'begin'}); - this.api = new WallabagApi(); - this.showInfo('Loading wallabag API...'); - - let apiAuthorised = this.api.init() - .then(data => { - if (this.api.needNewAppToken()) { - this.showInfo('Obtaining wallabag api token...'); - return this.api.GetAppToken(); - } - return 'OK'; - }) - .catch(error => { - this.hide(this.infoToast); - this.showError(error.message); - browser.runtime.sendMessage({type: 'error'}); - throw error; + if (typeof (data.preview_picture) === 'string' && + data.preview_picture.length > 0 && + data.preview_picture.indexOf('http') === 0) { + this.cardImage.src = data.preview_picture; + } else { + this.hide(this.cardImage); + } + + if (data.is_starred !== undefined) { this.starred = data.is_starred; } + this.setIconTitle(this.starredIcon, this.starred); + if (this.starred) { + this.toggleIcon(this.starredIcon); + } + if (data.is_archived !== undefined) { this.archived = data.is_archived; } + this.setIconTitle(this.archivedIcon, this.archived); + if (this.archived) { + this.toggleIcon(this.archivedIcon); + } + if (data.id === -1 && data.tagList !== undefined) { + this.dirtyTags = data.tagList.split(',').map(taglabel => { + this.tmpTagId = this.tmpTagId - 1; + return { + id: this.tmpTagId, + label: taglabel, + slug: taglabel + }; }); + this.createTags([]); + } else { + this.createTags(data.tags); + } + this.enableTagsInput(); + }, - apiAuthorised.then(data => this.activeTab()) - .then(tab => { - this.showInfo('Saving the page to wallabag ...'); - if(this.api.data.Debug === true) { - console.log(tab.url); - } - return this.api.SavePage(tab.url); - }) - .then(data => { - if(this.api.data.Debug === true) { - console.log(data); - } - if (data != null) { - this.articleId = data.id; - this.cardTitle.textContent = data.title; - this.cardTitle.href = `${this.api.data.Url}/view/${this.articleId}`; - this.entryUrl.textContent = data.domain_name; - this.entryUrl.href = data.url; - - if (typeof (data.preview_picture) === 'string' && - data.preview_picture.length > 0 && - data.preview_picture.indexOf('http') === 0) { - this.cardImage.src = data.preview_picture; - } else { - this.hide(this.cardImage); - } - - this.starred = data.is_starred; - this.setIconTitle(this.starredIcon, this.starred); - if (this.starred) { - this.toggleIcon(this.starredIcon); - } - this.archived = data.is_archived; - this.setIconTitle(this.archivedIcon, this.archived); - if (this.archived) { - this.toggleIcon(this.archivedIcon); - } - } + messageListener: function (msg) { + switch (msg.response) { + case 'info': + this.showInfo(msg.text); + break; + case 'error': this.hide(this.infoToast); - this.show(this.mainCard); - browser.runtime.sendMessage({type: 'success', url: data.url}); - }) - .then(data => this.loadArticleTags(data)) - .then(data => this.enableTagsInput()) - .catch(error => { + this.hide(this.mainCard); + this.showError(msg.error.message); + break; + case 'article': this.hide(this.infoToast); - this.showError(error.message); - browser.runtime.sendMessage({type: 'error'}); - }); + if (msg.article !== null) { + this.setArticle(msg.article); + this.hide(this.infoToast); + this.show(this.mainCard); + } else { + this.showError('Error: empty data!'); + } + break; + case 'tags': + this.allTags = msg.tags; + break; + case 'title': + this.cardTitle.innerHTML = msg.title; + break; + case 'setup': + this.AllowSpaceInTags = msg.data.AllowSpaceInTags; + this.apiUrl = msg.data.Url; + break; + case 'articleTags': + this.createTags(msg.tags); + break; + case 'action': + this.archived = msg.value.archived; + this.starred = msg.value.starred; + break; + default: + console.log(`unknown message: ${msg}`); + }; + }, - // loading all tags - apiAuthorised.then(data => this.api.GetTags()) - .catch(error => { - this.hide(this.infoToast); - this.showError(error.message); - }); + init: function () { + this.port = browser.runtime.connect({name: 'popup'}); + this.port.onMessage.addListener(this.messageListener.bind(this)); + this.port.postMessage({request: 'setup'}); + this.activeTab().then(tab => { + this.tabUrl = tab.url; + this.cardTitle.textContent = tab.title; + this.entryUrl.textContent = /(\w+:\/\/)([^/]+)\/(.*)/.exec(tab.url)[2]; + this.enableTagsInput(); + this.port.postMessage({request: 'save', tabUrl: tab.url}); + }); + this.port.postMessage({request: 'tags'}); }, showError: function (infoString) { diff --git a/wallabagger/js/wallabag-api.js b/wallabagger/js/wallabag-api.js index 8ece262..93fee6d 100644 --- a/wallabagger/js/wallabag-api.js +++ b/wallabagger/js/wallabag-api.js @@ -29,18 +29,18 @@ WallabagApi.prototype = { return this.load(); }, - resetDebug: function() { + resetDebug: function () { this.data.Debug = this.defaultValues.Debug; this.save(); }, save: function () { - chrome.storage.local.set({ 'wallabagdata': this.data }); + browser.storage.local.set({ 'wallabagdata': this.data }); }, load: function () { return new Promise((resolve, reject) => { - chrome.storage.local.get('wallabagdata', result => { + browser.storage.local.get('wallabagdata', result => { if (result.wallabagdata != null) { this.set(result.wallabagdata); if (this.checkParams()) { @@ -67,7 +67,11 @@ WallabagApi.prototype = { }, checkParams: function () { - return ((this.data.ClientId !== '') && + return ((this.data.ClientId !== null) && + (this.data.ClientSecret !== null) && + (this.data.userLogin !== null) && + (this.data.UserPassword !== null) && + (this.data.ClientId !== '') && (this.data.ClientSecret !== '') && (this.data.userLogin !== '') && (this.data.UserPassword !== '')); @@ -85,6 +89,11 @@ WallabagApi.prototype = { Object.assign(this.data, params); }, + setsave: function (params) { + this.set(params); + this.save; + }, + CheckUrl: function () { let url_ = this.data.Url + '/api/version'; return this.fetchApi.Get(url_, '') @@ -96,33 +105,39 @@ WallabagApi.prototype = { }, SaveTitle: function (articleId, articleTitle) { - return this.PatchArticle(articleId, JSON.stringify({ title: articleTitle })); + return this.PatchArticle(articleId, { title: articleTitle }); }, SaveStarred: function (articleId, articleStarred) { - return this.PatchArticle(articleId, JSON.stringify({ starred: articleStarred })); + return this.PatchArticle(articleId, { starred: articleStarred }); }, SaveArchived: function (articleId, articleArchived) { - return this.PatchArticle(articleId, JSON.stringify({ archive: articleArchived })); + return this.PatchArticle(articleId, { archive: articleArchived }); }, SaveTags: function (articleId, taglist) { - return this.PatchArticle(articleId, JSON.stringify({ tags: taglist })); + return this.PatchArticle(articleId, { tags: taglist }); }, PatchArticle: function (articleId, content) { let entryUrl = `${this.data.Url}/api/entries/${articleId}.json`; - return this.fetchApi.Patch(entryUrl, this.data.ApiToken, content) + return this.CheckToken().then(a => + this.fetchApi.Patch(entryUrl, this.data.ApiToken, content) + ) .catch(error => { throw new Error(`Failed to update article ${entryUrl} ${error.message}`); }); }, - + /** Delete article + * @param articleId {number} Article identificator + */ DeleteArticle: function (articleId) { let entryUrl = `${this.data.Url}/api/entries/${articleId}.json`; - return this.fetchApi.Delete(entryUrl, this.data.ApiToken) + return this.CheckToken().then(a => + this.fetchApi.Delete(entryUrl, this.data.ApiToken) + ) .catch(error => { throw new Error(`Failed to delete article ${entryUrl} ${error.message}`); @@ -131,17 +146,30 @@ WallabagApi.prototype = { DeleteArticleTag: function (articleId, tagid) { let entryUrl = `${this.data.Url}/api/entries/${articleId}/tags/${tagid}.json`; - return this.fetchApi.Delete(entryUrl, this.data.ApiToken) + return this.CheckToken().then(a => + this.fetchApi.Delete(entryUrl, this.data.ApiToken) + ) .catch(error => { throw new Error(`Failed to delete article tag ${entryUrl} ${error.message}`); }); }, + CheckToken: function () { + return new Promise((resolve, reject) => { + if (this.needNewAppToken()) { + resolve(this.GetAppToken()); + } + resolve(1); + }); + }, + SavePage: function (pageUrl) { - let content = JSON.stringify({ url: pageUrl }); + let content = { url: pageUrl }; let entriesUrl = `${this.data.Url}/api/entries.json`; - return this.fetchApi.Post(entriesUrl, this.data.ApiToken, content) + return this.CheckToken().then(a => + this.fetchApi.Post(entriesUrl, this.data.ApiToken, content) + ) .catch(error => { throw new Error(`Failed to save page ${entriesUrl} ${error.message}`); @@ -149,12 +177,12 @@ WallabagApi.prototype = { }, RefreshToken: function () { - let content = JSON.stringify({ + let content = { grant_type: 'refresh_token', refresh_token: this.data.RefreshToken, client_id: this.data.ClientId, client_secret: this.data.ClientSecret - }); + }; let oauthurl = `${this.data.Url}/oauth/v2/token`; return this.fetchApi.Post(oauthurl, '', content) .then(data => { @@ -174,7 +202,9 @@ WallabagApi.prototype = { GetTags: function () { let entriesUrl = `${this.data.Url}/api/tags.json`; - return this.fetchApi.Get(entriesUrl, this.data.ApiToken) + return this.CheckToken().then(a => + this.fetchApi.Get(entriesUrl, this.data.ApiToken) + ) .then(fetchData => { this.tags = fetchData; return fetchData; @@ -188,7 +218,9 @@ WallabagApi.prototype = { EntryExists: function (url) { let entriesUrl = `${this.data.Url}/api/entries/exists.json?url=${url}`; - return this.fetchApi.Get(entriesUrl, this.data.ApiToken) + return this.CheckToken().then(a => + this.fetchApi.Get(entriesUrl, this.data.ApiToken) + ) .catch(error => { throw new Error(`Failed to check if exists ${entriesUrl} ${error.message}`); @@ -197,7 +229,9 @@ WallabagApi.prototype = { GetArticle: function (articleId) { let entriesUrl = `${this.data.Url}/api/entries/${articleId}.json`; - return this.fetchApi.Get(entriesUrl, this.data.ApiToken) + return this.CheckToken().then(a => + this.fetchApi.Get(entriesUrl, this.data.ApiToken) + ) .catch(error => { throw new Error(`Failed to get article ${entriesUrl} ${error.message}`); @@ -206,29 +240,23 @@ WallabagApi.prototype = { GetArticleTags: function (articleId) { let entriesUrl = `${this.data.Url}/api/entries/${articleId}/tags.json`; - return this.fetchApi.Get(entriesUrl, this.data.ApiToken) + return this.CheckToken().then(a => + this.fetchApi.Get(entriesUrl, this.data.ApiToken) + ) .catch(error => { throw new Error(`Failed to get article tags ${entriesUrl} ${error.message}`); }); }, - // CheckAppToken: function () { - // let entriesUrl = `${this.data.Url}/api/entries.json?perPage=1`; - // let rinit = this.RequestInit("GET", this.AuhorizedHeader(), ''); - // return fetch( entriesUrl, rinit ) - // .then(this._status) - // .then(this._json); - // }, - GetAppToken: function () { - let content = JSON.stringify({ + let content = { grant_type: 'password', client_id: this.data.ClientId, client_secret: this.data.ClientSecret, username: this.data.UserLogin, password: this.data.UserPassword - }); + }; let oauthurl = `${this.data.Url}/oauth/v2/token`; return this.fetchApi.Post(oauthurl, '', content) diff --git a/wallabagger/manifest.json b/wallabagger/manifest.json index 7809a73..9290fd1 100644 --- a/wallabagger/manifest.json +++ b/wallabagger/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Wallabagger", - "version": "1.3", + "version": "1.4", "description": "Wallabag apiV2 extension with ability to edit title, tags, set starred and archived, and delete", "icons": { "16": "img/wallabag-icon-48a.png", "128": "img/wallabag-icon-128.png" }, diff --git a/wallabagger/options.html b/wallabagger/options.html index 9679088..662ace8 100644 --- a/wallabagger/options.html +++ b/wallabagger/options.html @@ -5,7 +5,7 @@