Skip to content

Commit 76bb448

Browse files
Add/site integration (#26)
* Updating site integrations Adding Twitter integration Removing Reddit Removing Hacker News * Fixing Twitter integration Twitter integration was not respecting the users settings. This performs a check at twitter launch. Future versions will create a signal/response
1 parent 789ad37 commit 76bb448

File tree

7 files changed

+174
-32
lines changed

7 files changed

+174
-32
lines changed

src/containers/background/_sites.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { takeLatest, call } from 'redux-saga/effects'
2+
import { requireAuthorization } from '../auth/_auth'
3+
import { saveToPocket } from '../../common/api'
4+
5+
// SAGAS
6+
export function* wSaveTweet() {
7+
yield takeLatest('SAVE_TWEET_TO_POCKET', saveTweetRequest)
8+
}
9+
10+
function* saveTweetRequest(saveObject) {
11+
const { permaLink, elementId } = saveObject.request
12+
const authToken = yield call(requireAuthorization)
13+
14+
const url = `https://twitter.com${permaLink}`
15+
const data = saveToPocket({ url, elementId }, authToken)
16+
17+
data.then(results => {
18+
saveObject.sendResponse(results)
19+
})
20+
}

src/containers/background/background.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,20 @@ Interface.addMessageListener((request, sender, sendResponse) => {
4949
? store.dispatch(cancelCloseSavePanel({ tabId: sender.tab.id }))
5050
: store.dispatch(closeSavePanel({ tabId: sender.tab.id }))
5151
}
52+
53+
if (request.action === 'twitterCheck') {
54+
const twitterState = store.getState()
55+
sendResponse(twitterState.setup && twitterState.setup.sites_twitter)
56+
}
57+
58+
if (request.action === 'twitterSave') {
59+
store.dispatch({
60+
type: 'SAVE_TWEET_TO_POCKET',
61+
request,
62+
sendResponse
63+
})
64+
return true
65+
}
5266
})
5367

5468
Interface.contextMenus().removeAll(createContextMenus)

src/containers/options/options.app.js

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ export default class Options extends Component {
4545
}
4646

4747
toggleTwitter = () => this.props.toggleSite('sites_twitter')
48-
toggleHackernews = () => this.props.toggleSite('sites_hackernews')
49-
toggleReddit = () => this.props.toggleSite('sites_reddit')
5048

5149
setShortcuts = () => openTabWithUrl(SET_SHORTCUTS)
5250

