diff --git a/README.md b/README.md
index a4e89eb..b3aede8 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,16 @@
-chrome-extensions-example
-=========================
+chrome-extensions-examples
+==========================
-The [Chrome Extensions examples](http://developer.chrome.com/extensions/samples.html) did not
+The [Chrome Extensions examples](http://developer.chrome.com/extensions/samples) did not
exist as a Git repository, and browsing both the samples page and the VCViewer did not seem particularly
handy. So, I decided to scrape the content into this repository for easier browsing and (possible)
editing.
-If you would like to clone a part of this repository, use git
+If you would like to clone a part of this repository, use git
[sparse checkouts](http://jasonkarns.com/blog/subdirectory-checkouts-with-git-sparse-checkout/).
-You can find the scraper used to generate this repository (except for a `git init` and push)
+You can find the scraper used to generate this repository (except for a `git init` and push)
on [github](https://github.com/orbitbot/chrome-extension-scraper).
@@ -42,13 +42,11 @@ Example projects
* [Chromium IRC App](/app_2/)
* [Chromium Search](/chrome_search/)
* [Console TTS Engine](/console_tts_engine/)
-* [Content Script Cross-Domain XMLHttpRequest Example](/contentscript_xhr/)
* [Content settings](/contentSettings/)
* [Context Menus Sample](/basic_2/)
* [Context Menus Sample (with Event Page)](/event_page/)
* [Cookie API Test Extension](/cookies/)
* [Desktop Capture Example](/desktopCapture/)
-* [Download Filename Controller](/download_filename_controller/)
* [Download Manager Button](/download_manager/)
* [Download Selected Links](/download_links/)
* [Download and Open Button](/download_open/)
@@ -56,7 +54,10 @@ Example projects
* [Email this page (by Google)](/email_this_page/)
* [Event Page Example](/basic_4/)
* [Event Tracking with Google Analytics](/analytics/)
+* [Fake Archive Handler App](/archive/)
+* [File System Provider API Extension Example](/basic_5/)
* [FirePHP for Chrome](/chrome-firephp/)
+* [Getting started example](/getstarted/)
* [Google Calendar Checker (by Google)](/calendar/)
* [Google Document List Viewer](/gdocs/)
* [Google Mail Checker](/gmail/)
@@ -67,6 +68,7 @@ Example projects
* [Keep Awake](/power/)
* [Keyboard Pin](/pin/)
* [Live HTTP headers](/live-headers/)
+* [Managed Bookmarks](/managed_bookmarks/)
* [Mappy](/mappy/)
* [Merge Windows](/merge_windows/)
* [Message Timer](/timer/)
@@ -80,8 +82,6 @@ Example projects
* [News Reader (by Google)](/news/)
* [Notification Demo](/notifications/)
* [Omnibox Example](/simple-example/)
-* [One-click Kittens](/getstarted/)
-* [Page Benchmarker](/benchmark/)
* [Page Redder](/make_page_red/)
* [Page action by URL](/pageaction_by_url/)
* [Page action by content](/pageaction_by_content/)
@@ -92,7 +92,6 @@ Example projects
* [Sample - OAuth Contacts](/oauth_contacts/)
* [Sample Extension Commands extension](/commands/)
* [Sandboxed Frame](/sandbox/)
-* [SandwichBar](/sandwichbar/)
* [Show Tabs in Process](/show_tabs/)
* [Simple Background App](/background-simple/)
* [Speak Selection](/speak_selection/)
@@ -101,12 +100,13 @@ Example projects
* [TTS Demo](/ttsdemo/)
* [Tab Inspector](/inspector/)
* [Tab Shortcuts](/tab_shortcuts/)
+* [Tabs Zoom API Demo](/zoom/)
* [Talking Alarm Clock](/talking_alarm_clock/)
-* [Test IME](/basic_5/)
+* [Test IME](/basic_6/)
* [Test Screenshot Extension](/screenshot/)
* [Top Chrome Extension Questions](/extension-questions/)
-* [Top Sites](/basic_6/)
+* [Top Sites](/basic_7/)
* [Typed URL History](/showHistory/)
-* [WebNavigation Tech Demo](/basic_7/)
+* [WebNavigation Tech Demo](/basic_8/)
* [`extension.isAllowedFileSchemeAccess` and `extension.isAllowedIncognitoAccess` Example](/isAllowedAccess/)
* [iGoogle new tab page](/override_igoogle/)
\ No newline at end of file
diff --git a/allowThirdPartyCookies/README.md b/allowThirdPartyCookies/README.md
index eda2f7b..56fed86 100644
--- a/allowThirdPartyCookies/README.md
+++ b/allowThirdPartyCookies/README.md
@@ -11,5 +11,4 @@ Content is licensed under the [Google BSD License](http://code.google.com/google
Calls
-----
-* [extension.isAllowedIncognitoAccess](http://developer.chrome.com/extensions/extension.html#method-isAllowedIncognitoAccess)
-* [privacy.websites.thirdPartyCookiesAllowed](http://developer.chrome.com/extensions/privacy.html#property-websites-thirdPartyCookiesAllowed)
\ No newline at end of file
+* [extension.isAllowedIncognitoAccess](https://developer.chrome.com/extensions/extension#method-isAllowedIncognitoAccess)
\ No newline at end of file
diff --git a/app/README.md b/app/README.md
index dd7eb65..88f0793 100644
--- a/app/README.md
+++ b/app/README.md
@@ -11,5 +11,4 @@ Content is licensed under the [Google BSD License](http://code.google.com/google
Calls
-----
-* [runtime.connectNative](http://developer.chrome.com/extensions/runtime.html#method-connectNative)
-* [runtime.lastError.message](http://developer.chrome.com/extensions/runtime.html#property-lastError-message)
\ No newline at end of file
+* [runtime.connectNative](https://developer.chrome.com/extensions/runtime#method-connectNative)
\ No newline at end of file
diff --git a/app_1/README.md b/app_1/README.md
index e7e6b50..b70b216 100644
--- a/app_1/README.md
+++ b/app_1/README.md
@@ -11,9 +11,3 @@ Content is licensed under the [Google BSD License](http://code.google.com/google
Calls
-----
-* [app.runtime](http://developer.chrome.com/extensions/app.runtime.html)
-* [app.runtime.onLaunched](http://developer.chrome.com/extensions/app.runtime.html#event-onLaunched)
-* [app.runtime.onRestarted](http://developer.chrome.com/extensions/app.runtime.html#event-onRestarted)
-* [app.window.create](http://developer.chrome.com/extensions/app.window.html#method-create)
-* [storage.StorageArea.get](http://developer.chrome.com/extensions/storage.html#method-StorageArea-get)
-* [storage.StorageArea.set](http://developer.chrome.com/extensions/storage.html#method-StorageArea-set)
\ No newline at end of file
diff --git a/app_1/controller.js b/app_1/controller.js
index a3998d7..18a13e9 100644
--- a/app_1/controller.js
+++ b/app_1/controller.js
@@ -4,36 +4,29 @@
* found in the LICENSE file.
**/
-// Checking for "chrome.app.runtime" availability allows this Chrome app code to
-// be tested in a regular web page (like tests/manual.html). Checking for
-// "chrome" and "chrome.app" availability further allows this code to be tested
-// in non-Chrome browsers, which is useful for example to test touch support
-// with a non-Chrome touch device.
+// Checking for "chrome" availability allows this app code to be tested in
+// non-Chrome browsers, which is useful for example to test touch support with
+// a non-Chrome touch device.
+// Checking for "chrome.shell" allows testing under app_shell, which does not
+// have chrome.app APIs.
+// Checking for "chrome.app.runtime" availability allows testing in a regular
+// web page (like tests/manual.html).
if (typeof chrome !== 'undefined' && chrome.app && chrome.app.runtime) {
var showCalculatorWindow = function () {
chrome.app.window.create('calculator.html', {
- defaultWidth: 243, minWidth: 243, maxWidth: 243,
- defaultHeight: 380, minHeight: 380, maxHeight: 380,
+ innerBounds: {
+ width: 243, minWidth: 243, maxWidth: 243,
+ height: 380, minHeight: 380, maxHeight: 380
+ },
id: 'calculator'
}, function(appWindow) {
appWindow.contentWindow.onload = function() {
new Controller(new Model(9), new View(appWindow.contentWindow));
};
-
- chrome.storage.local.set({windowVisible: true});
- appWindow.onClosed.addListener(function() {
- chrome.storage.local.set({windowVisible: false});
- });
});
}
chrome.app.runtime.onLaunched.addListener(showCalculatorWindow);
- chrome.app.runtime.onRestarted.addListener(function() {
- chrome.storage.local.get('windowVisible', function(data) {
- if (data.windowVisible)
- showCalculatorWindow();
- });
- });
}
function Controller(model, view) {
@@ -51,21 +44,21 @@ function Controller(model, view) {
/** @private */
Controller.prototype.defineInputs_ = function() {
var inputs = {byButton: {}, byKey: {}};
- inputs.byButton['zero'] = inputs.byKey['48'] = '0';
- inputs.byButton['one'] = inputs.byKey['49'] = '1';
- inputs.byButton['two'] = inputs.byKey['50'] = '2';
- inputs.byButton['three'] = inputs.byKey['51'] = '3';
- inputs.byButton['four'] = inputs.byKey['52'] = '4';
- inputs.byButton['five'] = inputs.byKey['53'] = '5';
- inputs.byButton['six'] = inputs.byKey['54'] = '6';
- inputs.byButton['seven'] = inputs.byKey['55'] = '7';
- inputs.byButton['eight'] = inputs.byKey['56'] = '8';
- inputs.byButton['nine'] = inputs.byKey['57'] = '9';
- inputs.byButton['point'] = inputs.byKey['190'] = '.';
- inputs.byButton['add'] = inputs.byKey['^187'] = '+';
- inputs.byButton['subtract'] = inputs.byKey['189'] = '-';
- inputs.byButton['multiply'] = inputs.byKey['^56'] = '*';
- inputs.byButton['divide'] = inputs.byKey['191'] = '/';
+ inputs.byButton['zero'] = inputs.byKey['48'] = inputs.byKey['96'] = '0';
+ inputs.byButton['one'] = inputs.byKey['49'] = inputs.byKey['97'] = '1';
+ inputs.byButton['two'] = inputs.byKey['50'] = inputs.byKey['98'] = '2';
+ inputs.byButton['three'] = inputs.byKey['51'] = inputs.byKey['99'] = '3';
+ inputs.byButton['four'] = inputs.byKey['52'] = inputs.byKey['100'] = '4';
+ inputs.byButton['five'] = inputs.byKey['53'] = inputs.byKey['101'] = '5';
+ inputs.byButton['six'] = inputs.byKey['54'] = inputs.byKey['102'] = '6';
+ inputs.byButton['seven'] = inputs.byKey['55'] = inputs.byKey['103'] = '7';
+ inputs.byButton['eight'] = inputs.byKey['56'] = inputs.byKey['104'] = '8';
+ inputs.byButton['nine'] = inputs.byKey['57'] = inputs.byKey['105'] = '9';
+ inputs.byButton['point'] = inputs.byKey['190'] = inputs.byKey['110'] = '.';
+ inputs.byButton['add'] = inputs.byKey['^187'] = inputs.byKey['107'] = '+';
+ inputs.byButton['subtract'] = inputs.byKey['189'] = inputs.byKey['109'] = '-';
+ inputs.byButton['multiply'] = inputs.byKey['^56'] = inputs.byKey['106'] = '*';
+ inputs.byButton['divide'] = inputs.byKey['191'] = inputs.byKey['111'] = '/';
inputs.byButton['equals'] = inputs.byKey['187'] = inputs.byKey['13'] = '=';
inputs.byButton['negate'] = inputs.byKey['32'] = '+ / -';
inputs.byButton['clear'] = inputs.byKey['67'] = 'AC';
diff --git a/app_1/manifest.json b/app_1/manifest.json
index 76c570d..09b249e 100644
--- a/app_1/manifest.json
+++ b/app_1/manifest.json
@@ -3,11 +3,10 @@
"description": "A simple calculator.",
"manifest_version": 2,
"minimum_chrome_version": "23",
- "version": "1.3.2",
+ "version": "1.3.3",
"app": {"background": {"scripts": ["model.js", "view.js", "controller.js"]}},
"icons": {
"16": "images/icon-16x16.png",
"128": "images/icon-128x128.png"
- },
- "permissions": ["storage"]
+ }
}
diff --git a/app_launcher/README.md b/app_launcher/README.md
index db1b3f6..fdaa8c5 100644
--- a/app_launcher/README.md
+++ b/app_launcher/README.md
@@ -11,7 +11,7 @@ Content is licensed under the [Google BSD License](http://code.google.com/google
Calls
-----
-* [extension.getURL](http://developer.chrome.com/extensions/extension.html#method-getURL)
-* [management.getAll](http://developer.chrome.com/extensions/management.html#method-getAll)
-* [management.launchApp](http://developer.chrome.com/extensions/management.html#method-launchApp)
-* [tabs.create](http://developer.chrome.com/extensions/tabs.html#method-create)
\ No newline at end of file
+* [extension.getURL](https://developer.chrome.com/extensions/extension#method-getURL)
+* [management.getAll](https://developer.chrome.com/extensions/management#method-getAll)
+* [management.launchApp](https://developer.chrome.com/extensions/management#method-launchApp)
+* [tabs.create](https://developer.chrome.com/extensions/tabs#method-create)
\ No newline at end of file
diff --git a/archive/README.md b/archive/README.md
new file mode 100644
index 0000000..8651c19
--- /dev/null
+++ b/archive/README.md
@@ -0,0 +1,25 @@
+
+Fake Archive Handler App
+=======
+
+Demonstrate File System Provider API usage for apps.
+
+[Zipfile](http://developer.chrome.com/extensions/examples/api/fileSystemProvider/archive.zip)
+
+Content is licensed under the [Google BSD License](http://code.google.com/google_bsd_license.html).
+
+Calls
+-----
+
+* [fileSystemProvider.mount](https://developer.chrome.com/extensions/fileSystemProvider#method-mount)
+* [fileSystemProvider.onCloseFileRequested](https://developer.chrome.com/extensions/fileSystemProvider#event-onCloseFileRequested)
+* [fileSystemProvider.onGetMetadataRequested](https://developer.chrome.com/extensions/fileSystemProvider#event-onGetMetadataRequested)
+* [fileSystemProvider.onOpenFileRequested](https://developer.chrome.com/extensions/fileSystemProvider#event-onOpenFileRequested)
+* [fileSystemProvider.onReadDirectoryRequested](https://developer.chrome.com/extensions/fileSystemProvider#event-onReadDirectoryRequested)
+* [fileSystemProvider.onReadFileRequested](https://developer.chrome.com/extensions/fileSystemProvider#event-onReadFileRequested)
+* [fileSystemProvider.onUnmountRequested](https://developer.chrome.com/extensions/fileSystemProvider#event-onUnmountRequested)
+* [fileSystemProvider.unmount](https://developer.chrome.com/extensions/fileSystemProvider#method-unmount)
+* [runtime.onStartup](https://developer.chrome.com/extensions/runtime#event-onStartup)
+* [runtime.onSuspend](https://developer.chrome.com/extensions/runtime#event-onSuspend)
+* [storage.StorageArea.get](https://developer.chrome.com/extensions/storage#method-StorageArea-get)
+* [storage.StorageArea.set](https://developer.chrome.com/extensions/storage#method-StorageArea-set)
\ No newline at end of file
diff --git a/archive/background.js b/archive/background.js
new file mode 100644
index 0000000..09458cd
--- /dev/null
+++ b/archive/background.js
@@ -0,0 +1,247 @@
+// Copyright 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.
+
+'use strict';
+
+// Metadata is stored in files as serialized to JSON maps. See contents of
+// example1.fake and example2.fake.
+
+// Multiple volumes can be opened at the same time. The key is the
+// fileSystemId, which is the same as the file's displayPath.
+// The value is a Volume object.
+var volumes = {};
+
+// Defines a volume object that contains information about a mounted file
+// system.
+function Volume(entry, metadata, opt_openedFiles) {
+ // Used for restoring the opened file entry after resuming the event page.
+ this.entry = entry;
+
+ // The volume metadata.
+ this.metadata = [];
+ for (var path in metadata) {
+ this.metadata[path] = metadata[path];
+ // Date object is serialized in JSON as string.
+ this.metadata[path].modificationTime =
+ new Date(metadata[path].modificationTime);
+ }
+
+ // A map with currently opened files. The key is a requestId value from the
+ // openFileRequested event, and the value is the file path.
+ this.openedFiles = opt_openedFiles ? opt_openedFiles : {};
+};
+
+function onUnmountRequested(options, onSuccess, onError) {
+ if (Object.keys(volumes[options.fileSystemId].openedFiles).length != 0) {
+ onError('IN_USE');
+ return;
+ }
+
+ chrome.fileSystemProvider.unmount(
+ {fileSystemId: options.fileSystemId},
+ function() {
+ delete volumes[options.fileSystemId];
+ saveState(); // Remove volume from local storage state.
+ onSuccess();
+ },
+ function() {
+ onError('FAILED');
+ });
+};
+
+function onGetMetadataRequested(options, onSuccess, onError) {
+ restoreState(options.fileSystemId, function () {
+ var entryMetadata =
+ volumes[options.fileSystemId].metadata[options.entryPath];
+ if (!entryMetadata)
+ error('NOT_FOUND');
+ else
+ onSuccess(entryMetadata);
+ }, onError);
+};
+
+function onReadDirectoryRequested(options, onSuccess, onError) {
+ restoreState(options.fileSystemId, function () {
+ var directoryMetadata =
+ volumes[options.fileSystemId].metadata[options.directoryPath];
+ if (!directoryMetadata) {
+ onError('NOT_FOUND');
+ return;
+ }
+ if (!directoryMetadata.isDirectory) {
+ onError('NOT_A_DIRECTORY');
+ return;
+ }
+
+ // Retrieve directory contents from metadata.
+ var entries = [];
+ for (var entry in volumes[options.fileSystemId].metadata) {
+ // Do not add itself on the list.
+ if (entry == options.directoryPath)
+ continue;
+ // Check if the entry is a child of the requested directory.
+ if (entry.indexOf(options.directoryPath) != 0)
+ continue;
+ // Restrict to direct children only.
+ if (entry.substring(options.directoryPath.length + 1).indexOf('/') != -1)
+ continue;
+
+ entries.push(volumes[options.fileSystemId].metadata[entry]);
+ }
+ onSuccess(entries, false /* Last call. */);
+ }, onError);
+};
+
+function onOpenFileRequested(options, onSuccess, onError) {
+ restoreState(options.fileSystemId, function () {
+ if (options.mode != 'READ' || options.create) {
+ onError('INVALID_OPERATION');
+ } else {
+ volumes[options.fileSystemId].openedFiles[options.requestId] =
+ options.filePath;
+ onSuccess();
+ }
+ }, onError);
+};
+
+function onCloseFileRequested(options, onSuccess, onError) {
+ restoreState(options.fileSystemId, function () {
+ if (!volumes[options.fileSystemId].openedFiles[options.openRequestId]) {
+ onError('INVALID_OPERATION');
+ } else {
+ delete volumes[options.fileSystemId].openedFiles[options.openRequestId];
+ onSuccess();
+ }
+ }, onError);
+};
+
+function onReadFileRequested(options, onSuccess, onError) {
+ restoreState(options.fileSystemId, function () {
+ var filePath =
+ volumes[options.fileSystemId].openedFiles[options.openRequestId];
+ if (!filePath) {
+ onError('INVALID_OPERATION');
+ return;
+ }
+
+ var contents = volumes[options.fileSystemId].metadata[filePath].contents;
+
+ // Write the contents as ASCII text.
+ var buffer = new ArrayBuffer(options.length);
+ var bufferView = new Uint8Array(buffer);
+ for (var i = 0; i < options.length; i++) {
+ bufferView[i] = contents.charCodeAt(i);
+ }
+
+ onSuccess(buffer, false /* Last call. */);
+ }, onError);
+};
+
+// Saves state in case of restarts, event page suspend, crashes, etc.
+function saveState() {
+ var state = {};
+ for (var volumeId in volumes) {
+ var entryId = chrome.fileSystem.retainEntry(volumes[volumeId].entry);
+ state[volumeId] = {
+ entryId: entryId,
+ openedFiles: volumes[volumeId].openedFiles
+ };
+ }
+ chrome.storage.local.set({state: state});
+}
+
+// Restores metadata for the passed file system ID.
+function restoreState(fileSystemId, onSuccess, onError) {
+ chrome.storage.local.get(['state'], function(result) {
+ // Check if metadata for the given file system is alread in memory.
+ if (volumes[fileSystemId]) {
+ onSuccess();
+ return;
+ }
+
+ chrome.fileSystem.restoreEntry(
+ result.state[fileSystemId].entryId,
+ function(entry) {
+ readMetadataFromFile(entry,
+ function(metadata) {
+ volumes[fileSystemId] = new Volume(entry, metadata,
+ result.state[fileSystemId].openedFiles);
+ onSuccess();
+ }, onError);
+ });
+ });
+}
+
+// Reads metadata from a file and returns it with the onSuccess callback.
+function readMetadataFromFile(entry, onSuccess, onError) {
+ entry.file(function(file) {
+ var fileReader = new FileReader();
+ fileReader.onload = function(event) {
+ onSuccess(JSON.parse(event.target.result));
+ };
+
+ fileReader.onerror = function(event) {
+ onError('FAILED');
+ };
+
+ fileReader.readAsText(file);
+ });
+}
+
+// Event called on opening a file with the extension or mime type
+// declared in the manifest file.
+chrome.app.runtime.onLaunched.addListener(function(event) {
+ event.items.forEach(function(item) {
+ readMetadataFromFile(item.entry,
+ function(metadata) {
+ // Mount the volume and save its information in local storage
+ // in order to be able to recover the metadata in case of
+ // restarts, system crashes, etc.
+ chrome.fileSystem.getDisplayPath(item.entry, function(displayPath) {
+ volumes[displayPath] = new Volume(item.entry, metadata);
+ chrome.fileSystemProvider.mount(
+ {fileSystemId: displayPath, displayName: item.entry.name},
+ function() { saveState(); },
+ function() { console.error('Failed to mount.'); });
+ });
+ },
+ function(error) {
+ console.error(error);
+ });
+ });
+});
+
+// Event called on a profile startup.
+chrome.runtime.onStartup.addListener(function () {
+ chrome.storage.local.get(['state'], function(result) {
+ // Nothing to change.
+ if (!result.state)
+ return;
+
+ // Remove files opened before the profile shutdown from the local storage.
+ for (var volumeId in result.state) {
+ result.state[volumeId].openedFiles = {};
+ }
+ chrome.storage.local.set({state: result.state});
+ });
+});
+
+// Save the state before suspending the event page, so we can resume it
+// once new events arrive.
+chrome.runtime.onSuspend.addListener(function() {
+ saveState();
+});
+
+chrome.fileSystemProvider.onUnmountRequested.addListener(
+ onUnmountRequested);
+chrome.fileSystemProvider.onGetMetadataRequested.addListener(
+ onGetMetadataRequested);
+chrome.fileSystemProvider.onReadDirectoryRequested.addListener(
+ onReadDirectoryRequested);
+chrome.fileSystemProvider.onOpenFileRequested.addListener(
+ onOpenFileRequested);
+chrome.fileSystemProvider.onCloseFileRequested.addListener(
+ onCloseFileRequested);
+chrome.fileSystemProvider.onReadFileRequested.addListener(
+ onReadFileRequested);
diff --git a/archive/example1.fake b/archive/example1.fake
new file mode 100644
index 0000000..4bcb726
--- /dev/null
+++ b/archive/example1.fake
@@ -0,0 +1,34 @@
+{
+ "/": {
+ "isDirectory": true,
+ "name": "/",
+ "size": 0,
+ "modificationTime": "2014-06-26T08:47:11.591Z"
+ },
+ "/file1.txt": {
+ "isDirectory": false,
+ "name": "file1.txt",
+ "size": 46,
+ "modificationTime": "2014-06-26T08:47:11.591Z",
+ "contents": "It works!\nEverything gets displayed correctly."
+ },
+ "/file2": {
+ "isDirectory": false,
+ "name": "file2",
+ "size": 150,
+ "modificationTime": "2014-06-26T08:47:11.591Z"
+ },
+ "/dir": {
+ "isDirectory": true,
+ "name": "dir",
+ "size": 0,
+ "modificationTime": "2014-06-26T08:47:11.591Z"
+ },
+ "/dir/file3.txt": {
+ "isDirectory": false,
+ "name": "file3.txt",
+ "size": 21,
+ "modificationTime": "2014-06-26T08:47:11.591Z",
+ "contents": "Just another example."
+ }
+}
diff --git a/archive/example2.fake b/archive/example2.fake
new file mode 100644
index 0000000..a409b14
--- /dev/null
+++ b/archive/example2.fake
@@ -0,0 +1,15 @@
+{
+ "/": {
+ "isDirectory": true,
+ "name": "/",
+ "size": 0,
+ "modificationTime": "2014-06-26T08:47:11.591Z"
+ },
+ "/file.txt": {
+ "isDirectory": false,
+ "name": "file.txt",
+ "size": 9,
+ "modificationTime": "2014-06-26T08:47:11.591Z",
+ "contents": "It works!"
+ }
+}
diff --git a/archive/manifest.json b/archive/manifest.json
new file mode 100644
index 0000000..0fd15bc
--- /dev/null
+++ b/archive/manifest.json
@@ -0,0 +1,25 @@
+{
+ "name": "Fake Archive Handler App",
+ "version": "0.1",
+ "manifest_version": 2,
+ "description": "Demonstrate File System Provider API usage for apps.",
+ "permissions": [
+ "fileSystemProvider",
+ {"fileSystem": ["retainEntries"]},
+ "storage"
+ ],
+ "file_handlers": {
+ "fake": {
+ "types": ["application/fake"],
+ "extensions": ["fake"],
+ "title": "Open fake archive"
+ }
+ },
+ "app": {
+ "background": {
+ "scripts": [
+ "background.js"
+ ]
+ }
+ }
+}
diff --git a/background-simple/background.html b/background-simple/background.html
index 12d906e..7095d3f 100644
--- a/background-simple/background.html
+++ b/background-simple/background.html
@@ -6,9 +6,8 @@
-->
diff --git a/basic/README.md b/basic/README.md
index 015f449..fed61f3 100644
--- a/basic/README.md
+++ b/basic/README.md
@@ -11,8 +11,8 @@ Content is licensed under the [Google BSD License](http://code.google.com/google
Calls
-----
-* [bookmarks.create](http://developer.chrome.com/extensions/bookmarks.html#method-create)
-* [bookmarks.getTree](http://developer.chrome.com/extensions/bookmarks.html#method-getTree)
-* [bookmarks.remove](http://developer.chrome.com/extensions/bookmarks.html#method-remove)
-* [bookmarks.update](http://developer.chrome.com/extensions/bookmarks.html#method-update)
-* [tabs.create](http://developer.chrome.com/extensions/tabs.html#method-create)
\ No newline at end of file
+* [bookmarks.create](https://developer.chrome.com/extensions/bookmarks#method-create)
+* [bookmarks.getTree](https://developer.chrome.com/extensions/bookmarks#method-getTree)
+* [bookmarks.remove](https://developer.chrome.com/extensions/bookmarks#method-remove)
+* [bookmarks.update](https://developer.chrome.com/extensions/bookmarks#method-update)
+* [tabs.create](https://developer.chrome.com/extensions/tabs#method-create)
\ No newline at end of file
diff --git a/basic_1/README.md b/basic_1/README.md
index 70a4106..5a291ca 100644
--- a/basic_1/README.md
+++ b/basic_1/README.md
@@ -11,4 +11,4 @@ Content is licensed under the [Google BSD License](http://code.google.com/google
Calls
-----
-* [browsingData.remove](http://developer.chrome.com/extensions/browsingData.html#method-remove)
\ No newline at end of file
+* [browsingData.remove](https://developer.chrome.com/extensions/browsingData#method-remove)
\ No newline at end of file
diff --git a/basic_2/README.md b/basic_2/README.md
index 18b786a..748f7e8 100644
--- a/basic_2/README.md
+++ b/basic_2/README.md
@@ -11,6 +11,5 @@ Content is licensed under the [Google BSD License](http://code.google.com/google
Calls
-----
-* [contextMenus.create](http://developer.chrome.com/extensions/contextMenus.html#method-create)
-* [extension.lastError](http://developer.chrome.com/extensions/extension.html#property-lastError)
-* [extension.lastError.message](http://developer.chrome.com/extensions/extension.html#property-lastError-message)
\ No newline at end of file
+* [contextMenus.create](https://developer.chrome.com/extensions/contextMenus#method-create)
+* [extension.lastError](https://developer.chrome.com/extensions/extension#property-lastError)
\ No newline at end of file
diff --git a/basic_3/README.md b/basic_3/README.md
index e2b507e..13e0d72 100644
--- a/basic_3/README.md
+++ b/basic_3/README.md
@@ -11,5 +11,5 @@ Content is licensed under the [Google BSD License](http://code.google.com/google
Calls
-----
-* [signedInDevices.get](http://developer.chrome.com/extensions/signedInDevices.html#method-get)
-* [signedInDevices.onDeviceInfoChange](http://developer.chrome.com/extensions/signedInDevices.html#event-onDeviceInfoChange)
\ No newline at end of file
+* [signedInDevices.get](https://developer.chrome.com/extensions/signedInDevices#method-get)
+* [signedInDevices.onDeviceInfoChange](https://developer.chrome.com/extensions/signedInDevices#event-onDeviceInfoChange)
\ No newline at end of file
diff --git a/basic_4/README.md b/basic_4/README.md
index a394d7d..9470053 100644
--- a/basic_4/README.md
+++ b/basic_4/README.md
@@ -11,19 +11,19 @@ Content is licensed under the [Google BSD License](http://code.google.com/google
Calls
-----
-* [alarms.create](http://developer.chrome.com/extensions/alarms.html#method-create)
-* [alarms.onAlarm](http://developer.chrome.com/extensions/alarms.html#event-onAlarm)
-* [bookmarks.onRemoved](http://developer.chrome.com/extensions/bookmarks.html#event-onRemoved)
-* [browserAction.onClicked](http://developer.chrome.com/extensions/browserAction.html#event-onClicked)
-* [browserAction.setBadgeText](http://developer.chrome.com/extensions/browserAction.html#method-setBadgeText)
-* [commands.onCommand](http://developer.chrome.com/extensions/commands.html#event-onCommand)
-* [declarativeWebRequest.RedirectRequest](http://developer.chrome.com/extensions/declarativeWebRequest.html#type-RedirectRequest)
-* [declarativeWebRequest.RequestMatcher](http://developer.chrome.com/extensions/declarativeWebRequest.html#type-RequestMatcher)
-* [runtime.onInstalled](http://developer.chrome.com/extensions/runtime.html#event-onInstalled)
-* [runtime.onMessage](http://developer.chrome.com/extensions/runtime.html#event-onMessage)
-* [runtime.onSuspend](http://developer.chrome.com/extensions/runtime.html#event-onSuspend)
-* [runtime.sendMessage](http://developer.chrome.com/extensions/runtime.html#method-sendMessage)
-* [tabs.create](http://developer.chrome.com/extensions/tabs.html#method-create)
-* [tabs.executeScript](http://developer.chrome.com/extensions/tabs.html#method-executeScript)
-* [tabs.query](http://developer.chrome.com/extensions/tabs.html#method-query)
-* [tabs.sendMessage](http://developer.chrome.com/extensions/tabs.html#method-sendMessage)
\ No newline at end of file
+* [alarms.create](https://developer.chrome.com/extensions/alarms#method-create)
+* [alarms.onAlarm](https://developer.chrome.com/extensions/alarms#event-onAlarm)
+* [bookmarks.onRemoved](https://developer.chrome.com/extensions/bookmarks#event-onRemoved)
+* [browserAction.onClicked](https://developer.chrome.com/extensions/browserAction#event-onClicked)
+* [browserAction.setBadgeText](https://developer.chrome.com/extensions/browserAction#method-setBadgeText)
+* [commands.onCommand](https://developer.chrome.com/extensions/commands#event-onCommand)
+* [declarativeWebRequest.RedirectRequest](https://developer.chrome.com/extensions/declarativeWebRequest#type-RedirectRequest)
+* [declarativeWebRequest.RequestMatcher](https://developer.chrome.com/extensions/declarativeWebRequest#type-RequestMatcher)
+* [runtime.onInstalled](https://developer.chrome.com/extensions/runtime#event-onInstalled)
+* [runtime.onMessage](https://developer.chrome.com/extensions/runtime#event-onMessage)
+* [runtime.onSuspend](https://developer.chrome.com/extensions/runtime#event-onSuspend)
+* [runtime.sendMessage](https://developer.chrome.com/extensions/runtime#method-sendMessage)
+* [tabs.create](https://developer.chrome.com/extensions/tabs#method-create)
+* [tabs.executeScript](https://developer.chrome.com/extensions/tabs#method-executeScript)
+* [tabs.query](https://developer.chrome.com/extensions/tabs#method-query)
+* [tabs.sendMessage](https://developer.chrome.com/extensions/tabs#method-sendMessage)
\ No newline at end of file
diff --git a/basic_5/README.md b/basic_5/README.md
index f13ee39..9a36770 100644
--- a/basic_5/README.md
+++ b/basic_5/README.md
@@ -1,20 +1,20 @@
-Test IME
+File System Provider API Extension Example
=======
-A simple IME that converts all keystrokes to upper case.
+Demonstrate features of the API like mounting, listing directories, etc for extensions.
-[Zipfile](http://developer.chrome.com/extensions/examples/api/input.ime/basic.zip)
+[Zipfile](http://developer.chrome.com/extensions/examples/api/fileSystemProvider/basic.zip)
Content is licensed under the [Google BSD License](http://code.google.com/google_bsd_license.html).
Calls
-----
-* [input.ime](http://developer.chrome.com/extensions/input.ime.html)
-* [input.ime.commitText](http://developer.chrome.com/extensions/input.ime.html#method-commitText)
-* [input.ime.onActivate](http://developer.chrome.com/extensions/input.ime.html#event-onActivate)
-* [input.ime.onBlur](http://developer.chrome.com/extensions/input.ime.html#event-onBlur)
-* [input.ime.onDeactivated](http://developer.chrome.com/extensions/input.ime.html#event-onDeactivated)
-* [input.ime.onFocus](http://developer.chrome.com/extensions/input.ime.html#event-onFocus)
-* [input.ime.onKeyEvent](http://developer.chrome.com/extensions/input.ime.html#event-onKeyEvent)
\ No newline at end of file
+* [fileSystemProvider.mount](https://developer.chrome.com/extensions/fileSystemProvider#method-mount)
+* [fileSystemProvider.onCloseFileRequested](https://developer.chrome.com/extensions/fileSystemProvider#event-onCloseFileRequested)
+* [fileSystemProvider.onGetMetadataRequested](https://developer.chrome.com/extensions/fileSystemProvider#event-onGetMetadataRequested)
+* [fileSystemProvider.onOpenFileRequested](https://developer.chrome.com/extensions/fileSystemProvider#event-onOpenFileRequested)
+* [fileSystemProvider.onReadDirectoryRequested](https://developer.chrome.com/extensions/fileSystemProvider#event-onReadDirectoryRequested)
+* [fileSystemProvider.onReadFileRequested](https://developer.chrome.com/extensions/fileSystemProvider#event-onReadFileRequested)
+* [runtime.onInstalled](https://developer.chrome.com/extensions/runtime#event-onInstalled)
\ No newline at end of file
diff --git a/basic_5/background.js b/basic_5/background.js
new file mode 100644
index 0000000..f95a098
--- /dev/null
+++ b/basic_5/background.js
@@ -0,0 +1,119 @@
+// Copyright 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.
+
+'use strict';
+
+// Fake data similar to a file system structure.
+var MODIFICATION_DATE = new Date();
+var SHORT_CONTENTS = 'Just another example.';
+var LONGER_CONTENTS = 'It works!\nEverything gets displayed correctly.';
+
+var METADATA = {
+ '/': {isDirectory: true, name: '/', size: 0,
+ modificationTime: MODIFICATION_DATE},
+ '/file1.txt': {isDirectory: false, name: 'file1.txt',
+ size: LONGER_CONTENTS.length, modificationTime: MODIFICATION_DATE,
+ contents: LONGER_CONTENTS},
+ '/file2': {isDirectory: false, name: 'file2', size: 150,
+ modificationTime: MODIFICATION_DATE},
+ '/dir': {isDirectory: true, name: 'dir', size: 0,
+ modificationTime: MODIFICATION_DATE},
+ '/dir/file3.txt': {isDirectory: false, name: 'file3.txt',
+ size: SHORT_CONTENTS.length, modificationTime: MODIFICATION_DATE,
+ contents: SHORT_CONTENTS}};
+
+// A map with currently opened files. As key it has requestId of
+// openFileRequested and as a value the file path.
+var openedFiles = {};
+
+function onGetMetadataRequested(options, onSuccess, onError) {
+ if (!METADATA[options.entryPath])
+ onError('NOT_FOUND');
+ else
+ onSuccess(METADATA[options.entryPath]);
+}
+
+function onReadDirectoryRequested(options, onSuccess, onError) {
+ if (!METADATA[options.directoryPath]) {
+ onError('NOT_FOUND');
+ return;
+ }
+ if (!METADATA[options.directoryPath].isDirectory) {
+ onError('NOT_A_DIRECTORY');
+ return;
+ }
+
+ // Retrieve directory contents from METADATA.
+ var entries = [];
+ for (var entry in METADATA) {
+ // Do not add itself on the list.
+ if (entry == options.directoryPath)
+ continue;
+ // Check if the entry is a child of the requested directory.
+ if (entry.indexOf(options.directoryPath) != 0)
+ continue;
+ // Restrict to direct children only.
+ if (entry.substring(options.directoryPath.length + 1).indexOf('/') != -1)
+ continue;
+
+ entries.push(METADATA[entry]);
+ }
+ onSuccess(entries, false /* Last call. */);
+}
+
+function onOpenFileRequested(options, onSuccess, onError) {
+ if (options.mode != 'READ' || options.create) {
+ onError('INVALID_OPERATION');
+ } else {
+ openedFiles[options.requestId] = options.filePath;
+ onSuccess();
+ }
+}
+
+function onCloseFileRequested(options, onSuccess, onError) {
+ if (!openedFiles[options.openRequestId]) {
+ onError('INVALID_OPERATION');
+ } else {
+ delete openedFiles[options.openRequestId];
+ onSuccess();
+ }
+}
+
+function onReadFileRequested(options, onSuccess, onError) {
+ if (!openedFiles[options.openRequestId]) {
+ onError('INVALID_OPERATION');
+ return;
+ }
+
+ var contents =
+ METADATA[openedFiles[options.openRequestId]].contents;
+
+ // Write the contents as ASCII text.
+ var buffer = new ArrayBuffer(options.length);
+ var bufferView = new Uint8Array(buffer);
+ for (var i = 0; i < options.length; i++) {
+ bufferView[i] = contents.charCodeAt(i);
+ }
+
+ onSuccess(buffer, false /* Last call. */);
+}
+
+// Mount the file system.
+chrome.runtime.onInstalled.addListener(function(details) {
+ chrome.fileSystemProvider.mount(
+ {fileSystemId: 'sample-file-system', displayName: 'Sample File System'},
+ function() {},
+ function() { console.error('Failed to mount.'); });
+});
+
+chrome.fileSystemProvider.onGetMetadataRequested.addListener(
+ onGetMetadataRequested);
+chrome.fileSystemProvider.onReadDirectoryRequested.addListener(
+ onReadDirectoryRequested);
+chrome.fileSystemProvider.onOpenFileRequested.addListener(
+ onOpenFileRequested);
+chrome.fileSystemProvider.onCloseFileRequested.addListener(
+ onCloseFileRequested);
+chrome.fileSystemProvider.onReadFileRequested.addListener(
+ onReadFileRequested);
diff --git a/basic_5/manifest.json b/basic_5/manifest.json
index e21aec1..c480355 100644
--- a/basic_5/manifest.json
+++ b/basic_5/manifest.json
@@ -1,22 +1,15 @@
{
- "name": "Test IME",
- "version": "1.0",
+ "name": "File System Provider API Extension Example",
+ "version": "0.1",
"manifest_version": 2,
- "description": "A simple IME that converts all keystrokes to upper case.",
- "background": {
- "scripts": ["main.js"]
- },
+ "description":
+ "Demonstrate features of the API like mounting, listing directories, etc for extensions.",
"permissions": [
- "input"
+ "fileSystemProvider"
],
- "input_components": [
- {
- "name": "Test IME",
- "type": "ime",
- "id": "test",
- "description": "Test IME", // A user visible description
- "language": "en-US", // The primary language this IME is used for
- "layouts": ["us::eng"] // The supported keyboard layouts for this IME
- }
- ]
+ "background": {
+ "scripts": [
+ "background.js"
+ ]
+ }
}
diff --git a/basic_6/README.md b/basic_6/README.md
index d6d8e4d..d387f95 100644
--- a/basic_6/README.md
+++ b/basic_6/README.md
@@ -1,15 +1,20 @@
-Top Sites
+Test IME
=======
-Shows the top sites in a browser action
+A simple IME that converts all keystrokes to upper case.
-[Zipfile](http://developer.chrome.com/extensions/examples/api/topsites/basic.zip)
+[Zipfile](http://developer.chrome.com/extensions/examples/api/input.ime/basic.zip)
Content is licensed under the [Google BSD License](http://code.google.com/google_bsd_license.html).
Calls
-----
-* [tabs.create](http://developer.chrome.com/extensions/tabs.html#method-create)
-* [topSites.get](http://developer.chrome.com/extensions/topSites.html#method-get)
\ No newline at end of file
+* [input.ime](https://developer.chrome.com/extensions/input.ime)
+* [input.ime.commitText](https://developer.chrome.com/extensions/input.ime#method-commitText)
+* [input.ime.onActivate](https://developer.chrome.com/extensions/input.ime#event-onActivate)
+* [input.ime.onBlur](https://developer.chrome.com/extensions/input.ime#event-onBlur)
+* [input.ime.onDeactivated](https://developer.chrome.com/extensions/input.ime#event-onDeactivated)
+* [input.ime.onFocus](https://developer.chrome.com/extensions/input.ime#event-onFocus)
+* [input.ime.onKeyEvent](https://developer.chrome.com/extensions/input.ime#event-onKeyEvent)
\ No newline at end of file
diff --git a/basic_6/main.js b/basic_6/main.js
new file mode 100644
index 0000000..fdff7ce
--- /dev/null
+++ b/basic_6/main.js
@@ -0,0 +1,37 @@
+// Copyright 2013 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.
+
+var ime_api = chrome.input.ime;
+
+var context_id = -1;
+
+console.log("Initializing IME");
+
+ime_api.onFocus.addListener(function(context) {
+ console.log('onFocus:' + context.contextID);
+ context_id = context.contextID;
+});
+ime_api.onBlur.addListener(function(contextID) {
+ console.log('onBlur:' + contextID);
+ context_id = -1;
+});
+
+ime_api.onActivate.addListener(function(engineID) {
+ console.log('onActivate:' + engineID);
+});
+ime_api.onDeactivated.addListener(function(engineID) {
+ console.log('onDeactivated:' + engineID);
+});
+
+ime_api.onKeyEvent.addListener(
+function(engineID, keyData) {
+ console.log('onKeyEvent:' + keyData.key + " context: " + context_id);
+ if (keyData.type == "keydown" && keyData.key.match(/^[a-z]$/)) {
+ chrome.input.ime.commitText({"contextID": context_id,
+ "text": keyData.key.toUpperCase()});
+ return true;
+ }
+
+ return false
+});
diff --git a/basic_6/manifest.json b/basic_6/manifest.json
index c042c09..e21aec1 100644
--- a/basic_6/manifest.json
+++ b/basic_6/manifest.json
@@ -1,11 +1,22 @@
{
- "name": "Top Sites",
- "version": "1.2",
- "description": "Shows the top sites in a browser action",
- "permissions": ["topSites"],
- "browser_action": {
- "default_icon": "icon.png",
- "default_popup": "popup.html"
+ "name": "Test IME",
+ "version": "1.0",
+ "manifest_version": 2,
+ "description": "A simple IME that converts all keystrokes to upper case.",
+ "background": {
+ "scripts": ["main.js"]
},
- "manifest_version": 2
+ "permissions": [
+ "input"
+ ],
+ "input_components": [
+ {
+ "name": "Test IME",
+ "type": "ime",
+ "id": "test",
+ "description": "Test IME", // A user visible description
+ "language": "en-US", // The primary language this IME is used for
+ "layouts": ["us::eng"] // The supported keyboard layouts for this IME
+ }
+ ]
}
diff --git a/basic_7/README.md b/basic_7/README.md
index 0f0f269..4ce03e7 100644
--- a/basic_7/README.md
+++ b/basic_7/README.md
@@ -1,26 +1,15 @@
-WebNavigation Tech Demo
+Top Sites
=======
-Demonstration of the WebNavigation extension API.
+Shows the top sites in a browser action
-[Zipfile](http://developer.chrome.com/extensions/examples/api/webNavigation/basic.zip)
+[Zipfile](http://developer.chrome.com/extensions/examples/api/topsites/basic.zip)
Content is licensed under the [Google BSD License](http://code.google.com/google_bsd_license.html).
Calls
-----
-* [extension.onRequest](http://developer.chrome.com/extensions/extension.html#event-onRequest)
-* [extension.sendRequest](http://developer.chrome.com/extensions/extension.html#method-sendRequest)
-* [i18n.getMessage](http://developer.chrome.com/extensions/i18n.html#method-getMessage)
-* [runtime.onStartup](http://developer.chrome.com/extensions/runtime.html#event-onStartup)
-* [storage.StorageArea.get](http://developer.chrome.com/extensions/storage.html#method-StorageArea-get)
-* [storage.StorageArea.set](http://developer.chrome.com/extensions/storage.html#method-StorageArea-set)
-* [webNavigation.onBeforeNavigate](http://developer.chrome.com/extensions/webNavigation.html#event-onBeforeNavigate)
-* [webNavigation.onCommitted](http://developer.chrome.com/extensions/webNavigation.html#event-onCommitted)
-* [webNavigation.onCompleted](http://developer.chrome.com/extensions/webNavigation.html#event-onCompleted)
-* [webNavigation.onCreatedNavigationTarget](http://developer.chrome.com/extensions/webNavigation.html#event-onCreatedNavigationTarget)
-* [webNavigation.onErrorOccurred](http://developer.chrome.com/extensions/webNavigation.html#event-onErrorOccurred)
-* [webNavigation.onHistoryStateUpdated](http://developer.chrome.com/extensions/webNavigation.html#event-onHistoryStateUpdated)
-* [webNavigation.onReferenceFragmentUpdated](http://developer.chrome.com/extensions/webNavigation.html#event-onReferenceFragmentUpdated)
\ No newline at end of file
+* [tabs.create](https://developer.chrome.com/extensions/tabs#method-create)
+* [topSites.get](https://developer.chrome.com/extensions/topSites#method-get)
\ No newline at end of file
diff --git a/basic_7/icon.png b/basic_7/icon.png
index 103ff36..0421e4c 100644
Binary files a/basic_7/icon.png and b/basic_7/icon.png differ
diff --git a/basic_7/manifest.json b/basic_7/manifest.json
index 2c0d435..c042c09 100644
--- a/basic_7/manifest.json
+++ b/basic_7/manifest.json
@@ -1,18 +1,11 @@
{
- "name": "__MSG_extName__",
- "version": "0.2",
- "description": "__MSG_extDescription__",
- "default_locale": "en",
- "background": {
- "persistent": false,
- "scripts": ["navigation_collector.js", "background.js"]
- },
+ "name": "Top Sites",
+ "version": "1.2",
+ "description": "Shows the top sites in a browser action",
+ "permissions": ["topSites"],
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
- "permissions": [
- "webNavigation", "storage"
- ],
"manifest_version": 2
}
diff --git a/basic_7/popup.html b/basic_7/popup.html
index 1f51802..1247307 100644
--- a/basic_7/popup.html
+++ b/basic_7/popup.html
@@ -1,17 +1,8 @@
-
-
+
-
- WebNavigation Tech Demo Popup
-
-
-
Most Requested URLs
-
-
+
Most Visited:
+
+
diff --git a/basic_7/popup.js b/basic_7/popup.js
index 35f6e00..5f6761d 100644
--- a/basic_7/popup.js
+++ b/basic_7/popup.js
@@ -1,36 +1,27 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
-/**
- * @filedescription Initializes the extension's popup page.
- */
+// Event listener for clicks on links in a browser action popup.
+// Open the link in a new tab of the current window.
+function onAnchorClick(event) {
+ chrome.tabs.create({ url: event.srcElement.href });
+ return false;
+}
-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);
- });
+// Given an array of URLs, build a DOM list of these URLs in the
+// browser action popup.
+function buildPopupDom(mostVisitedURLs) {
+ var popupDiv = document.getElementById('mostVisited_div');
+ var ol = popupDiv.appendChild(document.createElement('ol'));
+
+ for (var i = 0; i < mostVisitedURLs.length; i++) {
+ var li = ol.appendChild(document.createElement('li'));
+ var a = li.appendChild(document.createElement('a'));
+ a.href = mostVisitedURLs[i].url;
+ a.appendChild(document.createTextNode(mostVisitedURLs[i].title));
+ a.addEventListener('click', onAnchorClick);
+ }
+}
+
+chrome.topSites.get(buildPopupDom);
diff --git a/basic_8/README.md b/basic_8/README.md
new file mode 100644
index 0000000..a1887af
--- /dev/null
+++ b/basic_8/README.md
@@ -0,0 +1,26 @@
+
+WebNavigation Tech Demo
+=======
+
+Demonstration of the WebNavigation extension API.
+
+[Zipfile](http://developer.chrome.com/extensions/examples/api/webNavigation/basic.zip)
+
+Content is licensed under the [Google BSD License](http://code.google.com/google_bsd_license.html).
+
+Calls
+-----
+
+* [i18n.getMessage](https://developer.chrome.com/extensions/i18n#method-getMessage)
+* [runtime.onMessage](https://developer.chrome.com/extensions/runtime#event-onMessage)
+* [runtime.onStartup](https://developer.chrome.com/extensions/runtime#event-onStartup)
+* [runtime.sendMessage](https://developer.chrome.com/extensions/runtime#method-sendMessage)
+* [storage.StorageArea.get](https://developer.chrome.com/extensions/storage#method-StorageArea-get)
+* [storage.StorageArea.set](https://developer.chrome.com/extensions/storage#method-StorageArea-set)
+* [webNavigation.onBeforeNavigate](https://developer.chrome.com/extensions/webNavigation#event-onBeforeNavigate)
+* [webNavigation.onCommitted](https://developer.chrome.com/extensions/webNavigation#event-onCommitted)
+* [webNavigation.onCompleted](https://developer.chrome.com/extensions/webNavigation#event-onCompleted)
+* [webNavigation.onCreatedNavigationTarget](https://developer.chrome.com/extensions/webNavigation#event-onCreatedNavigationTarget)
+* [webNavigation.onErrorOccurred](https://developer.chrome.com/extensions/webNavigation#event-onErrorOccurred)
+* [webNavigation.onHistoryStateUpdated](https://developer.chrome.com/extensions/webNavigation#event-onHistoryStateUpdated)
+* [webNavigation.onReferenceFragmentUpdated](https://developer.chrome.com/extensions/webNavigation#event-onReferenceFragmentUpdated)
\ No newline at end of file
diff --git a/basic_8/_locales/en/messages.json b/basic_8/_locales/en/messages.json
new file mode 100644
index 0000000..e639880
--- /dev/null
+++ b/basic_8/_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."
+ },
+ "errorCompletedWithoutPending": {
+ "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/basic_8/background.js b/basic_8/background.js
new file mode 100644
index 0000000..a056515
--- /dev/null
+++ b/basic_8/background.js
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 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.
+
+/**
+ * @filedescription Initializes the extension's background page.
+ */
+
+var nav = new NavigationCollector();
+
+var eventList = ['onBeforeNavigate', 'onCreatedNavigationTarget',
+ 'onCommitted', 'onCompleted', 'onDOMContentLoaded',
+ 'onErrorOccurred', 'onReferenceFragmentUpdated', 'onTabReplaced',
+ 'onHistoryStateUpdated'];
+
+eventList.forEach(function(e) {
+ chrome.webNavigation[e].addListener(function(data) {
+ if (typeof data)
+ console.log(chrome.i18n.getMessage('inHandler'), e, data);
+ else
+ console.error(chrome.i18n.getMessage('inHandlerError'), e);
+ });
+});
+
+// Reset the navigation state on startup. We only want to collect data within a
+// session.
+chrome.runtime.onStartup.addListener(function() {
+ nav.resetDataStorage();
+});
diff --git a/basic_8/icon.png b/basic_8/icon.png
new file mode 100644
index 0000000..103ff36
Binary files /dev/null and b/basic_8/icon.png differ
diff --git a/basic_8/manifest.json b/basic_8/manifest.json
new file mode 100644
index 0000000..2c0d435
--- /dev/null
+++ b/basic_8/manifest.json
@@ -0,0 +1,18 @@
+{
+ "name": "__MSG_extName__",
+ "version": "0.2",
+ "description": "__MSG_extDescription__",
+ "default_locale": "en",
+ "background": {
+ "persistent": false,
+ "scripts": ["navigation_collector.js", "background.js"]
+ },
+ "browser_action": {
+ "default_icon": "icon.png",
+ "default_popup": "popup.html"
+ },
+ "permissions": [
+ "webNavigation", "storage"
+ ],
+ "manifest_version": 2
+}
diff --git a/basic_8/navigation_collector.js b/basic_8/navigation_collector.js
new file mode 100644
index 0000000..cec4db2
--- /dev/null
+++ b/basic_8/navigation_collector.js
@@ -0,0 +1,500 @@
+// Copyright (c) 2012 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.}
+ * @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.>}
+ * @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.>}
+ * @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.webNavigation.onCreatedNavigationTarget.addListener(
+ this.onCreatedNavigationTargetListener_.bind(this));
+ chrome.webNavigation.onBeforeNavigate.addListener(
+ this.onBeforeNavigateListener_.bind(this));
+ chrome.webNavigation.onCompleted.addListener(
+ this.onCompletedListener_.bind(this));
+ chrome.webNavigation.onCommitted.addListener(
+ this.onCommittedListener_.bind(this));
+ chrome.webNavigation.onErrorOccurred.addListener(
+ this.onErrorOccurredListener_.bind(this));
+ chrome.webNavigation.onReferenceFragmentUpdated.addListener(
+ this.onReferenceFragmentUpdatedListener_.bind(this));
+ chrome.webNavigation.onHistoryStateUpdated.addListener(
+ this.onHistoryStateUpdatedListener_.bind(this));
+
+ // Bind handler to extension messages for communication from popup.
+ chrome.runtime.onMessage.addListener(this.onMessageListener_.bind(this));
+
+ this.loadDataStorage_();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * 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.,
+ * openedInNewTab: boolean, source: {frameId: ?number, tabId: ?number},
+ * duration: number}}
+ */
+NavigationCollector.Request;
+
+///////////////////////////////////////////////////////////////////////////////
+
+NavigationCollector.prototype = {
+ /**
+ * Returns a somewhat unique ID for a given WebNavigation request.
+ *
+ * @param {!{tabId: ?number, frameId: ?number}} data Information
+ * about the navigation event we'd like an ID for.
+ * @return {!string} ID created by combining the source tab ID and frame ID
+ * (or target tab/frame IDs if there's no source), as the API ensures
+ * that these will be unique across a single navigation event.
+ * @private
+ */
+ parseId_: function(data) {
+ return data.tabId + '-' + (data.frameId ? data.frameId : 0);
+ },
+
+
+ /**
+ * Creates an empty entry in the pending array if one doesn't already exist,
+ * 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,
+ source: {
+ frameId: null,
+ tabId: null
+ },
+ start: null,
+ transitionQualifiers: [],
+ transitionType: null
+ };
+ this.completed_[url] = this.completed_[url] || [];
+ this.errored_[url] = this.errored_[url] || [];
+ },
+
+
+ /**
+ * Retrieves our saved data from storage.
+ * @private
+ */
+ loadDataStorage_: function() {
+ chrome.storage.local.get({
+ "completed": {},
+ "errored": {},
+ }, function(storage) {
+ this.completed_ = storage.completed;
+ this.errored_ = storage.errored;
+ }.bind(this));
+ },
+
+
+ /**
+ * Persists our state to the storage API.
+ * @private
+ */
+ saveDataStorage_: function() {
+ chrome.storage.local.set({
+ "completed": this.completed_,
+ "errored": this.errored_,
+ });
+ },
+
+
+ /**
+ * Resets our saved state to empty.
+ */
+ resetDataStorage: function() {
+ this.completed_ = {};
+ this.errored_ = {};
+ this.saveDataStorage_();
+ // Load again, in case there is an outstanding storage.get request. This
+ // one will reload the newly-cleared data.
+ this.loadDataStorage_();
+ },
+
+
+ /**
+ * Handler for the 'onCreatedNavigationTarget' event. Updates the
+ * pending request with a source frame/tab, 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
+ */
+ onCreatedNavigationTargetListener_: function(data) {
+ var id = this.parseId_(data);
+ this.prepareDataStorage_(id, data.url);
+ this.pending_[id].openedInNewTab = data.tabId;
+ this.pending_[id].source = {
+ tabId: data.sourceTabId,
+ frameId: data.sourceFrameId
+ };
+ 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.prepareDataStorage_(id, data.url);
+ this.pending_[id].transitionType = data.transitionType;
+ this.pending_[id].transitionQualifiers =
+ data.transitionQualifiers;
+ }
+ },
+
+
+ /**
+ * Handler for the 'onReferenceFragmentUpdated' 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
+ */
+ onReferenceFragmentUpdatedListener_: function(data) {
+ var id = this.parseId_(data);
+ if (!this.pending_[id]) {
+ this.completed_[data.url] = this.completed_[data.url] || [];
+ this.completed_[data.url].push({
+ duration: 0,
+ openedInNewWindow: false,
+ source: {
+ frameId: null,
+ tabId: null
+ },
+ transitionQualifiers: data.transitionQualifiers,
+ transitionType: data.transitionType,
+ url: data.url
+ });
+ this.saveDataStorage_();
+ } else {
+ this.prepareDataStorage_(id, data.url);
+ this.pending_[id].transitionType = data.transitionType;
+ this.pending_[id].transitionQualifiers =
+ data.transitionQualifiers;
+ }
+ },
+
+
+ /**
+ * Handler for the 'onHistoryStateUpdated' 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
+ */
+ onHistoryStateUpdatedListener_: function(data) {
+ var id = this.parseId_(data);
+ if (!this.pending_[id]) {
+ this.completed_[data.url] = this.completed_[data.url] || [];
+ this.completed_[data.url].push({
+ duration: 0,
+ openedInNewWindow: false,
+ source: {
+ frameId: null,
+ tabId: null
+ },
+ transitionQualifiers: data.transitionQualifiers,
+ transitionType: data.transitionType,
+ url: data.url
+ });
+ this.saveDataStorage_();
+ } else {
+ this.prepareDataStorage_(id, data.url);
+ 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,
+ source: this.pending_[id].source,
+ transitionQualifiers: this.pending_[id].transitionQualifiers,
+ transitionType: this.pending_[id].transitionType,
+ url: data.url
+ });
+ delete this.pending_[id];
+ this.saveDataStorage_();
+ }
+ },
+
+
+ /**
+ * 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.prepareDataStorage_(id, data.url);
+ this.errored_[data.url].push({
+ duration: (data.timeStamp - this.pending_[id].start),
+ openedInNewWindow: this.pending_[id].openedInNewWindow,
+ source: this.pending_[id].source,
+ transitionQualifiers: this.pending_[id].transitionQualifiers,
+ transitionType: this.pending_[id].transitionType,
+ url: data.url
+ });
+ delete this.pending_[id];
+ this.saveDataStorage_();
+ }
+ },
+
+ /**
+ * Handle messages from the popup.
+ *
+ * @param {!{type:string}} message The external message to answer.
+ * @param {!MessageSender} sender Info about the script context that sent
+ * the message.
+ * @param {!function} sendResponse Function to call to send a response.
+ * @private
+ */
+ onMessageListener_: function(message, sender, sendResponse) {
+ if (message.type === 'getMostRequestedUrls')
+ sendResponse({result: this.getMostRequestedUrls(message.num)});
+ else
+ sendResponse({});
+ },
+
+///////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @return {Object.} The complete list of
+ * successful navigation requests.
+ */
+ get completed() {
+ return this.completed_;
+ },
+
+
+ /**
+ * @return {Object.} 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.} 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.} 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.} 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].length) {
+ 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/basic_8/popup.css b/basic_8/popup.css
new file mode 100644
index 0000000..e551226
--- /dev/null
+++ b/basic_8/popup.css
@@ -0,0 +1,63 @@
+/**
+ * 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.
+ */
+
+
+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;
+}
diff --git a/basic_8/popup.html b/basic_8/popup.html
new file mode 100644
index 0000000..1f51802
--- /dev/null
+++ b/basic_8/popup.html
@@ -0,0 +1,17 @@
+
+
+
+
+ WebNavigation Tech Demo Popup
+
+
+
+
Most Requested URLs
+
+
+
+
diff --git a/basic_8/popup.js b/basic_8/popup.js
new file mode 100644
index 0000000..ccb3243
--- /dev/null
+++ b/basic_8/popup.js
@@ -0,0 +1,36 @@
+// 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.
+
+/**
+ * @filedescription Initializes the extension's popup page.
+ */
+
+chrome.runtime.sendMessage(
+ {'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);
+ });
diff --git a/broken-links/README.md b/broken-links/README.md
index 1dccbc5..58980b1 100644
--- a/broken-links/README.md
+++ b/broken-links/README.md
@@ -11,8 +11,8 @@ Content is licensed under the [Google BSD License](http://code.google.com/google
Calls
-----
-* [experimental.devtools.audits.addCategory](http://developer.chrome.com/extensions/experimental.devtools.audits.html#method-addCategory)
-* [extension.onRequest](http://developer.chrome.com/extensions/extension.html#event-onRequest)
-* [extension.sendRequest](http://developer.chrome.com/extensions/extension.html#method-sendRequest)
-* [tabs.executeScript](http://developer.chrome.com/extensions/tabs.html#method-executeScript)
-* [tabs.sendRequest](http://developer.chrome.com/extensions/tabs.html#method-sendRequest)
\ No newline at end of file
+* [experimental.devtools.audits.addCategory](https://developer.chrome.com/extensions/experimental.devtools.audits#method-addCategory)
+* [extension.onRequest](https://developer.chrome.com/extensions/extension#event-onRequest)
+* [extension.sendRequest](https://developer.chrome.com/extensions/extension#method-sendRequest)
+* [tabs.executeScript](https://developer.chrome.com/extensions/tabs#method-executeScript)
+* [tabs.sendRequest](https://developer.chrome.com/extensions/tabs#method-sendRequest)
\ No newline at end of file
diff --git a/buildbot/README.md b/buildbot/README.md
index 2117d19..af00331 100644
--- a/buildbot/README.md
+++ b/buildbot/README.md
@@ -11,11 +11,11 @@ Content is licensed under the [Google BSD License](http://code.google.com/google
Calls
-----
-* [browserAction.setBadgeBackgroundColor](http://developer.chrome.com/extensions/browserAction.html#method-setBadgeBackgroundColor)
-* [browserAction.setBadgeText](http://developer.chrome.com/extensions/browserAction.html#method-setBadgeText)
-* [browserAction.setTitle](http://developer.chrome.com/extensions/browserAction.html#method-setTitle)
-* [extension.getBackgroundPage](http://developer.chrome.com/extensions/extension.html#method-getBackgroundPage)
-* [extension.getURL](http://developer.chrome.com/extensions/extension.html#method-getURL)
-* [extension.getViews](http://developer.chrome.com/extensions/extension.html#method-getViews)
-* [storage.StorageArea.get](http://developer.chrome.com/extensions/storage.html#method-StorageArea-get)
-* [storage.StorageArea.set](http://developer.chrome.com/extensions/storage.html#method-StorageArea-set)
\ No newline at end of file
+* [browserAction.setBadgeBackgroundColor](https://developer.chrome.com/extensions/browserAction#method-setBadgeBackgroundColor)
+* [browserAction.setBadgeText](https://developer.chrome.com/extensions/browserAction#method-setBadgeText)
+* [browserAction.setTitle](https://developer.chrome.com/extensions/browserAction#method-setTitle)
+* [extension.getBackgroundPage](https://developer.chrome.com/extensions/extension#method-getBackgroundPage)
+* [extension.getURL](https://developer.chrome.com/extensions/extension#method-getURL)
+* [extension.getViews](https://developer.chrome.com/extensions/extension#method-getViews)
+* [storage.StorageArea.get](https://developer.chrome.com/extensions/storage#method-StorageArea-get)
+* [storage.StorageArea.set](https://developer.chrome.com/extensions/storage#method-StorageArea-set)
\ No newline at end of file
diff --git a/buildbot/bg.js b/buildbot/bg.js
index a351678..8324e03 100644
--- a/buildbot/bg.js
+++ b/buildbot/bg.js
@@ -25,12 +25,12 @@ function updateBadgeOnErrorStatus() {
var lastNotification = null;
function notifyStatusChange(treeState, status) {
if (lastNotification)
- lastNotification.cancel();
+ lastNotification.close();
- var notification = webkitNotifications.createNotification(
- chrome.extension.getURL("icon.png"), "Tree is " + treeState, status);
- lastNotification = notification;
- notification.show();
+ lastNotification = new Notification("Tree is " + treeState, {
+ icon: chrome.extension.getURL("icon.png"),
+ body: status
+ });
}
// The type parameter should be "open", "closed", or "throttled".
diff --git a/buildbot/manifest.json b/buildbot/manifest.json
index 1c1f5e0..0d86bcb 100644
--- a/buildbot/manifest.json
+++ b/buildbot/manifest.json
@@ -1,6 +1,6 @@
{
"name": "Chromium Buildbot Monitor",
- "version": "0.8.4",
+ "version": "0.9.0",
"description": "Displays the status of the Chromium buildbot in the toolbar. Click to see more detailed status in a popup.",
"icons": { "128": "icon.png" },
"background": {
@@ -23,6 +23,9 @@
"default_popup": "popup.html"
},
"options_page": "options.html",
-
+ "options_ui": {
+ "chrome_style": true,
+ "page": "options.html"
+ },
"manifest_version": 2
}
diff --git a/buildbot/options.html b/buildbot/options.html
index 539f7c8..e045aa6 100644
--- a/buildbot/options.html
+++ b/buildbot/options.html
@@ -2,10 +2,13 @@
Chromium Buildbot Monitor Options
+
-