From 15ad956be9d8925e590bfeb0ddd733ae4e28d7f4 Mon Sep 17 00:00:00 2001 From: Patrik Johnson Date: Mon, 9 Mar 2015 02:30:20 +0200 Subject: [PATCH] Updated content (possibly desctructively) using new version of scraper --- README.md | 26 +- allowThirdPartyCookies/README.md | 3 +- app/README.md | 3 +- app_1/README.md | 6 - app_1/controller.js | 59 +- app_1/manifest.json | 5 +- app_launcher/README.md | 8 +- archive/README.md | 25 + archive/background.js | 247 +++++++ archive/example1.fake | 34 + archive/example2.fake | 15 + archive/manifest.json | 25 + background-simple/background.html | 7 +- basic/README.md | 10 +- basic_1/README.md | 2 +- basic_2/README.md | 5 +- basic_3/README.md | 4 +- basic_4/README.md | 32 +- basic_5/README.md | 20 +- basic_5/background.js | 119 +++ basic_5/manifest.json | 27 +- basic_6/README.md | 15 +- basic_6/main.js | 37 + basic_6/manifest.json | 27 +- basic_7/README.md | 21 +- basic_7/icon.png | Bin 3789 -> 2798 bytes basic_7/manifest.json | 15 +- basic_7/popup.html | 17 +- basic_7/popup.js | 55 +- basic_8/README.md | 26 + basic_8/_locales/en/messages.json | 52 ++ basic_8/background.js | 29 + basic_8/icon.png | Bin 0 -> 3789 bytes basic_8/manifest.json | 18 + basic_8/navigation_collector.js | 500 +++++++++++++ basic_8/popup.css | 63 ++ basic_8/popup.html | 17 + basic_8/popup.js | 36 + broken-links/README.md | 10 +- buildbot/README.md | 16 +- buildbot/bg.js | 10 +- buildbot/manifest.json | 7 +- buildbot/options.html | 7 +- calendar/README.md | 26 +- calendar/images/icon-128.png | Bin 0 -> 12552 bytes calendar/images/icon-16.png | Bin 0 -> 3401 bytes calendar/images/icon-19.png | Bin 0 -> 3641 bytes calendar/images/icon-38.png | Bin 0 -> 5524 bytes calendar/images/icon-48.png | Bin 0 -> 6839 bytes calendar/javascript/background.js | 766 +------------------- calendar/javascript/options.js | 79 +- calendar/manifest.json | 27 +- calendar/views/options.html | 92 +-- catblock/README.md | 2 +- catifier/README.md | 10 +- chrome-firephp/README.md | 10 +- chrome-preprocessor/README.md | 6 +- chrome-query/README.md | 4 +- chrome_search/README.md | 14 +- cld/README.md | 10 +- commands/README.md | 2 +- console_tts_engine/README.md | 12 +- contentSettings/README.md | 6 +- contentSettings/popup.html | 56 +- contentSettings/popup.js | 9 +- cookies/README.md | 16 +- desktopCapture/README.md | 8 +- desktopCapture/app.js | 8 +- desktopCapture/background.js | 8 + desktopCapture/index.html | 6 +- download_links/README.md | 12 +- download_manager/README.md | 48 +- download_open/README.md | 12 +- downloads_overwrite/README.md | 2 +- email_this_page/README.md | 12 +- enableReferrer/README.md | 3 +- event_page/README.md | 9 +- extension-questions/README.md | 12 +- fontSettings/README.md | 34 +- fontSettings/css/chrome_shared.css | 4 +- fontSettings/css/overlay.css | 2 +- fontSettings/manifest.json | 2 +- fontSettings/options.html | 16 +- fontSettings/slider.js | 2 + fx/README.md | 34 +- gdocs/README.md | 12 +- getMessage/README.md | 4 +- getstarted/README.md | 5 +- getstarted/manifest.json | 7 +- getstarted/popup.html | 26 +- getstarted/popup.js | 177 +++-- gmail/README.md | 40 +- idle_simple/README.md | 8 +- imageinfo/README.md | 8 +- inspector/README.md | 52 +- isAllowedAccess/README.md | 4 +- live-headers/README.md | 15 +- magic8ball/README.md | 2 +- make_page_red/README.md | 4 +- managed_bookmarks/README.md | 27 + managed_bookmarks/_locales/en/messages.json | 10 + managed_bookmarks/background.js | 365 ++++++++++ managed_bookmarks/manifest.json | 18 + managed_bookmarks/schema.json | 36 + mappy/README.md | 18 +- merge_windows/README.md | 10 +- news/README.md | 6 +- news_a11y/README.md | 2 +- notifications/background.js | 14 +- oauth_contacts/README.md | 16 +- pageaction_by_content/README.md | 8 +- pageaction_by_content/background.js | 28 +- pageaction_by_content/manifest.json | 27 +- pageaction_by_content/video-128.png | Bin 0 -> 5693 bytes pageaction_by_content/video-19.png | Bin 0 -> 191 bytes pageaction_by_content/video-48.png | Bin 0 -> 4278 bytes pageaction_by_url/README.md | 5 +- pageaction_by_url/background.js | 30 +- pageaction_by_url/manifest.json | 7 +- pause-resume/README.md | 19 +- pin/README.md | 6 +- plugin_settings/README.md | 13 +- power/README.md | 20 +- power/background.js | 3 +- power/manifest.json | 2 +- print/README.md | 4 +- process_monitor/README.md | 4 +- process_monitor/popup.html | 1 + process_monitor/popup.js | 9 +- proxy_configuration/README.md | 18 +- sandbox/README.md | 2 +- sandbox/eventpage.js | 11 +- screenshot/README.md | 14 +- screenshot/background.js | 68 +- screenshot/manifest.json | 6 +- screenshot/screenshot.html | 2 +- set_icon/README.md | 14 +- set_icon_path/README.md | 4 +- set_page_color/README.md | 2 +- showHistory/README.md | 6 +- show_tabs/README.md | 12 +- simple-example/README.md | 4 +- speak_selection/README.md | 24 +- stylizr/README.md | 16 +- tab_shortcuts/README.md | 6 +- talking_alarm_clock/README.md | 12 +- timer/README.md | 10 +- ttsdebug/README.md | 6 +- ttsdemo/README.md | 11 +- zoom/README | 2 + zoom/README.md | 20 + zoom/background.js | 21 + zoom/manifest.json | 24 + zoom/popup.html | 54 ++ zoom/popup.js | 136 ++++ zoom/zoom16.png | Bin 0 -> 482 bytes zoom/zoom19.png | Bin 0 -> 590 bytes zoom/zoom48.png | Bin 0 -> 1692 bytes 158 files changed, 2908 insertions(+), 1710 deletions(-) create mode 100644 archive/README.md create mode 100644 archive/background.js create mode 100644 archive/example1.fake create mode 100644 archive/example2.fake create mode 100644 archive/manifest.json create mode 100644 basic_5/background.js create mode 100644 basic_6/main.js create mode 100644 basic_8/README.md create mode 100644 basic_8/_locales/en/messages.json create mode 100644 basic_8/background.js create mode 100644 basic_8/icon.png create mode 100644 basic_8/manifest.json create mode 100644 basic_8/navigation_collector.js create mode 100644 basic_8/popup.css create mode 100644 basic_8/popup.html create mode 100644 basic_8/popup.js create mode 100644 calendar/images/icon-128.png create mode 100644 calendar/images/icon-16.png create mode 100644 calendar/images/icon-19.png create mode 100644 calendar/images/icon-38.png create mode 100644 calendar/images/icon-48.png create mode 100644 managed_bookmarks/README.md create mode 100644 managed_bookmarks/_locales/en/messages.json create mode 100644 managed_bookmarks/background.js create mode 100644 managed_bookmarks/manifest.json create mode 100644 managed_bookmarks/schema.json create mode 100644 pageaction_by_content/video-128.png create mode 100644 pageaction_by_content/video-19.png create mode 100644 pageaction_by_content/video-48.png create mode 100644 zoom/README create mode 100644 zoom/README.md create mode 100644 zoom/background.js create mode 100644 zoom/manifest.json create mode 100644 zoom/popup.html create mode 100644 zoom/popup.js create mode 100644 zoom/zoom16.png create mode 100644 zoom/zoom19.png create mode 100644 zoom/zoom48.png 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 103ff36a16c197ec42aeb7849566a7b32dcad978..0421e4c799b1050dca629888ddc4807929523e70 100644 GIT binary patch literal 2798 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 AfdBvi literal 3789 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 - + - - 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 0000000000000000000000000000000000000000..103ff36a16c197ec42aeb7849566a7b32dcad978 GIT binary patch literal 3789 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 + * @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 + -

Options for Chromium Buildbot Monitor

-