summaryrefslogtreecommitdiffstats
path: root/chrome/common/extensions/docs/examples
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/common/extensions/docs/examples')
-rw-r--r--chrome/common/extensions/docs/examples/api/webNavigation/basic.zipbin0 -> 22569 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/webNavigation/basic/_locales/en/messages.json52
-rw-r--r--chrome/common/extensions/docs/examples/api/webNavigation/basic/background.html29
-rw-r--r--chrome/common/extensions/docs/examples/api/webNavigation/basic/icon.pngbin0 -> 3789 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/webNavigation/basic/manifest.json16
-rw-r--r--chrome/common/extensions/docs/examples/api/webNavigation/basic/navigation_collector.js371
-rw-r--r--chrome/common/extensions/docs/examples/api/webNavigation/basic/popup.html103
7 files changed, 571 insertions, 0 deletions
diff --git a/chrome/common/extensions/docs/examples/api/webNavigation/basic.zip b/chrome/common/extensions/docs/examples/api/webNavigation/basic.zip
new file mode 100644
index 0000000..496714e
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/webNavigation/basic.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/api/webNavigation/basic/_locales/en/messages.json b/chrome/common/extensions/docs/examples/api/webNavigation/basic/_locales/en/messages.json
new file mode 100644
index 0000000..704131d
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/webNavigation/basic/_locales/en/messages.json
@@ -0,0 +1,52 @@
+{
+ "extName": {
+ "message": "WebNavigation Tech Demo",
+ "description": "The extension name."
+ },
+ "extDescription": {
+ "message": "Demonstration of the WebNavigation extension API.",
+ "description": "The extension description."
+ },
+
+ "navigationDescription": {
+ "message": ", requested $NUM$ times. Loaded in an average of $LOAD$ miliseconds.",
+ "description": "The message posted in the popup for each stored navigation.",
+ "placeholders": {
+ "NUM": {
+ "content": "$1",
+ "example": "4 (The number of times this URL was accessed.)"
+ },
+ "LOAD": {
+ "content": "$2",
+ "example": "12.345 (The average load time in miliseconds.)"
+ }
+ }
+ },
+
+ "inHandler": {
+ "message": "In webNavigation[`%s`] handler: %o",
+ "description": "Notification displayed for each webNavigation event."
+ },
+
+ "inHandlerError": {
+ "message": "In webNavigation[`%s`] handler: No data!",
+ "description": "Notification displayed in a webNavigation event handler without data!"
+ },
+
+ "errorCommittedWithoutPending": {
+ "message": "Wha? `onCommitted` for `%s` called, though it's not pending: %o",
+ "description": "Error logged when `onCommitted` is triggered on a non-pending request."
+ },
+ "errorCommittedWithoutPending": {
+ "message": "Wha? `onCompleted` for `%s` called, though it's not pending: %o",
+ "description": "Error logged when `onCompleted` is triggered on a non-pending request."
+ },
+ "errorErrorOccurredWithoutPending": {
+ "message": "Wha? `onErrorOccurred` for `%s` called, though it's not pending: %o",
+ "description": "Error logged when `onErrorOccurred` is triggered on a non-pending request."
+ },
+ "errorCommittedWithoutPending": {
+ "message": "Wha? `onCompleted` for `%s` called, though it's not pending: %o",
+ "description": "Error logged when `onCompleted` is triggered on a non-pending request."
+ }
+}
diff --git a/chrome/common/extensions/docs/examples/api/webNavigation/basic/background.html b/chrome/common/extensions/docs/examples/api/webNavigation/basic/background.html
new file mode 100644
index 0000000..138e8d0
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/webNavigation/basic/background.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<!--
+ * Copyright (c) 2011 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.
+-->
+<html>
+ <head>
+ <title>WebNavigation Sample Extension Background Page</title>
+ </head>
+ <body>
+ <script src='./navigation_collector.js'></script>
+ <script>
+ var nav = new NavigationCollector();
+
+ var eventList = ['onBeforeNavigate', 'onBeforeRetarget', 'onCommitted',
+ 'onCompleted', 'onDOMContentLoaded', 'onErrorOccurred'];
+
+ eventList.forEach(function(e) {
+ chrome.experimental.webNavigation[e].addListener(function(data) {
+ if (typeof data)
+ console.log(chrome.i18n.getMessage('inHandler'), e, data);
+ else
+ console.error(chrome.i18n.getMessage('inHandlerError'), e);
+ });
+ });
+ </script>
+ </body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/api/webNavigation/basic/icon.png b/chrome/common/extensions/docs/examples/api/webNavigation/basic/icon.png
new file mode 100644
index 0000000..103ff36
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/webNavigation/basic/icon.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/api/webNavigation/basic/manifest.json b/chrome/common/extensions/docs/examples/api/webNavigation/basic/manifest.json
new file mode 100644
index 0000000..538417e
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/webNavigation/basic/manifest.json
@@ -0,0 +1,16 @@
+{
+ "name": "__MSG_extName__",
+ "version": "0.1",
+ "description": "__MSG_extDescription__",
+ "default_locale": "en",
+ "background_page": "background.html",
+ "browser_action": {
+ "default_icon": "icon.png",
+ "popup": "popup.html"
+ },
+ "permissions": [
+ "extension",
+ "experimental",
+ "webNavigation"
+ ]
+}
diff --git a/chrome/common/extensions/docs/examples/api/webNavigation/basic/navigation_collector.js b/chrome/common/extensions/docs/examples/api/webNavigation/basic/navigation_collector.js
new file mode 100644
index 0000000..9a7b608
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/webNavigation/basic/navigation_collector.js
@@ -0,0 +1,371 @@
+// Copyright (c) 2011 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.
+
+/**
+ * Implements the NavigationCollector object that powers the extension.
+ *
+ * @author mkwst@google.com (Mike West)
+ */
+
+/**
+ * Collects navigation events, and provides a list of successful requests
+ * that you can do interesting things with. Calling the constructor will
+ * automatically bind handlers to the relevant webnavigation API events,
+ * and to a `getMostRequestedUrls` extension message for internal
+ * communication between background pages and popups.
+ *
+ * @constructor
+ */
+function NavigationCollector() {
+ /**
+ * A list of currently pending requests, implemented as a hash of each
+ * request's tab ID, frame ID, and URL in order to ensure uniqueness.
+ *
+ * @type {Object.<string, {start: number}>}
+ * @private
+ */
+ this.pending_ = {};
+
+ /**
+ * A list of completed requests, implemented as a hash of each
+ * request's tab ID, frame ID, and URL in order to ensure uniqueness.
+ *
+ * @type {Object.<string, Array.<NavigationCollector.Request>>}
+ * @private
+ */
+ this.completed_ = {};
+
+ /**
+ * A list of requests that errored off, implemented as a hash of each
+ * request's tab ID, frame ID, and URL in order to ensure uniqueness.
+ *
+ * @type {Object.<string, Array.<NavigationCollector.Request>>}
+ * @private
+ */
+ this.errored_ = {};
+
+ // Bind handlers to the 'webNavigation' events that we're interested
+ // in handling in order to build up a complete picture of the whole
+ // navigation event.
+ chrome.experimental.webNavigation.onBeforeRetarget.addListener(
+ this.onBeforeRetargetListener_.bind(this));
+ chrome.experimental.webNavigation.onBeforeNavigate.addListener(
+ this.onBeforeNavigateListener_.bind(this));
+ chrome.experimental.webNavigation.onCompleted.addListener(
+ this.onCompletedListener_.bind(this));
+ chrome.experimental.webNavigation.onCommitted.addListener(
+ this.onCommittedListener_.bind(this));
+ chrome.experimental.webNavigation.onErrorOccurred.addListener(
+ this.onErrorOccurredListener_.bind(this));
+
+ // Bind handler to extension messages for communication from popup.
+ chrome.extension.onRequest.addListener(this.onRequestListener_.bind(this));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * The possible transition types that explain how the navigation event
+ * was generated (i.e. "The user clicked on a link." or "The user submitted
+ * a form").
+ *
+ * @see http://code.google.com/chrome/extensions/trunk/history.html
+ * @enum {string}
+ */
+NavigationCollector.NavigationType = {
+ AUTO_BOOKMARK: 'auto_bookmark',
+ AUTO_SUBFRAME: 'auto_subframe',
+ FORM_SUBMIT: 'form_submit',
+ GENERATED: 'generated',
+ KEYWORD: 'keyword',
+ KEYWORD_GENERATED: 'keyword_generated',
+ LINK: 'link',
+ MANUAL_SUBFRAME: 'manual_subframe',
+ RELOAD: 'reload',
+ START_PAGE: 'start_page',
+ TYPED: 'typed'
+};
+
+/**
+ * The possible transition qualifiers:
+ *
+ * * CLIENT_REDIRECT: Redirects caused by JavaScript, or a refresh meta tag
+ * on a page.
+ *
+ * * SERVER_REDIRECT: Redirected by the server via a 301/302 response.
+ *
+ * * FORWARD_BACK: User used the forward or back buttons to navigate through
+ * her browsing history.
+ *
+ * @enum {string}
+ */
+NavigationCollector.NavigationQualifier = {
+ CLIENT_REDIRECT: 'client_redirect',
+ FORWARD_BACK: 'forward_back',
+ SERVER_REDIRECT: 'server_redirect'
+};
+
+/**
+ * @typedef {{url: string, transitionType: NavigationCollector.NavigationType,
+ * transitionQualifier: Array.<NavigationCollector.NavigationQualifier>,
+ * openedInNewTab: boolean, sourceUrl: ?string, duration: number}}
+ */
+NavigationCollector.Request;
+
+///////////////////////////////////////////////////////////////////////////////
+
+NavigationCollector.prototype = {
+ /**
+ * Returns a somewhat unique ID for a given WebNavigation request.
+ *
+ * @param {!{tabId: number, frameId: number, url: string}} data Information
+ * about the navigation event we'd like an ID for.
+ * @return {!string} ID created by combining the tab ID and frame ID (as the
+ * API ensures that these will be unique across a single navigation
+ * event)
+ * @private
+ */
+ parseId_: function(data) {
+ return data.tabId + '-' + data.frameId;
+ },
+
+
+ /**
+ * Creates an empty entry in the pending array, and prepopulates the
+ * errored and completed arrays for ease of insertion later.
+ *
+ * @param {!string} id The request's ID, as produced by parseId_.
+ * @param {!string} url The request's URL.
+ */
+ prepareDataStorage_: function(id, url) {
+ this.pending_[id] = this.pending_[id] || {
+ openedInNewTab: false,
+ sourceUrl: null,
+ start: null,
+ transitionQualifiers: [],
+ transitionType: null
+ };
+ this.completed_[url] = this.completed_[url] || [];
+ this.errored_[url] = this.errored_[url] || [];
+ },
+
+
+ /**
+ * Handler for the 'onBeforeRetarget' event. Updates the pending request
+ * with a sourceUrl, and notes that it was opened in a new tab.
+ *
+ * Pushes the request onto the
+ * 'pending_' object, and stores it for later use.
+ *
+ * @param {!Object} data The event data generated for this request.
+ * @private
+ */
+ onBeforeRetargetListener_: function(data) {
+ var id = this.parseId_(data);
+ this.prepareDataStorage_(id, data.url);
+ this.pending_[id].openedInNewTab = true;
+ this.pending_[id].sourceUrl = data.sourceUrl;
+ this.pending_[id].start = data.timeStamp;
+ },
+
+
+ /**
+ * Handler for the 'onBeforeNavigate' event. Pushes the request onto the
+ * 'pending_' object, and stores it for later use.
+ *
+ * @param {!Object} data The event data generated for this request.
+ * @private
+ */
+ onBeforeNavigateListener_: function(data) {
+ var id = this.parseId_(data);
+ this.prepareDataStorage_(id, data.url);
+ this.pending_[id].start = this.pending_[id].start || data.timeStamp;
+ },
+
+
+ /**
+ * Handler for the 'onCommitted' event. Updates the pending request with
+ * transition information.
+ *
+ * Pushes the request onto the
+ * 'pending_' object, and stores it for later use.
+ *
+ * @param {!Object} data The event data generated for this request.
+ * @private
+ */
+ onCommittedListener_: function(data) {
+ var id = this.parseId_(data);
+ if (!this.pending_[id]) {
+ console.warn(
+ chrome.i18n.getMessage('errorCommittedWithoutPending'),
+ data.url,
+ data);
+ } else {
+ this.pending_[id].transitionType = data.transitionType;
+ this.pending_[id].transitionQualifiers =
+ data.transitionQualifiers;
+ }
+ },
+
+
+ /**
+ * Handler for the 'onCompleted` event. Pulls the request's data from the
+ * 'pending_' object, combines it with the completed event's data, and pushes
+ * a new NavigationCollector.Request object onto 'completed_'.
+ *
+ * @param {!Object} data The event data generated for this request.
+ * @private
+ */
+ onCompletedListener_: function(data) {
+ var id = this.parseId_(data);
+ if (!this.pending_[id]) {
+ console.warn(
+ chrome.i18n.getMessage('errorCompletedWithoutPending'),
+ data.url,
+ data);
+ } else {
+ this.completed_[data.url].push({
+ duration: (data.timeStamp - this.pending_[id].start),
+ openedInNewWindow: this.pending_[id].openedInNewWindow,
+ sourceUrl: this.pending_[id].sourceUrl,
+ transitionQualifiers: this.pending_[id].transitionQualifiers,
+ transitionType: this.pending_[id].transitionType,
+ url: data.url
+ });
+ delete this.pending_[id];
+ }
+ },
+
+
+ /**
+ * Handler for the 'onErrorOccurred` event. Pulls the request's data from the
+ * 'pending_' object, combines it with the completed event's data, and pushes
+ * a new NavigationCollector.Request object onto 'errored_'.
+ *
+ * @param {!Object} data The event data generated for this request.
+ * @private
+ */
+ onErrorOccurredListener_: function(data) {
+ var id = this.parseId_(data);
+ if (!this.pending_[id]) {
+ console.error(
+ chrome.i18n.getMessage('errorErrorOccurredWithoutPending'),
+ data.url,
+ data);
+ } else {
+ this.errored_[data.url].push({
+ duration: (data.timeStamp - this.pending_[id].start),
+ openedInNewWindow: this.pending_[id].openedInNewWindow,
+ sourceUrl: this.pending_[id].sourceUrl,
+ transitionQualifiers: this.pending_[id].transitionQualifiers,
+ transitionType: this.pending_[id].transitionType,
+ url: data.url
+ });
+ delete this.pending_[id];
+ }
+ },
+
+ /**
+ * Handle request messages from the popup.
+ *
+ * @param {!{type:string}} request The external request to answer.
+ * @param {!MessageSender} sender Info about the script context that sent
+ * the request.
+ * @param {!function} sendResponse Function to call to send a response.
+ * @private
+ */
+ onRequestListener_: function(request, sender, sendResponse) {
+ if (request.type === 'getMostRequestedUrls')
+ sendResponse({result: this.getMostRequestedUrls(request.num)});
+ else
+ sendResponse({});
+ },
+
+///////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @return {Object.<string, NavigationCollector.Request>} The complete list of
+ * successful navigation requests.
+ */
+ get completed() {
+ return this.completed_;
+ },
+
+
+ /**
+ * @return {Object.<string, Navigationcollector.Request>} The complete list of
+ * unsuccessful navigation requests.
+ */
+ get errored() {
+ return this.errored_;
+ },
+
+
+ /**
+ * Get a list of the X most requested URLs.
+ *
+ * @param {number=} num The number of successful navigation requests to
+ * return. If 0 is passed in, or the argument left off entirely, all
+ * successful requests are returned.
+ * @return {Object.<string, NavigationCollector.Request>} The list of
+ * successful navigation requests, sorted in decending order of frequency.
+ */
+ getMostRequestedUrls: function(num) {
+ return this.getMostFrequentUrls_(this.completed, num);
+ },
+
+
+ /**
+ * Get a list of the X most errored URLs.
+ *
+ * @param {number=} num The number of unsuccessful navigation requests to
+ * return. If 0 is passed in, or the argument left off entirely, all
+ * successful requests are returned.
+ * @return {Object.<string, NavigationCollector.Request>} The list of
+ * unsuccessful navigation requests, sorted in decending order
+ * of frequency.
+ */
+ getMostErroredUrls: function(num) {
+ return this.getMostErroredUrls_(this.errored, num);
+ },
+
+
+ /**
+ * Get a list of the most frequent URLs in a list.
+ *
+ * @param {NavigationCollector.Request} list A list of URLs to parse.
+ * @param {number=} num The number of navigation requests to return. If
+ * 0 is passed in, or the argument left off entirely, all requests
+ * are returned.
+ * @return {Object.<string, NavigationCollector.Request>} The list of
+ * navigation requests, sorted in decending order of frequency.
+ * @private
+ */
+ getMostFrequentUrls_: function(list, num) {
+ var result = [];
+ var avg;
+ // Convert the 'completed_' object to an array.
+ for (var x in list) {
+ avg = 0;
+ if (list.hasOwnProperty(x)) {
+ list[x].forEach(function(o) {
+ avg += o.duration;
+ });
+ avg = avg / list[x].length;
+ result.push({
+ url: x,
+ numRequests: list[x].length,
+ requestList: list[x],
+ average: avg
+ });
+ }
+ }
+ // Sort the array.
+ result.sort(function(a, b) {
+ return b.numRequests - a.numRequests;
+ });
+ // Return the requested number of results.
+ return num ? result.slice(0, num) : result;
+ }
+};
diff --git a/chrome/common/extensions/docs/examples/api/webNavigation/basic/popup.html b/chrome/common/extensions/docs/examples/api/webNavigation/basic/popup.html
new file mode 100644
index 0000000..55956aa
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/webNavigation/basic/popup.html
@@ -0,0 +1,103 @@
+<!doctype html>
+<!--
+ * Copyright (c) 2011 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.
+-->
+<html>
+ <head>
+ <title>WebNavigation Tech Demo Popup</title>
+ <style>
+ body {
+ margin: 5px 10px 10px;
+ }
+
+ h1 {
+ color: #53637D;
+ font: 26px/1.2 Helvetica, sans-serif;
+ font-size: 200%;
+ margin: 0;
+ padding-bottom: 4px;
+ text-shadow: white 0 1px 2px;
+ }
+
+ body > section {
+ border-radius: 5px;
+ background: -webkit-linear-gradient(rgba(234, 238, 243, 0.2), #EAEEF3),
+ -webkit-linear-gradient(
+ left, #EAEEF3, #EAEEF3 97%, #D3D7DB);
+ font: 14px/1 Arial,Sans Serif;
+ padding: 10px;
+ width: 563px;
+ max-height: 400px;
+ overflow-y: auto;
+ box-shadow: inset 0px 2px 5px rgba(0,0,0,0.5);
+ }
+
+ body > section > ol {
+ padding: 0;
+ margin: 0;
+ list-style: none inside;
+ }
+
+ body > section > ol > li {
+ position: relative;
+ margin: 0.5em 0 0.5em 40px;
+ }
+
+ code {
+ word-wrap: break-word;
+ background: rgba(255,255,0, 0.5);
+ }
+
+ em {
+ position: absolute;
+ top: 0px;
+ left: -40px;
+ width: 30px;
+ text-align: right;
+ font: 30px/1 Helvetica, sans-serif;
+ font-weight: 700;
+ }
+
+ p {
+ min-height: 30px;
+ line-height: 1.2;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>Most Requested URLs</h1>
+ <section></section>
+ <script>
+ chrome.extension.sendRequest(
+ {'type': 'getMostRequestedUrls'},
+ function generateList(response) {
+ var section = document.querySelector('body>section');
+ var results = response.result;
+ var ol = document.createElement('ol');
+ var li, p, em, code, text;
+ var i;
+ for (i = 0; i < results.length; i++ ) {
+ li = document.createElement('li');
+ p = document.createElement('p');
+ em = document.createElement('em');
+ em.textContent = i + 1;
+ code = document.createElement('code');
+ code.textContent = results[i].url;
+ text = document.createTextNode(
+ chrome.i18n.getMessage('navigationDescription',
+ [results[i].numRequests,
+ results[i].average]));
+ p.appendChild(em);
+ p.appendChild(code);
+ p.appendChild(text);
+ li.appendChild(p);
+ ol.appendChild(li);
+ }
+ section.innerHTML = '';
+ section.appendChild(ol);
+ });
+ </script>
+ </body>
+</html>