Skip to content
This repository has been archived by the owner on Mar 10, 2020. It is now read-only.

Commit

Permalink
First working version.
Browse files Browse the repository at this point in the history
- Implemented as a pageAction, with a supremely ugly "Notification"
  window for the "Saved!" message.

- @todo: Suck it up and inject a script into every page to handle
  `ctrl-p` for saving, and a "Saved!" message that doesn't look
  stunningly bad.  Look into the experimental 'infobar' API, as that
  might be Good Enough.
  • Loading branch information
mikewest committed Jun 20, 2010
0 parents commit d53adab
Show file tree
Hide file tree
Showing 10 changed files with 276 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.markdown
@@ -0,0 +1,8 @@
Instapaper Chrome Extension
===========================

I don't use any bookmarking tools with any regularity, other than
Instapaper, and I don't need an extension that does anything beyond
simply sending articles into the service. This extension aims to
make that as simple and streamlined as possible.

11 changes: 11 additions & 0 deletions background.html
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>'Send to Instapaper' controller</title>
<script src="sendtoinstapaper.js" type="text/javascript"></script>
<script type="text/javascript">
window.addEventListener( 'load', SendToInstapaper.backgroundInit );
</script>
</head>
<body></body>
</html>
Binary file added icon-128x128.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icon-16x16.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icon-19x19.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icon-48x48.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions manifest.json
@@ -0,0 +1,23 @@
{
"name": "Send to Instapaper",
"version": "0.1",

"description": "A simple, streamlined Instapapering tool.",
"icons": {
"16": "icon-16x16.png",
"19": "icon-19x19.png",
"48": "icon-48x48.png",
"128": "icon-128x128.png"
},

"page_action": {
"default_icon": "icon-19x19.png",
"default_title": "Send to Instapaper"
},
"background_page": "background.html",
"permissions": [
"tabs",
"notifications",
"https://www.instapaper.com/"
]
}
190 changes: 190 additions & 0 deletions sendtoinstapaper.js
@@ -0,0 +1,190 @@
/**
* SendToInstapaper
*/
var SendToInstapaper = ( function() {
var URL_AUTH = "https://www.instapaper.com/api/authenticate",
URL_ADD = "https://www.instapaper.com/api/add",

STATUS_OK = 200,
STATUS_CREATED = 201,
STATUS_BADREQUEST = 400,
STATUS_FORBIDDEN = 403,
STATUS_ERROR = 500;

function syncRequest( options ) {
options.method = options.method || "GET";
options.async = false;
var xhr = new XMLHttpRequest(),
postData = "";
xhr.open(
options.method, options.url, options.async
);
if ( options.username || options.password ) {
xhr.setRequestHeader( "Authorization", "Basic " + btoa( options.username + ":" + options.password ) );
}
if ( options.method === "POST" ) {
xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
}
console.log( "XHR: %o", options, xhr );
try {
if ( options.data ) {
for ( key in options.data ) {
if ( options.data.hasOwnProperty( key ) ) {
postData += encodeURIComponent( key ) + "=" + encodeURIComponent( options.data[ key ] ) + "&";
}
}
postData += "1=1";
}
xhr.send( postData );
return xhr;
} catch ( e ) {
return {
'status': 0,
'exception': e
};
}
}

function isAuthenticated( force ) {
console.log( "Checking auth: %o", option( 'authenticated' ) );
if ( option( 'authenticated' ) !== STATUS_ERROR && !force ) {
return option( 'authenticated' );
}

option( 'authenticated', null );
if (
option( "username" ) !== undefined &&
option( "password" ) !== undefined
) {
var req = syncRequest( {
'url': URL_AUTH,
'username': option( "username" ),
'password': option( "password" )
} );
switch ( req.status ) {
case STATUS_OK:
option( "authenticated", true );
break;
case STATUS_FORBIDDEN:
option( "authenticated", false );
break;
case STATUS_ERROR:
default:
option( "authenticated", STATUS_ERROR );
break;
}
}
return localStorage.authenticated;
}

function sendURL( tab ) {
if ( isAuthenticated() ) {
syncRequest( {
'method': "POST",
'url': URL_ADD,
'username': option( "username" ),
'password': option( "password" ),
'data': {
'url': tab.url,
'title': tab.title
}
} );
} else {
// Handle unauthenticated user here.
}
}

function backgroundInit() {
option( 'currentTab', null );
// When Chrome displays any tab, show the pageAction
// icon in that tab's addressbar.
chrome.tabs.onSelectionChanged.addListener(
function(tabId) {
option( 'currentTab', tabId );

chrome.pageAction.show( tabId );
setPopup();
}
);
// Display the pageAction icon for the current tab
// (as it's already visible, `onSelectionChange`
// won't have been called.
chrome.tabs.getSelected( null, function( tab ) {
option( 'currentTab', tab.id );
chrome.pageAction.show( tab.id );
setPopup();
} );

chrome.pageAction.onClicked.addListener( function ( tab ) {
sendURL( tab );
webkitNotifications.createNotification(
'icon.png',
'Instaper',
'Successfully saved "' + tab.title + '" to Instapaper.'
).show();
} );

}

function setPopup( ) {
if ( isAuthenticated() !== true ) {
console.log( "Setting popup." );
chrome.pageAction.setPopup( {
'tabId': option( 'currentTab' ),
'popup': 'setup.html'
} );
} else {
console.log( "Unsetting popup." );
chrome.pageAction.setPopup( {
'tabId': option( 'currentTab' ),
'popup': ''
} );
}
}

function setupInit() {
var theForm = document.getElementById( 'optionForm' ),
user = document.getElementById( 'username' ),
pass = document.getElementById( 'password' ),
auth;

user.value = option( 'username' );
pass.value = option( 'password' );

theForm.addEventListener( 'submit', function ( e ) {
option( 'username', user.value );
option( 'password', pass.value );
auth = isAuthenticated( true );
if ( auth === true ) {
theForm.appendChild( document.createTextNode( "Success!" ) );
} else if ( auth === false ) {
theForm.appendChild( document.createTextNode( "Invalid username/password." ) );
} else if ( auth === STATUS_ERROR ) {
theForm.appendChild( document.createTextNode( "Error communicating with Instapaper. Are you online?" ) );
}

setPopup();

e.preventDefault(); e.stopPropagation();
return false;
} );
}

function option( key, value ) {
if ( typeof( value ) !== "undefined" ) {
localStorage[ key ] = JSON.stringify( { "value": value } );
} else {
if ( typeof( localStorage[ key ] ) !== "undefined" ) {
return JSON.parse( localStorage[ key ] ).value;
} else {
return undefined;
}
}
}

return {
'backgroundInit': backgroundInit,
'setupInit': setupInit,
'option': option
};
}() );
44 changes: 44 additions & 0 deletions setup.html
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>
<head>
<title>'Send To Instapaper' Setup</title>
<script src="sendtoinstapaper.js" type="text/javascript"></script>
<style type="text/css">
body {
margin: 0;
padding: 10px;
width: 250px;
}
h1 {
font: 18px/1.2 Baskerville;
font-weight: 700;
margin: 0 0 10px;
padding: 0;
}
label {
display: block;
margin: 10px 0;
}
label input {
display: block;
}
</style>
<script type="text/javascript">
window.addEventListener( 'load', SendToInstapaper.setupInit );
</script>
</head>
<body>
<h1>'Send to Instapaper' Options</h1>
<form action="#" id="optionForm">
<label>
Email address or username:
<input type="text" id="username" value="">
</label>
<label>
Password:
<input type="password" id="password" value="">
</label>
<input type="submit" value="Save">
</form>
</body>
</html>

0 comments on commit d53adab

Please sign in to comment.