diff options
23 files changed, 265 insertions, 9 deletions
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index a18a7a56..d5be2b8 100755 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS @@ -17,6 +17,7 @@ include_rules = [ "+media/audio", # Chrome's lightweight audio library. "+third_party/sqlite", "+third_party/libevent", # For the remote V8 debugging server + "+third_party/cld", "+v8/include", # Browser uses V8 to get the version and run the debugger. # FIXME: this should probably not be here, we need to find a better diff --git a/chrome/browser/extensions/extension_browsertests_misc.cc b/chrome/browser/extensions/extension_browsertests_misc.cc index f17e5d5..4b8fb8f 100644 --- a/chrome/browser/extensions/extension_browsertests_misc.cc +++ b/chrome/browser/extensions/extension_browsertests_misc.cc @@ -43,10 +43,10 @@ static ExtensionHost* FindHostWithPath(ExtensionProcessManager* manager, // Tests that toolstrips initializes properly and can run basic extension js. IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, Toolstrip) { - ASSERT_TRUE(LoadExtension( - test_data_dir_.AppendASCII("good").AppendASCII("Extensions") - .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") - .AppendASCII("1.0.0.0"))); + FilePath extension_test_data_dir = test_data_dir_.AppendASCII("good"). + AppendASCII("Extensions").AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj"). + AppendASCII("1.0.0.0"); + ASSERT_TRUE(LoadExtension(extension_test_data_dir)); // At this point, there should be two ExtensionHosts loaded because this // extension has two toolstrips. Find the one that is hosting toolstrip1.html. @@ -59,6 +59,22 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, Toolstrip) { ui_test_utils::ExecuteJavaScriptAndExtractBool( host->render_view_host(), L"", L"testTabsAPI()", &result); EXPECT_TRUE(result); + +#if defined(OS_WIN) + // Test for compact language detection API. First navigate to a (static) html + // file with a French sentence. Then, run the test API in toolstrip1.html to + // actually call the language detection API through the existing extension, + // and verify that the language returned is indeed French. + FilePath language_url = extension_test_data_dir.AppendASCII( + "french_sentence.html"); + ui_test_utils::NavigateToURL( + browser(), + GURL(language_url.ToWStringHack())); + + ui_test_utils::ExecuteJavaScriptAndExtractBool( + host->render_view_host(), L"", L"testTabsLanguageAPI()", &result); + EXPECT_TRUE(result); +#endif } // Tests that the ExtensionShelf initializes properly, notices that diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h index 7798a19..ed2f9d0 100644 --- a/chrome/browser/extensions/extension_function.h +++ b/chrome/browser/extensions/extension_function.h @@ -93,7 +93,14 @@ class AsyncExtensionFunction : public ExtensionFunction { virtual void SetArgs(const std::string& args); virtual const std::string GetResult(); virtual const std::string GetError() { return error_; } - virtual void Run() = 0; + virtual void Run() { + if (!RunImpl()) + SendResponse(false); + } + + // Derived classes should implement this method to do their work and return + // success/failure. + virtual bool RunImpl() = 0; protected: void SendResponse(bool success); @@ -107,7 +114,7 @@ class AsyncExtensionFunction : public ExtensionFunction { Value* args_; // The result of the API. This should be populated by the derived class before - // Run() returns. + // SendResponse() is called. scoped_ptr<Value> result_; // Any detailed error from the API. This should be populated by the derived diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index 70cb59e..8238595 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -98,6 +98,8 @@ void FactoryRegistry::ResetFunctions() { &NewExtensionFunction<MoveTabFunction>; factories_[tabs::kRemoveTabFunction] = &NewExtensionFunction<RemoveTabFunction>; + factories_[tabs::kGetTabLanguageFunction] = + &NewExtensionFunction<GetTabLanguageFunction>; // Page Actions. factories_[page_actions::kEnablePageActionFunction] = diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc index b92677d..57248d7 100644 --- a/chrome/browser/extensions/extension_tabs_module.cc +++ b/chrome/browser/extensions/extension_tabs_module.cc @@ -615,6 +615,52 @@ bool RemoveTabFunction::RunImpl() { return true; } +bool GetTabLanguageFunction::RunImpl() { + int tab_id = 0; + Browser* browser = NULL; + TabContents* contents = NULL; + + // If |tab_id| is specified, look for it. Otherwise default to selected tab + // in the current window. + if (!args_->IsType(Value::TYPE_NULL)) { + EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&tab_id)); + if (!GetTabById(tab_id, profile(), &browser, NULL, &contents, NULL, + &error_)) { + return false; + } + if (!browser || !contents) + return false; + } else { + browser = dispatcher()->GetBrowser(); + if (!browser) + return false; + contents = browser->tabstrip_model()->GetSelectedTabContents(); + if (!contents) + return false; + } + + // Figure out what language |contents| contains. This sends an async call via + // the browser to the renderer to determine the language of the tab the + // renderer has. The renderer sends back the language of the tab after the + // tab loads (it may be delayed) to the browser, which in turn notifies this + // object that the language has been received. + contents->GetPageLanguage(); + registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED, + NotificationService::AllSources()); + AddRef(); // balanced in Observe() + return true; +} + +void GetTabLanguageFunction::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(type == NotificationType::TAB_LANGUAGE_DETERMINED); + std::string language(*Details<std::string>(details).ptr()); + result_.reset(Value::CreateStringValue(language.c_str())); + SendResponse(true); + Release(); // balanced in Run() +} + // static helpers // if |populate| is true, each window gets a list property |tabs| which contains diff --git a/chrome/browser/extensions/extension_tabs_module.h b/chrome/browser/extensions/extension_tabs_module.h index cb8b3d3..1b7c307 100644 --- a/chrome/browser/extensions/extension_tabs_module.h +++ b/chrome/browser/extensions/extension_tabs_module.h @@ -8,6 +8,8 @@ #include <string> #include "chrome/browser/extensions/extension_function.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_registrar.h" class Browser; class DictionaryValue; @@ -86,5 +88,15 @@ class MoveTabFunction : public SyncExtensionFunction { class RemoveTabFunction : public SyncExtensionFunction { virtual bool RunImpl(); }; +class GetTabLanguageFunction : public AsyncExtensionFunction, + public NotificationObserver { + virtual bool RunImpl(); + + private: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + NotificationRegistrar registrar_; +}; #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TABS_MODULE_H__ diff --git a/chrome/browser/extensions/extension_tabs_module_constants.cc b/chrome/browser/extensions/extension_tabs_module_constants.cc index 049f36a..69676e7 100755 --- a/chrome/browser/extensions/extension_tabs_module_constants.cc +++ b/chrome/browser/extensions/extension_tabs_module_constants.cc @@ -56,6 +56,6 @@ const char kCreateTabFunction[] = "CreateTab"; const char kUpdateTabFunction[] = "UpdateTab"; const char kMoveTabFunction[] = "MoveTab"; const char kRemoveTabFunction[] = "RemoveTab"; - +const char kGetTabLanguageFunction[] = "GetTabLanguage"; } // namespace extension_tabs_module_constants diff --git a/chrome/browser/extensions/extension_tabs_module_constants.h b/chrome/browser/extensions/extension_tabs_module_constants.h index 10abcf7..4df84c8 100755 --- a/chrome/browser/extensions/extension_tabs_module_constants.h +++ b/chrome/browser/extensions/extension_tabs_module_constants.h @@ -64,6 +64,7 @@ extern const char kCreateTabFunction[]; extern const char kUpdateTabFunction[]; extern const char kMoveTabFunction[]; extern const char kRemoveTabFunction[]; +extern const char kGetTabLanguageFunction[]; }; // namespace extension_tabs_module_constants diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 8e8f161..b41c04c 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -41,6 +41,8 @@ #if defined(OS_WIN) // TODO(port): accessibility not yet implemented. See http://crbug.com/8288. #include "chrome/browser/browser_accessibility_manager.h" +// TODO(port): The compact language detection library works only for Windows. +#include "third_party/cld/bar/toolbar/cld/i18n/encodings/compact_lang_det/win/cld_unicodetext.h" #endif using base::TimeDelta; @@ -410,6 +412,10 @@ void RenderViewHost::StopFinding(bool clear_selection) { Send(new ViewMsg_StopFinding(routing_id(), clear_selection)); } +void RenderViewHost::GetPageLanguage() { + Send(new ViewMsg_DeterminePageText(routing_id())); +} + void RenderViewHost::Zoom(PageZoom::Function function) { Send(new ViewMsg_Zoom(routing_id(), function)); } @@ -726,6 +732,8 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_DidFailProvisionalLoadWithError, OnMsgDidFailProvisionalLoadWithError) IPC_MESSAGE_HANDLER(ViewHostMsg_Find_Reply, OnMsgFindReply) + IPC_MESSAGE_HANDLER(ViewMsg_DeterminePageText_Reply, + OnDeterminePageTextReply) IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFavIconURL, OnMsgUpdateFavIconURL) IPC_MESSAGE_HANDLER(ViewHostMsg_DidDownloadFavIcon, OnMsgDidDownloadFavIcon) IPC_MESSAGE_HANDLER(ViewHostMsg_ContextMenu, OnMsgContextMenu) @@ -1058,6 +1066,21 @@ void RenderViewHost::OnMsgFindReply(int request_id, Send(new ViewMsg_FindReplyACK(routing_id())); } +void RenderViewHost::OnDeterminePageTextReply( + const std::wstring& page_text) { +#if defined(OS_WIN) // Only for windows. + int num_languages = 0; + bool is_reliable = false; + const char* language_char = LanguageName(DetectLanguageOfUnicodeText( + page_text.c_str(), true, &is_reliable, &num_languages, NULL)); + std::string language(language_char); + NotificationService::current()->Notify( + NotificationType::TAB_LANGUAGE_DETERMINED, + Source<RenderViewHost>(this), + Details<std::string>(&language)); +#endif +} + void RenderViewHost::OnMsgUpdateFavIconURL(int32 page_id, const GURL& icon_url) { RenderViewHostDelegate::FavIcon* favicon_delegate = diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index de4c70c..a43c5a2 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -206,6 +206,12 @@ class RenderViewHost : public RenderWidgetHost, // clear the selection on the focused frame. void StopFinding(bool clear_selection); + // Get the most probable language of the text content in the tab. This sends + // a message to the render view to get the content of the page as text. The + // caller gets the language via the NotificationService by registering to the + // NotificationType TAB_LANGUAGE_DETERMINED. + void GetPageLanguage(); + // Change the zoom level of a page. void Zoom(PageZoom::Function function); @@ -460,6 +466,7 @@ class RenderViewHost : public RenderWidgetHost, const gfx::Rect& selection_rect, int active_match_ordinal, bool final_update); + void OnDeterminePageTextReply(const std::wstring& tab_text); void OnMsgUpdateFavIconURL(int32 page_id, const GURL& icon_url); void OnMsgDidDownloadFavIcon(int id, const GURL& image_url, diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 001be58..9832fa4 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -976,6 +976,10 @@ void TabContents::StopFinding(bool clear_selection) { render_view_host()->StopFinding(clear_selection); } +void TabContents::GetPageLanguage() { + render_view_host()->GetPageLanguage(); +} + void TabContents::OnJavaScriptMessageBoxClosed(IPC::Message* reply_msg, bool success, const std::wstring& prompt) { diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index 99e99a1..e974f8e 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -493,6 +493,9 @@ class TabContents : public PageNavigator, return last_search_result_; } + // Get the most probable language of the text content in the tab. + void GetPageLanguage(); + // Misc state & callbacks ---------------------------------------------------- // Set whether the contents should block javascript message boxes or not. diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h index d2c8fca..93cbbaf 100644 --- a/chrome/common/notification_type.h +++ b/chrome/common/notification_type.h @@ -204,6 +204,10 @@ class NotificationType { // is the InfoBubble. INFO_BUBBLE_CREATED, + // Sent after a call to RenderViewHost::DeterminePageLanguage. The details + // are Details<std::string> and the source is Source<RenderViewHost>. + TAB_LANGUAGE_DETERMINED, + // The user has changed the browser theme. BROWSER_THEME_CHANGED, diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 5205bf6..ee3d154 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -191,6 +191,14 @@ IPC_BEGIN_MESSAGES(View) string16 /* search_text */, WebKit::WebFindOptions) + // Send from the browser to the rendered to get the text content of the page. + IPC_MESSAGE_ROUTED0(ViewMsg_DeterminePageText) + + // Send from the renderer to the browser to return the text content of the + // page. + IPC_MESSAGE_ROUTED1(ViewMsg_DeterminePageText_Reply, + std::wstring /* the language */) + // Sent when the headers are available for a resource request. IPC_MESSAGE_ROUTED2(ViewMsg_Resource_ReceivedResponse, int /* request_id */, diff --git a/chrome/renderer/extensions/extension_api_client_unittest.cc b/chrome/renderer/extensions/extension_api_client_unittest.cc index 663a892..0cb2876 100644 --- a/chrome/renderer/extensions/extension_api_client_unittest.cc +++ b/chrome/renderer/extensions/extension_api_client_unittest.cc @@ -275,6 +275,24 @@ TEST_F(ExtensionAPIClientTest, GetTab) { "GetTab", "2"); } +#if defined(OS_WIN) +TEST_F(ExtensionAPIClientTest, GetTabLanguage) { + ExpectJsFail("chrome.tabs.getLanguage(32, function(){}, 20);", + "Uncaught Error: Too many arguments."); + + ExpectJsFail("chrome.tabs.getLanguage('abc', function(){});", + "Uncaught Error: Invalid value for argument 0. " + "Expected 'integer' but got 'string'."); + + ExpectJsFail("chrome.tabs.getLanguage(1, 1);", + "Uncaught Error: Invalid value for argument 1. " + "Expected 'function' but got 'integer'."); + + ExpectJsPass("chrome.tabs.getLanguage(null, function(){})", + "GetTabLanguage", "null"); +} +#endif + TEST_F(ExtensionAPIClientTest, GetSelectedTab) { ExpectJsFail("chrome.tabs.getSelected(32, function(){}, 20);", "Uncaught Error: Too many arguments."); diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 5f72843..f08ad79e 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -192,7 +192,8 @@ RenderView::RenderView(RenderThreadBase* render_thread) popup_notification_visible_(false), delay_seconds_for_form_state_sync_(kDefaultDelaySecondsForFormStateSync), preferred_width_(0), - send_preferred_width_changes_(false) { + send_preferred_width_changes_(false), + determine_page_text_after_loading_stops_(false) { } RenderView::~RenderView() { @@ -355,6 +356,7 @@ void RenderView::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ViewMsg_CopyImageAt, OnCopyImageAt) IPC_MESSAGE_HANDLER(ViewMsg_ExecuteEditCommand, OnExecuteEditCommand) IPC_MESSAGE_HANDLER(ViewMsg_Find, OnFind) + IPC_MESSAGE_HANDLER(ViewMsg_DeterminePageText, OnDeterminePageText) IPC_MESSAGE_HANDLER(ViewMsg_Zoom, OnZoom) IPC_MESSAGE_HANDLER(ViewMsg_InsertText, OnInsertText) IPC_MESSAGE_HANDLER(ViewMsg_SetPageEncoding, OnSetPageEncoding) @@ -497,6 +499,12 @@ void RenderView::CapturePageInfo(int load_id, bool preliminary_capture) { Send(new ViewHostMsg_PageContents(url, load_id, contents)); } + // Send over text content of this page to the browser. + if (determine_page_text_after_loading_stops_) { + determine_page_text_after_loading_stops_ = false; + Send(new ViewMsg_DeterminePageText_Reply(routing_id_, contents)); + } + // thumbnail SendThumbnail(); } @@ -2199,6 +2207,23 @@ void RenderView::OnFind(int request_id, } } +void RenderView::OnDeterminePageText() { + if (!is_loading_) { + if (!webview()) + return; + WebFrame* main_frame = webview()->GetMainFrame(); + std::wstring contents; + CaptureText(main_frame, &contents); + Send(new ViewMsg_DeterminePageText_Reply(routing_id_, contents)); + determine_page_text_after_loading_stops_ = false; + return; + } + + // We set |determine_page_text_after_loading_stops_| true here so that, + // after page has been loaded completely, the text in the page is captured. + determine_page_text_after_loading_stops_ = true; +} + void RenderView::ReportFindInPageMatchCount(int count, int request_id, bool final_update) { // If we have a message that has been queued up, then we should just replace diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index bc44ac9..24621a4 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -478,6 +478,7 @@ class RenderView : public RenderWidget, void OnSetupDevToolsClient(); void OnCancelDownload(int32 download_id); void OnFind(int request_id, const string16&, const WebKit::WebFindOptions&); + void OnDeterminePageText(); void OnZoom(int function); void OnInsertText(const string16& text); void OnSetPageEncoding(const std::wstring& encoding_name); @@ -778,6 +779,9 @@ class RenderView : public RenderWidget, // The text selection the last time DidChangeSelection got called. std::string last_selection_; + // Set to true if request for capturing page text has been made. + bool determine_page_text_after_loading_stops_; + // Holds state pertaining to a navigation that we initiated. This is held by // the WebDataSource::ExtraData attribute. We use pending_navigation_state_ // as a temporary holder for the state until the WebDataSource corresponding diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd index ed66407..8acec84 100644 --- a/chrome/renderer/renderer_resources.grd +++ b/chrome/renderer/renderer_resources.grd @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- This comment is only here because changes to resources are not picked up -without changes to the corresponding grd file. mp12 --> +without changes to the corresponding grd file. mp13 --> <grit latest_public_release="0" current_release="1"> <outputs> <output filename="grit/renderer_resources.h" type="rc_header"> diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js index f3893fb..51756d0 100644 --- a/chrome/renderer/resources/extension_process_bindings.js +++ b/chrome/renderer/resources/extension_process_bindings.js @@ -24,6 +24,7 @@ var chrome = chrome || {}; native function UpdateTab(); native function MoveTab(); native function RemoveTab(); + native function GetTabLanguage(); native function EnablePageAction(); native function DisablePageAction(); native function GetBookmarks(); @@ -313,6 +314,16 @@ var chrome = chrome || {}; chrome.types.optFun ]; + chrome.tabs.getLanguage = function(tabId, callback) { + validate(arguments, arguments.callee.params); + sendRequest(GetTabLanguage, tabId, callback); + }; + + chrome.tabs.getLanguage.params = [ + chrome.types.optPInt, + chrome.types.optFun + ]; + // Sends ({Tab}). // Will *NOT* be followed by tab-attached - it is implied. // *MAY* be followed by tab-selection-changed. diff --git a/chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/french_sentence.html b/chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/french_sentence.html new file mode 100644 index 0000000..3d3c2e8 --- /dev/null +++ b/chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/french_sentence.html @@ -0,0 +1,12 @@ +<!-- +Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this +source code is governed by a BSD-style license that can be found in the +LICENSE file. +--> +<html> +<body> +<p> +Ceci est une phrase complète est en français, rédigé en anglais puis traduits +</p> +</body> +</html> diff --git a/chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/toolstrip1.html b/chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/toolstrip1.html index d0a1f21..cf87fe5 100644 --- a/chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/toolstrip1.html +++ b/chrome/test/data/extensions/good/Extensions/behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0/toolstrip1.html @@ -8,6 +8,16 @@ function testTabsAPI() { window.domAutomationController.send(tabs.length == 1); }); } + +// This function is called from the C++ browser test. It tests the getLanguage +// function to make sure it can be used as an extension API. This will pass if +// the browser navigates to a page in French language before this is called. +function testTabsLanguageAPI() { + chrome.tabs.getLanguage(null, function(language) { + window.domAutomationController.send(language == 'FRENCH'); + }); +} + </script> <select> <option>one</option> diff --git a/chrome/test/data/extensions/samples/cld/manifest.json b/chrome/test/data/extensions/samples/cld/manifest.json new file mode 100644 index 0000000..c0f20f2 --- /dev/null +++ b/chrome/test/data/extensions/samples/cld/manifest.json @@ -0,0 +1,6 @@ +{ + "name": "CLD", + "description": "Returns language of a tab", + "version": "0.1", + "toolstrips": ["toolstrip.html"] +} diff --git a/chrome/test/data/extensions/samples/cld/toolstrip.html b/chrome/test/data/extensions/samples/cld/toolstrip.html new file mode 100644 index 0000000..726a030 --- /dev/null +++ b/chrome/test/data/extensions/samples/cld/toolstrip.html @@ -0,0 +1,36 @@ +<!-- +Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this +source code is governed by a BSD-style license that can be found in the +LICENSE file. +--> + +<html> + <head> + <script> + +var selectedId = -1; +function refreshLanguage() { + console.log("refeshing..."); + chrome.tabs.getLanguage(null, function(language) { + document.getElementById("languageDiv").innerHTML = language; + }); +} + +chrome.tabs.onUpdated.addListener(function(tabId, props) { + console.log("updated: " + tabId); + if (prop.status == "complete" && tabId == selectedId) + refreshLanguage(); +}); + +chrome.tabs.onSelectionChanged.addListener(function(tabId, props) { + console.log("selection: " + tabId); + selectedId = tabId; + refreshLanguage(); +}); + </script> + </head> + <body onload="refreshLanguage();"> + <div id="languageDiv" class="toolstrip-button" onclick="refreshLanguage();"> + </div> + </body> +</html>
\ No newline at end of file |