diff --git a/src/containers/background/_sites.js b/src/containers/background/_sites.js
new file mode 100644
index 00000000..ab1d188f
--- /dev/null
+++ b/src/containers/background/_sites.js
@@ -0,0 +1,20 @@
+import { takeLatest, call } from 'redux-saga/effects'
+import { requireAuthorization } from '../auth/_auth'
+import { saveToPocket } from '../../common/api'
+
+// SAGAS
+export function* wSaveTweet() {
+ yield takeLatest('SAVE_TWEET_TO_POCKET', saveTweetRequest)
+}
+
+function* saveTweetRequest(saveObject) {
+ const { permaLink, elementId } = saveObject.request
+ const authToken = yield call(requireAuthorization)
+
+ const url = `https://twitter.com${permaLink}`
+ const data = saveToPocket({ url, elementId }, authToken)
+
+ data.then(results => {
+ saveObject.sendResponse(results)
+ })
+}
diff --git a/src/containers/background/background.js b/src/containers/background/background.js
index 3e1c2f6a..9ce897a3 100644
--- a/src/containers/background/background.js
+++ b/src/containers/background/background.js
@@ -49,6 +49,20 @@ Interface.addMessageListener((request, sender, sendResponse) => {
? store.dispatch(cancelCloseSavePanel({ tabId: sender.tab.id }))
: store.dispatch(closeSavePanel({ tabId: sender.tab.id }))
}
+
+ if (request.action === 'twitterCheck') {
+ const twitterState = store.getState()
+ sendResponse(twitterState.setup && twitterState.setup.sites_twitter)
+ }
+
+ if (request.action === 'twitterSave') {
+ store.dispatch({
+ type: 'SAVE_TWEET_TO_POCKET',
+ request,
+ sendResponse
+ })
+ return true
+ }
})
Interface.contextMenus().removeAll(createContextMenus)
diff --git a/src/containers/options/options.app.js b/src/containers/options/options.app.js
index 0de18a6c..d18e89e1 100644
--- a/src/containers/options/options.app.js
+++ b/src/containers/options/options.app.js
@@ -45,8 +45,6 @@ export default class Options extends Component {
}
toggleTwitter = () => this.props.toggleSite('sites_twitter')
- toggleHackernews = () => this.props.toggleSite('sites_hackernews')
- toggleReddit = () => this.props.toggleSite('sites_reddit')
setShortcuts = () => openTabWithUrl(SET_SHORTCUTS)
@@ -111,22 +109,6 @@ export default class Options extends Component {
/>
Twitter
-
-
- Hacker News
-
-
-
- Reddit
-
{localize('options_page', 'services_info')}
diff --git a/src/containers/sites/twitter/twitter.js b/src/containers/sites/twitter/twitter.js
index e69de29b..c1e5ada6 100644
--- a/src/containers/sites/twitter/twitter.js
+++ b/src/containers/sites/twitter/twitter.js
@@ -0,0 +1,124 @@
+import styles from './twitter.scss' // Import Styles
+import { addMessageListener, sendMessage } from '../../../common/interface'
+
+const mutationConfig = {
+ childList: true,
+ attributes: false,
+ characterData: false,
+ subtree: true
+}
+
+// Set up Observer
+const appObserver = new MutationObserver(appMutationHandler)
+function appMutationHandler(mutationList) {
+ for (var mutation of mutationList) {
+ if (
+ mutation.type === 'childList' &&
+ (mutation.target.id === 'page-container' ||
+ mutation.target.id === 'stream-items-id' ||
+ mutation.target.id === 'permalink-overlay-body')
+ ) {
+ handleNewItems()
+ }
+ }
+}
+
+// Define Markup
+const saveToPocketMarkup = `
+
+`
+const saveToPocketButton = document.createElement('div')
+saveToPocketButton.classList.add(
+ 'ProfileTweet-action',
+ 'ProfileTweet-action--stp'
+)
+saveToPocketButton.innerHTML = saveToPocketMarkup
+
+// Start and Stop integration
+function resolveCheck(integrate) {
+ if (integrate) return startIntegration()
+ stopIntegration()
+}
+
+function startIntegration() {
+ appObserver.observe(document, mutationConfig)
+ handleNewItems()
+}
+
+function stopIntegration() {
+ appObserver.disconnect()
+ const nodeList = document.querySelectorAll('div.ProfileTweet-action--stp')
+ nodeList.forEach(e => e.parentNode.removeChild(e))
+}
+
+// Set Injections
+function handleNewItems() {
+ const tweetActionLists = document.querySelectorAll(
+ '.tweet:not(.PocketAdded)'
+ )
+ if (!tweetActionLists.length) return
+
+ Array.from(tweetActionLists, addPocketFunctionality)
+}
+
+function addPocketFunctionality(element) {
+ const permaLink = element.getAttribute('data-permalink-path')
+ const elementId = element.getAttribute('data-item-id')
+
+ const buttonClone = saveToPocketButton.cloneNode(true)
+ buttonClone.id = `pocketButton-${elementId}`
+ buttonClone.addEventListener(
+ 'click',
+ handleSave.bind(this, elementId, permaLink)
+ )
+
+ buttonClone.setAttribute('data-permalink-path', permaLink)
+ buttonClone.setAttribute('data-item-id', elementId)
+
+ const actionList = element.querySelector('.ProfileTweet-actionList')
+ if (actionList) {
+ actionList.appendChild(buttonClone)
+ element.classList.add('PocketAdded')
+ }
+}
+
+// Handle saving
+function handleSave(elementId, permaLink) {
+ sendMessage(
+ null,
+ { action: 'twitterSave', permaLink, elementId },
+ resolveSave
+ )
+}
+
+function resolveSave(data) {
+ const elementId = data.saveObject.elementId
+ const tweet = document.getElementById(`pocketButton-${elementId}`)
+ tweet.classList.add(styles.saved)
+}
+
+function handleAction(action, sender, sendResponse) {
+ if (action.type === 'twitterStop') {
+ stopIntegration()
+ }
+
+ if (action.type === 'twitterStart') {
+ startIntegration()
+ }
+}
+
+addMessageListener(handleAction)
+
+// Do we want twitter integration?
+sendMessage(null, { action: 'twitterCheck' }, resolveCheck)
diff --git a/src/containers/sites/twitter/twitter.scss b/src/containers/sites/twitter/twitter.scss
new file mode 100644
index 00000000..c9d1563e
--- /dev/null
+++ b/src/containers/sites/twitter/twitter.scss
@@ -0,0 +1,12 @@
+.pocketIcon {
+ display: inline-block;
+ fill: currentColor;
+ height: 16px;
+ vertical-align: bottom;
+ width: 16px;
+
+ &:hover,
+ .saved & {
+ fill: #ef4056;
+ }
+}
diff --git a/src/manifest.yml b/src/manifest.yml
index f20dffe1..9f1ab223 100644
--- a/src/manifest.yml
+++ b/src/manifest.yml
@@ -1,5 +1,5 @@
name: 'Save to Pocket'
-version: 3.0.0.8
+version: 3.0.0.9
options_page: options.html
description: __MSG_extDescriptionGoogleChrome__
default_locale: "en"
@@ -45,19 +45,7 @@ content_scripts:
- '*://twitter.com/*'
js:
- js/twitter.bundle.js
- -
- matches:
- - 'http://*.ycombinator.org/*'
- - 'https://*.ycombinator.org/*'
- - 'http://*.ycombinator.com/*'
- - 'https://*.ycombinator.com/*'
- js:
- - js/hackerNews.bundle.js
- -
- matches:
- - '*://*.reddit.com/*'
- js:
- - js/reddit.bundle.js
+
icons:
128: images/icon-128.png
48: images/icon-48.png
diff --git a/src/store/combineSagas.js b/src/store/combineSagas.js
index a2efc0ab..5be8595f 100644
--- a/src/store/combineSagas.js
+++ b/src/store/combineSagas.js
@@ -6,6 +6,7 @@ import { wSetup } from '../containers/background/_setup'
import { wHydrate } from '../containers/background/_setup'
import { wToggleRecs } from '../containers/background/_setup'
import { wToggleSite } from '../containers/background/_setup'
+import { wSaveTweet } from '../containers/background/_sites'
import { wAuthCodeRecieved } from '../containers/auth/_auth'
import { wLogout } from '../containers/auth/_auth'
@@ -35,6 +36,7 @@ export default function* rootSaga() {
wHydrate(),
wToggleRecs(),
wToggleSite(),
+ wSaveTweet(),
wOpenPocket(),
wOpenOptions(),