mirror of
https://github.com/GoogleChrome/chrome-extensions-samples.git
synced 2026-03-26 13:19:49 +07:00
* Remove docs folder. This was a redirect from a GitHub pages site that does not appear to be in use. * Rename api folder to api-samples. * Move examples to functional-samples folder. * Move cookbook sample to functional-samples. * Move tutorials to functional-samples folder. * Move mv2 and apps folders to _archive. * Rename tools folder to .repo. * Move reference folder to functional-samples. * Update README. Update README with new relative links for reorg. * Update README.md Co-authored-by: amysteamdev <37001393+AmySteam@users.noreply.github.com> --------- Co-authored-by: amysteamdev <37001393+AmySteam@users.noreply.github.com>
580 lines
25 KiB
HTML
580 lines
25 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
* Copyright (c) 2010 The Chromium Authors. All rights reserved. Use of this
|
|
* source code is governed by a BSD-style license that can be found in the
|
|
* LICENSE file.
|
|
*
|
|
* Author: Eric Bidelman <ericbidelman@chromium.org>
|
|
-->
|
|
<html>
|
|
<head>
|
|
<title>Your Google Documents List</title>
|
|
<script type="text/javascript" src="js/jquery-1.4.1.min.js"></script>
|
|
<style type="text/css">
|
|
body {
|
|
font: 12px 'Myriad Pro', 'Tw Cen MT', Arial, Verdana, sans-serif;
|
|
color: #666666;
|
|
overflow-x: hidden;
|
|
}
|
|
ul {
|
|
padding: 0;
|
|
list-style: none;
|
|
}
|
|
li {
|
|
clear: both;
|
|
padding: 2px 0;
|
|
}
|
|
li div img {
|
|
margin: 0 5px;
|
|
vertical-align: middle;
|
|
}
|
|
li div {
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
width: 250px;
|
|
float: left;
|
|
padding: 2px 0;
|
|
}
|
|
li span {
|
|
margin-left: 5px;
|
|
}
|
|
li:hover {
|
|
background-color: #fffccc;
|
|
}
|
|
a {
|
|
color: #4E7DC2;
|
|
text-decoration: none;
|
|
}
|
|
a:hover {
|
|
color: #880000;
|
|
text-decoration: underline;
|
|
}
|
|
#butter {
|
|
color: #fff;
|
|
background-color: #000033;
|
|
padding: 5px 20px;
|
|
border-radius: 15px;
|
|
width: auto;
|
|
text-align: center;
|
|
float: right;
|
|
display: none;
|
|
}
|
|
#butter.error {
|
|
background-color: red;
|
|
}
|
|
#new_doc_container {
|
|
display: none;
|
|
}
|
|
#new_doc_container input[type='text'],textarea {
|
|
width: 100%;
|
|
}
|
|
#output {
|
|
width: 375px;
|
|
clear: both;
|
|
}
|
|
[contenteditable]:hover {
|
|
outline: 1px dotted #666;
|
|
}
|
|
.star {
|
|
margin-top: 1px;
|
|
margin-right: 3px;
|
|
width: 16px;
|
|
height: 16px;
|
|
background: no-repeat url(data:image/png;base64,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) !important;
|
|
}
|
|
.star.selected {
|
|
background: no-repeat url(data:image/png;base64,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) !important;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div style="height:15px;">
|
|
<div style="float:left;">
|
|
<a href="javascript:void(0);" onclick="gdocs.refreshDocs();return false;">Refresh list</a>,
|
|
<a href="javascript:void(0);" onclick="$('#new_doc_container').toggle();return false;">New Document</a>
|
|
</div>
|
|
<div id="butter">Fetching your docs</div>
|
|
</div>
|
|
<div id="new_doc_container">
|
|
Create a: <select id="doc_type">
|
|
<option value="document">document</option>
|
|
<option value="presentation">presentation</option>
|
|
<option value="spreadsheet">spreadsheet</option>
|
|
</select>
|
|
<input type="text" id="doc_title" placeholder="Enter a title"><br>
|
|
<textarea id="doc_content" placeholder="Enter document content"></textarea>
|
|
Star it? <input type="checkbox" id="doc_starred">
|
|
<button onclick="gdocs.createDoc();" style="float:right;">Create new doc</button>
|
|
</div>
|
|
<div id="output"></div>
|
|
|
|
<script type="text/javascript">
|
|
// Protected namespaces.
|
|
var util = {};
|
|
var gdocs = {};
|
|
|
|
var bgPage = chrome.extension.getBackgroundPage();
|
|
var pollIntervalMax = 1000 * 60 * 60; // 1 hour
|
|
var requestFailureCount = 0; // used for exponential backoff
|
|
var requestTimeout = 1000 * 2; // 5 seconds
|
|
|
|
var DEFAULT_MIMETYPES = {
|
|
'atom': 'application/atom+xml',
|
|
'document': 'text/plain',
|
|
'spreadsheet': 'text/csv',
|
|
'presentation': 'text/plain',
|
|
'pdf': 'application/pdf'
|
|
};
|
|
|
|
// Persistent click handler for star icons.
|
|
$('#doc_type').change(function() {
|
|
if ($(this).val() === 'presentation') {
|
|
$('#doc_content').attr('disabled', 'true')
|
|
.attr('placeholder', 'N/A for presentations');
|
|
} else {
|
|
$('#doc_content').removeAttr('disabled')
|
|
.attr('placeholder', 'Enter document content');
|
|
}
|
|
});
|
|
|
|
|
|
// Persistent click handler for changing the title of a document.
|
|
$('[contenteditable="true"]').live('blur', function(index) {
|
|
var index = $(this).parent().parent().attr('data-index');
|
|
|
|
// Only make the XHR if the user chose a new title.
|
|
if ($(this).text() != bgPage.docs[index].title) {
|
|
bgPage.docs[index].title = $(this).text();
|
|
gdocs.updateDoc(bgPage.docs[index]);
|
|
}
|
|
});
|
|
|
|
// Persistent click handler for star icons.
|
|
$('.star').live('click', function() {
|
|
$(this).toggleClass('selected');
|
|
|
|
var index = $(this).parent().attr('data-index');
|
|
bgPage.docs[index].starred = $(this).hasClass('selected');
|
|
gdocs.updateDoc(bgPage.docs[index]);
|
|
});
|
|
|
|
/**
|
|
* Class to compartmentalize properties of a Google document.
|
|
* @param {Object} entry A JSON representation of a DocList atom entry.
|
|
* @constructor
|
|
*/
|
|
gdocs.GoogleDoc = function(entry) {
|
|
this.entry = entry;
|
|
this.title = entry.title.$t;
|
|
this.resourceId = entry.gd$resourceId.$t;
|
|
this.type = gdocs.getCategory(
|
|
entry.category, 'http://schemas.google.com/g/2005#kind');
|
|
this.starred = gdocs.getCategory(
|
|
entry.category, 'http://schemas.google.com/g/2005/labels',
|
|
'http://schemas.google.com/g/2005/labels#starred') ? true : false;
|
|
this.link = {
|
|
'alternate': gdocs.getLink(entry.link, 'alternate').href
|
|
};
|
|
this.contentSrc = entry.content.src;
|
|
};
|
|
|
|
/**
|
|
* Sets up a future poll for the user's document list.
|
|
*/
|
|
util.scheduleRequest = function() {
|
|
var exponent = Math.pow(2, requestFailureCount);
|
|
var delay = Math.min(bgPage.pollIntervalMin * exponent,
|
|
pollIntervalMax);
|
|
delay = Math.round(delay);
|
|
|
|
if (bgPage.oauth.hasToken()) {
|
|
var req = bgPage.window.setTimeout(function() {
|
|
gdocs.getDocumentList();
|
|
util.scheduleRequest();
|
|
}, delay);
|
|
bgPage.requests.push(req);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Urlencodes a JSON object of key/value query parameters.
|
|
* @param {Object} parameters Key value pairs representing URL parameters.
|
|
* @return {string} query parameters concatenated together.
|
|
*/
|
|
util.stringify = function(parameters) {
|
|
var params = [];
|
|
for(var p in parameters) {
|
|
params.push(encodeURIComponent(p) + '=' +
|
|
encodeURIComponent(parameters[p]));
|
|
}
|
|
return params.join('&');
|
|
};
|
|
|
|
/**
|
|
* Creates a JSON object of key/value pairs
|
|
* @param {string} paramStr A string of Url query parmeters.
|
|
* For example: max-results=5&startindex=2&showfolders=true
|
|
* @return {Object} The query parameters as key/value pairs.
|
|
*/
|
|
util.unstringify = function(paramStr) {
|
|
var parts = paramStr.split('&');
|
|
|
|
var params = {};
|
|
for (var i = 0, pair; pair = parts[i]; ++i) {
|
|
var param = pair.split('=');
|
|
params[decodeURIComponent(param[0])] = decodeURIComponent(param[1]);
|
|
}
|
|
return params;
|
|
};
|
|
|
|
/**
|
|
* Utility for displaying a message to the user.
|
|
* @param {string} msg The message.
|
|
*/
|
|
util.displayMsg = function(msg) {
|
|
$('#butter').removeClass('error').text(msg).show();
|
|
};
|
|
|
|
/**
|
|
* Utility for removing any messages currently showing to the user.
|
|
*/
|
|
util.hideMsg = function() {
|
|
$('#butter').fadeOut(1500);
|
|
};
|
|
|
|
/**
|
|
* Utility for displaying an error to the user.
|
|
* @param {string} msg The message.
|
|
*/
|
|
util.displayError = function(msg) {
|
|
util.displayMsg(msg);
|
|
$('#butter').addClass('error');
|
|
};
|
|
|
|
/**
|
|
* Returns the correct atom link corresponding to the 'rel' value passed in.
|
|
* @param {Array<Object>} links A list of atom link objects.
|
|
* @param {string} rel The rel value of the link to return. For example: 'next'.
|
|
* @return {string|null} The appropriate link for the 'rel' passed in, or null
|
|
* if one is not found.
|
|
*/
|
|
gdocs.getLink = function(links, rel) {
|
|
for (var i = 0, link; link = links[i]; ++i) {
|
|
if (link.rel === rel) {
|
|
return link;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Returns the correct atom category corresponding to the scheme/term passed in.
|
|
* @param {Array<Object>} categories A list of atom category objects.
|
|
* @param {string} scheme The category's scheme to look up.
|
|
* @param {opt_term?} An optional term value for the category to look up.
|
|
* @return {string|null} The appropriate category, or null if one is not found.
|
|
*/
|
|
gdocs.getCategory = function(categories, scheme, opt_term) {
|
|
for (var i = 0, cat; cat = categories[i]; ++i) {
|
|
if (opt_term) {
|
|
if (cat.scheme === scheme && opt_term === cat.term) {
|
|
return cat;
|
|
}
|
|
} else if (cat.scheme === scheme) {
|
|
return cat;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* A generic error handler for failed XHR requests.
|
|
* @param {XMLHttpRequest} xhr The xhr request that failed.
|
|
* @param {string} textStatus The server's returned status.
|
|
*/
|
|
gdocs.handleError = function(xhr, textStatus) {
|
|
util.displayError('Failed to fetch docs. Please try again.');
|
|
++requestFailureCount;
|
|
};
|
|
|
|
/**
|
|
* A helper for constructing the raw Atom xml send in the body of an HTTP post.
|
|
* @param {XMLHttpRequest} xhr The xhr request that failed.
|
|
* @param {string} docTitle A title for the document.
|
|
* @param {string} docType The type of document to create.
|
|
* (eg. 'document', 'spreadsheet', etc.)
|
|
* @param {boolean?} opt_starred Whether the document should be starred.
|
|
* @return {string} The Atom xml as a string.
|
|
*/
|
|
gdocs.constructAtomXml_ = function(docTitle, docType, opt_starred) {
|
|
var starred = opt_starred || null;
|
|
|
|
var starCat = ['<category scheme="http://schemas.google.com/g/2005/labels" ',
|
|
'term="http://schemas.google.com/g/2005/labels#starred" ',
|
|
'label="starred"/>'].join('');
|
|
|
|
var atom = ["<?xml version='1.0' encoding='UTF-8'?>",
|
|
'<entry xmlns="http://www.w3.org/2005/Atom">',
|
|
'<category scheme="http://schemas.google.com/g/2005#kind"',
|
|
' term="http://schemas.google.com/docs/2007#', docType, '"/>',
|
|
starred ? starCat : '',
|
|
'<title>', docTitle, '</title>',
|
|
'</entry>'].join('');
|
|
return atom;
|
|
};
|
|
|
|
/**
|
|
* A helper for constructing the body of a mime-mutlipart HTTP request.
|
|
* @param {string} title A title for the new document.
|
|
* @param {string} docType The type of document to create.
|
|
* (eg. 'document', 'spreadsheet', etc.)
|
|
* @param {string} body The body of the HTTP request.
|
|
* @param {string} contentType The Content-Type of the (non-Atom) portion of the
|
|
* http body.
|
|
* @param {boolean?} opt_starred Whether the document should be starred.
|
|
* @return {string} The Atom xml as a string.
|
|
*/
|
|
gdocs.constructContentBody_ = function(title, docType, body, contentType,
|
|
opt_starred) {
|
|
var body = ['--END_OF_PART\r\n',
|
|
'Content-Type: application/atom+xml;\r\n\r\n',
|
|
gdocs.constructAtomXml_(title, docType, opt_starred), '\r\n',
|
|
'--END_OF_PART\r\n',
|
|
'Content-Type: ', contentType, '\r\n\r\n',
|
|
body, '\r\n',
|
|
'--END_OF_PART--\r\n'].join('');
|
|
return body;
|
|
};
|
|
|
|
/**
|
|
* Creates a new document in Google Docs.
|
|
*/
|
|
gdocs.createDoc = function() {
|
|
var title = $.trim($('#doc_title').val());
|
|
if (!title) {
|
|
alert('Please provide a title');
|
|
return;
|
|
}
|
|
var content = $('#doc_content').val();
|
|
var starred = $('#doc_starred').is(':checked');
|
|
var docType = $('#doc_type').val();
|
|
|
|
util.displayMsg('Creating doc...');
|
|
|
|
var handleSuccess = function(resp, xhr) {
|
|
bgPage.docs.splice(0, 0, new gdocs.GoogleDoc(JSON.parse(resp).entry));
|
|
|
|
gdocs.renderDocList();
|
|
bgPage.setIcon({'text': bgPage.docs.length.toString()});
|
|
|
|
$('#new_doc_container').hide();
|
|
$('#doc_title').val('');
|
|
$('#doc_content').val('');
|
|
util.displayMsg('Document created!');
|
|
util.hideMsg();
|
|
|
|
requestFailureCount = 0;
|
|
};
|
|
|
|
var params = {
|
|
'method': 'POST',
|
|
'headers': {
|
|
'GData-Version': '3.0',
|
|
'Content-Type': 'multipart/related; boundary=END_OF_PART',
|
|
},
|
|
'parameters': {'alt': 'json'},
|
|
'body': gdocs.constructContentBody_(title, docType, content,
|
|
DEFAULT_MIMETYPES[docType], starred)
|
|
};
|
|
|
|
// Presentation can only be created from binary content. Instead, create a
|
|
// blank presentation.
|
|
if (docType === 'presentation') {
|
|
params['headers']['Content-Type'] = DEFAULT_MIMETYPES['atom'];
|
|
params['body'] = gdocs.constructAtomXml_(title, docType, starred);
|
|
}
|
|
|
|
bgPage.oauth.sendSignedRequest(bgPage.DOCLIST_FEED, handleSuccess, params);
|
|
};
|
|
|
|
/**
|
|
* Updates a document's metadata (title, starred, etc.).
|
|
* @param {gdocs.GoogleDoc} googleDocObj An object containing the document to
|
|
* update.
|
|
*/
|
|
gdocs.updateDoc = function(googleDocObj) {
|
|
var handleSuccess = function(resp) {
|
|
util.displayMsg('Updated!');
|
|
util.hideMsg();
|
|
requestFailureCount = 0;
|
|
};
|
|
|
|
var params = {
|
|
'method': 'PUT',
|
|
'headers': {
|
|
'GData-Version': '3.0',
|
|
'Content-Type': 'application/atom+xml',
|
|
'If-Match': '*'
|
|
},
|
|
'body': gdocs.constructAtomXml_(googleDocObj.title, googleDocObj.type,
|
|
googleDocObj.starred)
|
|
};
|
|
|
|
var url = bgPage.DOCLIST_FEED + googleDocObj.resourceId;
|
|
bgPage.oauth.sendSignedRequest(url, handleSuccess, params);
|
|
};
|
|
|
|
/**
|
|
* Deletes a document from the user's document list.
|
|
* @param {integer} index An index intro the background page's docs array.
|
|
*/
|
|
gdocs.deleteDoc = function(index) {
|
|
var handleSuccess = function(resp, xhr) {
|
|
util.displayMsg('Document trashed!');
|
|
util.hideMsg();
|
|
requestFailureCount = 0;
|
|
bgPage.docs.splice(index, 1);
|
|
bgPage.setIcon({'text': bgPage.docs.length.toString()});
|
|
}
|
|
|
|
var params = {
|
|
'method': 'DELETE',
|
|
'headers': {
|
|
'GData-Version': '3.0',
|
|
'If-Match': '*'
|
|
}
|
|
};
|
|
|
|
$('#output li').eq(index).fadeOut('slow');
|
|
|
|
bgPage.oauth.sendSignedRequest(
|
|
bgPage.DOCLIST_FEED + bgPage.docs[index].resourceId,
|
|
handleSuccess, params);
|
|
};
|
|
|
|
/**
|
|
* Callback for processing the JSON feed returned by the DocList API.
|
|
* @param {string} response The server's response.
|
|
* @param {XMLHttpRequest} xhr The xhr request that was made.
|
|
*/
|
|
gdocs.processDocListResults = function(response, xhr) {
|
|
if (xhr.status != 200) {
|
|
gdocs.handleError(xhr, response);
|
|
return;
|
|
} else {
|
|
requestFailureCount = 0;
|
|
}
|
|
|
|
var data = JSON.parse(response);
|
|
|
|
for (var i = 0, entry; entry = data.feed.entry[i]; ++i) {
|
|
bgPage.docs.push(new gdocs.GoogleDoc(entry));
|
|
}
|
|
|
|
var nextLink = gdocs.getLink(data.feed.link, 'next');
|
|
if (nextLink) {
|
|
gdocs.getDocumentList(nextLink.href); // Fetch next page of results.
|
|
} else {
|
|
gdocs.renderDocList();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Presents the in-memory documents that were fetched from the server as HTML.
|
|
*/
|
|
gdocs.renderDocList = function() {
|
|
util.hideMsg();
|
|
|
|
// Construct the iframe's HTML.
|
|
var html = [];
|
|
for (var i = 0, doc; doc = bgPage.docs[i]; ++i) {
|
|
// If we have an arbitrary file, use generic file icon.
|
|
var type = doc.type.label;
|
|
if (doc.type.term == 'http://schemas.google.com/docs/2007#file') {
|
|
type = 'file';
|
|
}
|
|
|
|
var starred = doc.starred ? ' selected' : '';
|
|
html.push(
|
|
'<li data-index="', i , '"><div class="star', starred, '"></div>',
|
|
'<div><img src="img/icons/', type, '.gif">',
|
|
'<span contenteditable="true" class="doc_title"></span></div>',
|
|
'<span>[<a href="', doc.link['alternate'],
|
|
'" target="_new">view</a> | <a href="javascript:void(0);" ',
|
|
'onclick="gdocs.deleteDoc(',i,
|
|
');return false;">delete</a>]','</span></li>');
|
|
}
|
|
$('#output').html('<ul>' + html.join('') + '</ul>');
|
|
|
|
// Set each span's innerText to be the doc title. We're filling this after
|
|
// the html has been rendered to the page prevent XSS attacks when using
|
|
// innerHTML.
|
|
$('#output li span.doc_title').each(function(i, ul) {
|
|
$(ul).text(bgPage.docs[i].title);
|
|
});
|
|
|
|
bgPage.setIcon({'text': bgPage.docs.length.toString()});
|
|
};
|
|
|
|
/**
|
|
* Fetches the user's document list.
|
|
* @param {string?} opt_url A url to query the doclist API with. If omitted,
|
|
* the main doclist feed uri is used.
|
|
*/
|
|
gdocs.getDocumentList = function(opt_url) {
|
|
var url = opt_url || null;
|
|
|
|
var params = {
|
|
'headers': {
|
|
'GData-Version': '3.0'
|
|
}
|
|
};
|
|
|
|
if (!url) {
|
|
util.displayMsg('Fetching your docs');
|
|
bgPage.setIcon({'text': '...'});
|
|
|
|
bgPage.docs = []; // Clear document list. We're doing a refresh.
|
|
|
|
url = bgPage.DOCLIST_FEED;
|
|
params['parameters'] = {
|
|
'alt': 'json',
|
|
'showfolders': 'true'
|
|
};
|
|
} else {
|
|
util.displayMsg($('#butter').text() + '.');
|
|
|
|
var parts = url.split('?');
|
|
if (parts.length > 1) {
|
|
url = parts[0]; // Extract base URI. Params are passed in separately.
|
|
params['parameters'] = util.unstringify(parts[1]);
|
|
}
|
|
}
|
|
|
|
bgPage.oauth.sendSignedRequest(url, gdocs.processDocListResults, params);
|
|
};
|
|
|
|
/**
|
|
* Refreshes the user's document list.
|
|
*/
|
|
gdocs.refreshDocs = function() {
|
|
bgPage.clearPendingRequests();
|
|
gdocs.getDocumentList();
|
|
util.scheduleRequest();
|
|
};
|
|
|
|
|
|
bgPage.oauth.authorize(function() {
|
|
if (!bgPage.docs.length) {
|
|
gdocs.getDocumentList();
|
|
} else {
|
|
gdocs.renderDocList();
|
|
}
|
|
util.scheduleRequest();
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|