@@ -111,22 +109,6 @@ export default class Options extends Component {
111109
/>
112110
Twitter
113111
</li>
114-
<li>
115-
<Toggle
116-
active={
117-
this.props.setup.sites_hackernews
118-
}
119-
action={this.toggleHackernews}
120-
/>
121-
Hacker News
122-
</li>
123-
<li>
124-
<Toggle
125-
active={this.props.setup.sites_reddit}
126-
action={this.toggleReddit}
127-
/>
128-
Reddit
129-
</li>
130112
</ul>
131113
<div className={styles.info}>
132114
{localize('options_page', 'services_info')}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import styles from './twitter.scss' // Import Styles
2+
import { addMessageListener, sendMessage } from '../../../common/interface'
3+
4+
const mutationConfig = {
5+
childList: true,
6+
attributes: false,
7+
characterData: false,
8+
subtree: true
9+
}
10+
11+
// Set up Observer
12+
const appObserver = new MutationObserver(appMutationHandler)
13+
function appMutationHandler(mutationList) {
14+
for (var mutation of mutationList) {
15+
if (
16+
mutation.type === 'childList' &&
17+
(mutation.target.id === 'page-container' ||
18+
mutation.target.id === 'stream-items-id' ||
19+
mutation.target.id === 'permalink-overlay-body')
20+
) {
21+
handleNewItems()
22+
}
23+
}
24+
}
25+
26+
// Define Markup
27+
const saveToPocketMarkup = `
28+
<button class="ProfileTweet-actionButton u-textUserColorHover js-actionButton"
29+
type="button" data-nav="share_tweet_to_pocket">
30+
<div class="IconContainer js-tooltip" data-original-title="Save To Pocket">
31+
<span class="Icon Icon--medium Icon--saveToPocket">
32+
<svg class=${styles.pocketIcon}
33+
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1836 1836">
34+
<path d="M217.7,148.1A153.7,153.7,0,0,0,74.7,248.2,146.5,146.5,0,0,0,64,303.6V811L71.1,911a800.4,800.4,0,0,0,330.5,568.2l10.7,7.1H416a812.9,812.9,0,0,0,334.1,144.7,873.7,873.7,0,0,0,169.7,17.9,757.5,757.5,0,0,0,157.2-14.3l19.7-3.6a7.1,7.1,0,0,0,7.1-3.6,882.6,882.6,0,0,0,318-141.1h3.6l10.7-7.1a825.4,825.4,0,0,0,335.9-571.7l7.1-100.1V300a246.6,246.6,0,0,0-7.1-51.8,159,159,0,0,0-146.5-100.1h0M1400.4,778.8l-402,377a119.7,119.7,0,0,1-164.4,0l-398.4-377a116.1,116.1,0,0,1-3.6-162.6,119.7,119.7,0,0,1,164.4-3.6L916.2,916.4l319.8-303.7a119.7,119.7,0,0,1,164.4,3.6,112.6,112.6,0,0,1,5.4,159Z"/>
35+
</svg>
36+
</span>
37+
<span class="u-hiddenVisually">Save To Pocket</span>
38+
</div>
39+
</button>
40+
`
41+
const saveToPocketButton = document.createElement('div')
42+
saveToPocketButton.classList.add(
43+
'ProfileTweet-action',
44+
'ProfileTweet-action--stp'
45+
)
46+
saveToPocketButton.innerHTML = saveToPocketMarkup
47+
48+
// Start and Stop integration
49+
function resolveCheck(integrate) {
50+
if (integrate) return startIntegration()
51+
stopIntegration()
52+
}
53+
54+
function startIntegration() {
55+
appObserver.observe(document, mutationConfig)
56+
handleNewItems()
57+
}
58+
59+
function stopIntegration() {
60+
appObserver.disconnect()
61+
const nodeList = document.querySelectorAll('div.ProfileTweet-action--stp')
62+
nodeList.forEach(e => e.parentNode.removeChild(e))
63+
}
64+
65+
// Set Injections
66+
function handleNewItems() {
67+
const tweetActionLists = document.querySelectorAll(
68+
'.tweet:not(.PocketAdded)'
69+
)
70+
if (!tweetActionLists.length) return
71+
72+
Array.from(tweetActionLists, addPocketFunctionality)
73+
}
74+
75+
function addPocketFunctionality(element) {
76+
const permaLink = element.getAttribute('data-permalink-path')
77+
const elementId = element.getAttribute('data-item-id')
78+
79+
const buttonClone = saveToPocketButton.cloneNode(true)
80+
buttonClone.id = `pocketButton-${elementId}`
81+
buttonClone.addEventListener(
82+
'click',
83+
handleSave.bind(this, elementId, permaLink)
84+
)
85+
86+
buttonClone.setAttribute('data-permalink-path', permaLink)
87+
buttonClone.setAttribute('data-item-id', elementId)
88+
89+
const actionList = element.querySelector('.ProfileTweet-actionList')
90+
if (actionList) {
91+
actionList.appendChild(buttonClone)
92+
element.classList.add('PocketAdded')
93+
}
94+
}
95+
96+
// Handle saving
97+
function handleSave(elementId, permaLink) {
98+
sendMessage(
99+
null,
100+
{ action: 'twitterSave', permaLink, elementId },
101+
resolveSave
102+
)
103+
}
104+
105+
function resolveSave(data) {
106+
const elementId = data.saveObject.elementId
107+
const tweet = document.getElementById(`pocketButton-${elementId}`)
108+
tweet.classList.add(styles.saved)
109+
}
110+
111+
function handleAction(action, sender, sendResponse) {
112+
if (action.type === 'twitterStop') {
113+
stopIntegration()
114+
}
115+
116+
if (action.type === 'twitterStart') {
117+
startIntegration()
118+
}
119+
}
120+
121+
addMessageListener(handleAction)
122+
123+
// Do we want twitter integration?
124+
sendMessage(null, { action: 'twitterCheck' }, resolveCheck)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.pocketIcon {
2+
display: inline-block;
3+
fill: currentColor;
4+
height: 16px;
5+
vertical-align: bottom;
6+
width: 16px;
7+
8+
&:hover,
9+
.saved & {
10+
fill: #ef4056;
11+
}
12+
}

src/manifest.yml

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: 'Save to Pocket'
2-
version: 3.0.0.8
2+
version: 3.0.0.9
33
options_page: options.html
44
description: __MSG_extDescriptionGoogleChrome__
55
default_locale: "en"
@@ -45,19 +45,7 @@ content_scripts:
4545
- '*://twitter.com/*'
4646
js:
4747
- js/twitter.bundle.js
48-
-
49-
matches:
50-
- 'http://*.ycombinator.org/*'
51-
- 'https://*.ycombinator.org/*'
52-
- 'http://*.ycombinator.com/*'
53-
- 'https://*.ycombinator.com/*'
54-
js:
55-
- js/hackerNews.bundle.js
56-
-
57-
matches:
58-
- '*://*.reddit.com/*'
59-
js:
60-
- js/reddit.bundle.js
48+
6149
icons:
6250
128: images/icon-128.png
6351
48: images/icon-48.png

src/store/combineSagas.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { wSetup } from '../containers/background/_setup'
66
import { wHydrate } from '../containers/background/_setup'
77
import { wToggleRecs } from '../containers/background/_setup'
88
import { wToggleSite } from '../containers/background/_setup'
9+
import { wSaveTweet } from '../containers/background/_sites'
910

1011
import { wAuthCodeRecieved } from '../containers/auth/_auth'
1112
import { wLogout } from '../containers/auth/_auth'
@@ -35,6 +36,7 @@ export default function* rootSaga() {
3536
wHydrate(),
3637
wToggleRecs(),
3738
wToggleSite(),
39+
wSaveTweet(),
3840

3941
wOpenPocket(),
4042
wOpenOptions(),

0 commit comments

Comments
 (0)