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,
"name": "One-click Kittens",
"description": "This extension demonstrates a 'browser action' with kittens.",
"name": "Getting started example",
"description": "This extension shows a Google Image search result for the current page",
"version": "1.0",
"browser_action": {
......@@ -10,6 +10,7 @@
"default_popup": "popup.html"
},
"permissions": [
"https://secure.flickr.com/"
"activeTab",
"https://ajax.googleapis.com/"
]
}
<!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>
<head>
<title>Getting Started Extension's Popup</title>
<style>
body {
min-width: 357px;
overflow-x: hidden;
font-family: "Segoe UI", "Lucida Grande", Tahoma, sans-serif;
font-size: 100%;
}
img {
margin: 5px;
border: 2px solid black;
vertical-align: middle;
width: 75px;
height: 75px;
#status {
/* avoid an excessively wide status text */
white-space: pre;
text-overflow: ellipsis;
overflow: hidden;
max-width: 400px;
}
</style>
......@@ -21,11 +25,13 @@
- JavaScript and HTML must be in separate files: see our Content Security
- 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>
</head>
<body>
<div id="status"></div>
<img id="image-result" hidden>
</body>
</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
// found in the LICENSE file.
/**
* Global variable containing the query we'd like to pass to Flickr. In this
* case, kittens!
* Get the current URL.
*
* @type {string}
*/
var QUERY = 'kittens';
* @param {function(string)} callback - called when the URL of the current tab
* is found.
**/
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
};
var kittenGenerator = {
/**
* Flickr URL that will give us lots and lots of whatever we're looking for.
*
* See http://www.flickr.com/services/api/flickr.photos.search.html for
* 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',
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];
/**
* 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);
},
// 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;
/**
* Handle the 'onload' event of our kitten XHR request, generated in
* 'requestKittens', by generating 'img' elements, and stuffing them into
* the document for display.
*
* @param {ProgressEvent} e The XHR ProgressEvent.
* @private
*/
showPhotos_: function (e) {
var kittens = e.target.responseXML.querySelectorAll('photo');
for (var i = 0; i < kittens.length; i++) {
var img = document.createElement('img');
img.src = this.constructKittenURL_(kittens[i]);
img.setAttribute('alt', kittens[i].getAttribute('title'));
document.body.appendChild(img);
}
},
// 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
// from |queryInfo|), then the "tabs" permission is required to see their
// "url" properties.
console.assert(typeof url == 'string', 'tab.url should be a string');
/**
* Given a photo, construct a URL using the method outlined at
* http://www.flickr.com/services/api/misc.urlKittenl
*
* @param {DOMElement} A kitten.
* @return {string} The kitten's URL.
* @private
callback(url);
});
// Most methods of the Chrome extension APIs are asynchronous. This means that
// you CANNOT do something like this:
//
// var url;
// chrome.tabs.query(queryInfo, function(tabs) {
// url = tabs[0].url;
// });
// alert(url); // Shows "undefined", because chrome.tabs.query is async.
}
/**
* @param {string} searchTerm - Search term for Google Image search.
* @param {function(string,number,number)} callback - Called when an image has
* been found. The callback gets the URL, width and height of the image.
* @param {function(string)} errorCallback - Called when the image is not found.
* The callback gets a string that describes the failure reason.
*/
constructKittenURL_: function (photo) {
return "http://farm" + photo.getAttribute("farm") +
".static.flickr.com/" + photo.getAttribute("server") +
"/" + photo.getAttribute("id") +
"_" + photo.getAttribute("secret") +
"_s.jpg";
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' +
'Google image search result: ' + imageUrl);
var imageResult = document.getElementById('image-result');
// Explicitly set the width/height to minimize the number of reflows. For
// a single image, this does not matter, but if you're going to embed
// multiple external images in your page, then the absence of width/height
// attributes causes the popup to resize multiple times.
imageResult.width = width;
imageResult.height = height;
imageResult.src = imageUrl;
imageResult.hidden = false;
// Run our kitten generation script as soon as the document's DOM is ready.
document.addEventListener('DOMContentLoaded', function () {
kittenGenerator.requestKittens();
}, function(errorMessage) {
renderStatus('Cannot display image. ' + errorMessage);
});
});
});
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