Commit 093cfa5a authored by rob's avatar rob Committed by Commit bot

New Getting started example for extensions

Replaces the outdated Kittens tutorial with a new getting started tutorial that uses the Google Image search API.

BUG=383385
NOTRY=true
R=kalman@chromium.org,mkearney@chromium.org

Review URL: https://codereview.chromium.org/732943002

Cr-Commit-Position: refs/heads/master@{#311485}
parent 5d4299f0
{ {
"manifest_version": 2, "manifest_version": 2,
"name": "One-click Kittens", "name": "Getting started example",
"description": "This extension demonstrates a 'browser action' with kittens.", "description": "This extension shows a Google Image search result for the current page",
"version": "1.0", "version": "1.0",
"browser_action": { "browser_action": {
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
"default_popup": "popup.html" "default_popup": "popup.html"
}, },
"permissions": [ "permissions": [
"https://secure.flickr.com/" "activeTab",
"https://ajax.googleapis.com/"
] ]
} }
<!doctype html> <!doctype html>
<!--
This page is shown when the extension button is clicked, because the
"browser_action" field in manifest.json contains the "default_popup" key with
value "popup.html".
-->
<html> <html>
<head> <head>
<title>Getting Started Extension's Popup</title> <title>Getting Started Extension's Popup</title>
<style> <style>
body { body {
min-width: 357px; font-family: "Segoe UI", "Lucida Grande", Tahoma, sans-serif;
overflow-x: hidden; font-size: 100%;
} }
#status {
img { /* avoid an excessively wide status text */
margin: 5px; white-space: pre;
border: 2px solid black; text-overflow: ellipsis;
vertical-align: middle; overflow: hidden;
width: 75px; max-width: 400px;
height: 75px;
} }
</style> </style>
...@@ -21,11 +25,13 @@ ...@@ -21,11 +25,13 @@
- JavaScript and HTML must be in separate files: see our Content Security - JavaScript and HTML must be in separate files: see our Content Security
- Policy documentation[1] for details and explanation. - Policy documentation[1] for details and explanation.
- -
- [1]: http://developer.chrome.com/extensions/contentSecurityPolicy.html - [1]: https://developer.chrome.com/extensions/contentSecurityPolicy
--> -->
<script src="popup.js"></script> <script src="popup.js"></script>
</head> </head>
<body> <body>
<div id="status"></div>
<img id="image-result" hidden>
</body> </body>
</html> </html>
// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
/** /**
* Global variable containing the query we'd like to pass to Flickr. In this * Get the current URL.
* case, kittens!
* *
* @type {string} * @param {function(string)} callback - called when the URL of the current tab
*/ * is found.
var QUERY = 'kittens'; **/
function getCurrentTabUrl(callback) {
// Query filter to be passed to chrome.tabs.query - see
// https://developer.chrome.com/extensions/tabs#method-query
var queryInfo = {
active: true,
currentWindow: true
};
chrome.tabs.query(queryInfo, function(tabs) {
// chrome.tabs.query invokes the callback with a list of tabs that match the
// query. When the popup is opened, there is certainly a window and at least
// one tab, so we can safely assume that |tabs| is a non-empty array.
// A window can only have one active tab at a time, so the array consists of
// exactly one tab.
var tab = tabs[0];
// A tab is a plain object that provides information about the tab.
// See https://developer.chrome.com/extensions/tabs#type-Tab
var url = tab.url;
var kittenGenerator = { // tab.url is only available if the "activeTab" permission is declared.
/** // If you want to see the URL of other tabs (e.g. after removing active:true
* Flickr URL that will give us lots and lots of whatever we're looking for. // from |queryInfo|), then the "tabs" permission is required to see their
* // "url" properties.
* See http://www.flickr.com/services/api/flickr.photos.search.html for console.assert(typeof url == 'string', 'tab.url should be a string');
* details about the construction of this URL.
*
* @type {string}
* @private
*/
searchOnFlickr_: 'https://secure.flickr.com/services/rest/?' +
'method=flickr.photos.search&' +
'api_key=90485e931f687a9b9c2a66bf58a3861a&' +
'text=' + encodeURIComponent(QUERY) + '&' +
'safe_search=1&' +
'content_type=1&' +
'sort=interestingness-desc&' +
'per_page=20',
/** callback(url);
* Sends an XHR GET request to grab photos of lots and lots of kittens. The });
* XHR's 'onload' event is hooks up to the 'showPhotos_' method.
*
* @public
*/
requestKittens: function() {
var req = new XMLHttpRequest();
req.open("GET", this.searchOnFlickr_, true);
req.onload = this.showPhotos_.bind(this);
req.send(null);
},
/** // Most methods of the Chrome extension APIs are asynchronous. This means that
* Handle the 'onload' event of our kitten XHR request, generated in // you CANNOT do something like this:
* 'requestKittens', by generating 'img' elements, and stuffing them into //
* the document for display. // var url;
* // chrome.tabs.query(queryInfo, function(tabs) {
* @param {ProgressEvent} e The XHR ProgressEvent. // url = tabs[0].url;
* @private // });
*/ // alert(url); // Shows "undefined", because chrome.tabs.query is async.
showPhotos_: function (e) { }
var kittens = e.target.responseXML.querySelectorAll('photo');
for (var i = 0; i < kittens.length; i++) { /**
var img = document.createElement('img'); * @param {string} searchTerm - Search term for Google Image search.
img.src = this.constructKittenURL_(kittens[i]); * @param {function(string,number,number)} callback - Called when an image has
img.setAttribute('alt', kittens[i].getAttribute('title')); * been found. The callback gets the URL, width and height of the image.
document.body.appendChild(img); * @param {function(string)} errorCallback - Called when the image is not found.
* The callback gets a string that describes the failure reason.
*/
function getImageUrl(searchTerm, callback, errorCallback) {
// Google image search - 100 searches per day.
// https://developers.google.com/image-search/
var searchUrl = 'https://ajax.googleapis.com/ajax/services/search/images' +
'?v=1.0&q=' + encodeURIComponent(searchTerm);
var x = new XMLHttpRequest();
x.open('GET', searchUrl);
// The Google image search API responds with JSON, so let Chrome parse it.
x.responseType = 'json';
x.onload = function() {
// Parse and process the response from Google Image Search.
var response = x.response;
if (!response || !response.responseData || !response.responseData.results ||
response.responseData.results.length === 0) {
errorCallback('No response from Google Image search!');
return;
} }
}, var firstResult = response.responseData.results[0];
// Take the thumbnail instead of the full image to get an approximately
// consistent image size.
var imageUrl = firstResult.tbUrl;
var width = parseInt(firstResult.tbWidth);
var height = parseInt(firstResult.tbHeight);
console.assert(
typeof imageUrl == 'string' && !isNaN(width) && !isNaN(height),
'Unexpected respose from the Google Image Search API!');
callback(imageUrl, width, height);
};
x.onerror = function() {
errorCallback('Network error.');
};
x.send();
}
function renderStatus(statusText) {
document.getElementById('status').textContent = statusText;
}
document.addEventListener('DOMContentLoaded', function() {
getCurrentTabUrl(function(url) {
// Put the image URL in Google search.
renderStatus('Performing Google Image search for ' + url);
getImageUrl(url, function(imageUrl, width, height) {
/** renderStatus('Search term: ' + url + '\n' +
* Given a photo, construct a URL using the method outlined at 'Google image search result: ' + imageUrl);
* http://www.flickr.com/services/api/misc.urlKittenl var imageResult = document.getElementById('image-result');
* // Explicitly set the width/height to minimize the number of reflows. For
* @param {DOMElement} A kitten. // a single image, this does not matter, but if you're going to embed
* @return {string} The kitten's URL. // multiple external images in your page, then the absence of width/height
* @private // attributes causes the popup to resize multiple times.
*/ imageResult.width = width;
constructKittenURL_: function (photo) { imageResult.height = height;
return "http://farm" + photo.getAttribute("farm") + imageResult.src = imageUrl;
".static.flickr.com/" + photo.getAttribute("server") + imageResult.hidden = false;
"/" + photo.getAttribute("id") +
"_" + photo.getAttribute("secret") +
"_s.jpg";
}
};
// Run our kitten generation script as soon as the document's DOM is ready. }, function(errorMessage) {
document.addEventListener('DOMContentLoaded', function () { renderStatus('Cannot display image. ' + errorMessage);
kittenGenerator.requestKittens(); });
});
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment