diff options
author | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-05 03:05:00 +0000 |
---|---|---|
committer | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-05 03:05:00 +0000 |
commit | e515f5de833d9298682570fd2f70abb16d032912 (patch) | |
tree | 05b4a10956097b7e173ebbc8153c5b557180bac8 | |
parent | 126f4120902008da93759d7256c87e1e6d3ae70b (diff) | |
download | chromium_src-e515f5de833d9298682570fd2f70abb16d032912.zip chromium_src-e515f5de833d9298682570fd2f70abb16d032912.tar.gz chromium_src-e515f5de833d9298682570fd2f70abb16d032912.tar.bz2 |
implemented API style/convention changes, including:
-tabs.update()
-tabs.move()
-tabs.remove()
-tabs.update()
-tabs.create()
-tabs.get()
-all tab events, except onUpdated
implemented
-tabs.getSelected()
-tabs.getAllInWindow()
-windows.getCurrent()
-windows.getFocused()
-windows.getAll(populate)
-windows.onFocusedChanged()
-ExtensionBrowserEventRouter now uses BrowserList::Observer
Review URL: http://codereview.chromium.org/100345
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15271 0039d316-1c4b-4281-b951-d872f2087c98
11 files changed, 725 insertions, 297 deletions
diff --git a/chrome/browser/extensions/extension_browser_event_router.cc b/chrome/browser/extensions/extension_browser_event_router.cc index fb3d354..f4853ea 100644 --- a/chrome/browser/extensions/extension_browser_event_router.cc +++ b/chrome/browser/extensions/extension_browser_event_router.cc @@ -22,6 +22,7 @@ const char* kOnTabDetached = "tab-detached"; const char* kOnTabRemoved = "tab-removed"; const char* kOnWindowCreated = "window-created"; const char* kOnWindowRemoved = "window-removed"; +const char* kOnWindowFocusedChanged = "window-focus-changed"; ExtensionBrowserEventRouter* ExtensionBrowserEventRouter::GetInstance() { return Singleton<ExtensionBrowserEventRouter>::get(); @@ -34,14 +35,22 @@ static void DispatchEvent(Profile *profile, DispatchEventToRenderers(event_name, json_args); } +static void DispatchSimpleBrowserEvent(Profile *profile, const int window_id, + const char* event_name) { + ListValue args; + args.Append(Value::CreateIntegerValue(window_id)); + + std::string json_args; + JSONWriter::Write(&args, false, &json_args); + + DispatchEvent(profile, event_name, json_args); +} + void ExtensionBrowserEventRouter::Init() { if (initialized_) return; - NotificationService::current()->AddObserver(this, - NotificationType::BROWSER_OPENED, NotificationService::AllSources()); - NotificationService::current()->AddObserver(this, - NotificationType::BROWSER_CLOSED, NotificationService::AllSources()); + BrowserList::AddObserver(this); initialized_ = true; } @@ -49,75 +58,67 @@ void ExtensionBrowserEventRouter::Init() { ExtensionBrowserEventRouter::ExtensionBrowserEventRouter() : initialized_(false) { } -// NotificationObserver -void ExtensionBrowserEventRouter::Observe(NotificationType type, - const NotificationSource& source, const NotificationDetails& details) { - Browser* browser; - - switch (type.value) { - case(NotificationType::BROWSER_OPENED) : - browser = Source<Browser>(source).ptr(); - browser->tabstrip_model()->AddObserver(this); - BrowserOpened(browser); - break; - case(NotificationType::BROWSER_CLOSED) : - browser = Source<Browser>(source).ptr(); - browser->tabstrip_model()->RemoveObserver(this); - BrowserClosed(browser); - break; - default: - NOTREACHED(); - break; - } +void ExtensionBrowserEventRouter::OnBrowserAdded(const Browser* browser) { + // Start listening to TabStripModel events for this browser. + browser->tabstrip_model()->AddObserver(this); + + DispatchSimpleBrowserEvent(browser->profile(), + ExtensionTabUtil::GetWindowId(browser), + kOnWindowCreated); } -void ExtensionBrowserEventRouter::BrowserOpened(Browser* browser) { - int window_id = ExtensionTabUtil::GetWindowId(browser); - - ListValue args; - args.Append(Value::CreateIntegerValue(window_id)); - - std::string json_args; - JSONWriter::Write(&args, false, &json_args); +void ExtensionBrowserEventRouter::OnBrowserRemoving(const Browser* browser) { + // Stop listening to TabStripModel events for this browser. + browser->tabstrip_model()->RemoveObserver(this); - DispatchEvent(browser->profile(), kOnWindowCreated, json_args); + DispatchSimpleBrowserEvent(browser->profile(), + ExtensionTabUtil::GetWindowId(browser), + kOnWindowRemoved); } -void ExtensionBrowserEventRouter::BrowserClosed(Browser* browser) { - int window_id = ExtensionTabUtil::GetWindowId(browser); +void ExtensionBrowserEventRouter::OnBrowserSetLastActive( + const Browser* browser) { + DispatchSimpleBrowserEvent(browser->profile(), + ExtensionTabUtil::GetWindowId(browser), + kOnWindowFocusedChanged); +} +void ExtensionBrowserEventRouter::TabCreatedAt(TabContents* contents, + int index, + bool foreground) { ListValue args; - args.Append(Value::CreateIntegerValue(window_id)); - + args.Append(ExtensionTabUtil::CreateTabValue(contents)); std::string json_args; JSONWriter::Write(&args, false, &json_args); - DispatchEvent(browser->profile(), kOnWindowRemoved, json_args); + DispatchEvent(contents->profile(), kOnTabCreated, json_args); } void ExtensionBrowserEventRouter::TabInsertedAt(TabContents* contents, int index, bool foreground) { - const char* event_name = kOnTabAttached; // If tab is new, send tab-created event. int tab_id = ExtensionTabUtil::GetTabId(contents); if (tab_ids_.find(tab_id) == tab_ids_.end()) { tab_ids_.insert(tab_id); - event_name = kOnTabCreated; + + TabCreatedAt(contents, index, foreground); + return; } ListValue args; + args.Append(Value::CreateIntegerValue(tab_id)); + DictionaryValue *object_args = new DictionaryValue(); - object_args->Set(L"tabId", Value::CreateIntegerValue(tab_id)); - object_args->Set(L"windowId", Value::CreateIntegerValue( + object_args->Set(L"newWindowId", Value::CreateIntegerValue( ExtensionTabUtil::GetWindowIdOfTab(contents))); - object_args->Set(L"index", Value::CreateIntegerValue(index)); + object_args->Set(L"newPosition", Value::CreateIntegerValue(index)); args.Append(object_args); std::string json_args; JSONWriter::Write(&args, false, &json_args); - DispatchEvent(contents->profile(), event_name, json_args); + DispatchEvent(contents->profile(), kOnTabAttached, json_args); } void ExtensionBrowserEventRouter::TabDetachedAt(TabContents* contents, @@ -129,11 +130,12 @@ void ExtensionBrowserEventRouter::TabDetachedAt(TabContents* contents, } ListValue args; + args.Append(Value::CreateIntegerValue(tab_id)); + DictionaryValue *object_args = new DictionaryValue(); - object_args->Set(L"tabId", Value::CreateIntegerValue(tab_id)); - object_args->Set(L"windowId", Value::CreateIntegerValue( + object_args->Set(L"oldWindowId", Value::CreateIntegerValue( ExtensionTabUtil::GetWindowIdOfTab(contents))); - object_args->Set(L"index", Value::CreateIntegerValue(index)); + object_args->Set(L"oldPosition", Value::CreateIntegerValue(index)); args.Append(object_args); std::string json_args; @@ -163,12 +165,12 @@ void ExtensionBrowserEventRouter::TabSelectedAt(TabContents* old_contents, int index, bool user_gesture) { ListValue args; - DictionaryValue *object_args = new DictionaryValue(); - object_args->Set(L"tabId", Value::CreateIntegerValue( + args.Append(Value::CreateIntegerValue( ExtensionTabUtil::GetTabId(new_contents))); + + DictionaryValue *object_args = new DictionaryValue(); object_args->Set(L"windowId", Value::CreateIntegerValue( ExtensionTabUtil::GetWindowIdOfTab(new_contents))); - object_args->Set(L"index", Value::CreateIntegerValue(index)); args.Append(object_args); std::string json_args; @@ -181,9 +183,9 @@ void ExtensionBrowserEventRouter::TabMoved(TabContents* contents, int from_index, int to_index) { ListValue args; + args.Append(Value::CreateIntegerValue(ExtensionTabUtil::GetTabId(contents))); + DictionaryValue *object_args = new DictionaryValue(); - object_args->Set(L"tabId", Value::CreateIntegerValue( - ExtensionTabUtil::GetTabId(contents))); object_args->Set(L"windowId", Value::CreateIntegerValue( ExtensionTabUtil::GetWindowIdOfTab(contents))); object_args->Set(L"fromIndex", Value::CreateIntegerValue(from_index)); diff --git a/chrome/browser/extensions/extension_browser_event_router.h b/chrome/browser/extensions/extension_browser_event_router.h index 51099fd..afebdd3 100644 --- a/chrome/browser/extensions/extension_browser_event_router.h +++ b/chrome/browser/extensions/extension_browser_event_router.h @@ -11,6 +11,7 @@ #include "base/basictypes.h" #include "base/singleton.h" +#include "chrome/browser/browser_list.h" #include "chrome/browser/tabs/tab_strip_model.h" #include "chrome/common/notification_observer.h" @@ -20,7 +21,7 @@ // events from windows/tabs within a profile to extension processes in the same // profile. class ExtensionBrowserEventRouter : public TabStripModelObserver, - public NotificationObserver { + public BrowserList::Observer { public: // Get Browser-Global instance. static ExtensionBrowserEventRouter* GetInstance(); @@ -28,7 +29,12 @@ class ExtensionBrowserEventRouter : public TabStripModelObserver, // Must be called once. Subsequent calls have no effect. void Init(); - // TabStripModelObserver. + // BrowserList::Observer + virtual void OnBrowserAdded(const Browser* browser); + virtual void OnBrowserRemoving(const Browser* browser); + virtual void OnBrowserSetLastActive(const Browser* browser); + + // TabStripModelObserver void TabInsertedAt(TabContents* contents, int index, bool foreground); void TabClosingAt(TabContents* contents, int index); void TabDetachedAt(TabContents* contents, int index); @@ -51,10 +57,8 @@ class ExtensionBrowserEventRouter : public TabStripModelObserver, const NotificationSource& source, const NotificationDetails& details); private: - // Construct and dispatch windows.onCreated event. - void BrowserOpened(Browser* browser); - // Construct and dispatch windows.onRemoved event. - void BrowserClosed(Browser* browser); + // "Synthetic" event. Called from TabInsertedAt if new tab is detected. + void TabCreatedAt(TabContents* contents, int index, bool foreground); ExtensionBrowserEventRouter(); friend struct DefaultSingletonTraits<ExtensionBrowserEventRouter>; diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index 8843ee8..bb093de 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -51,13 +51,21 @@ FactoryRegistry* FactoryRegistry::instance() { FactoryRegistry::FactoryRegistry() { // Register all functions here. - // Tabs. - factories_["GetWindows"] = &NewExtensionFunction<GetWindowsFunction>; + // Windows + factories_["GetWindow"] = &NewExtensionFunction<GetWindowFunction>; + factories_["GetCurrentWindow"] = + &NewExtensionFunction<GetCurrentWindowFunction>; + factories_["GetFocusedWindow"] = + &NewExtensionFunction<GetFocusedWindowFunction>; + factories_["GetAllWindows"] = &NewExtensionFunction<GetAllWindowsFunction>; factories_["CreateWindow"] = &NewExtensionFunction<CreateWindowFunction>; factories_["RemoveWindow"] = &NewExtensionFunction<RemoveWindowFunction>; - factories_["GetTabsForWindow"] = - &NewExtensionFunction<GetTabsForWindowFunction>; + + // Tabs factories_["GetTab"] = &NewExtensionFunction<GetTabFunction>; + factories_["GetSelectedTab"] = &NewExtensionFunction<GetSelectedTabFunction>; + factories_["GetAllTabsInWindow"] = + &NewExtensionFunction<GetAllTabsInWindowFunction>; factories_["CreateTab"] = &NewExtensionFunction<CreateTabFunction>; factories_["UpdateTab"] = &NewExtensionFunction<UpdateTabFunction>; factories_["MoveTab"] = &NewExtensionFunction<MoveTabFunction>; diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc index 41663dd..d219152 100644 --- a/chrome/browser/extensions/extension_tabs_module.cc +++ b/chrome/browser/extensions/extension_tabs_module.cc @@ -18,11 +18,30 @@ #include "chrome/common/temp_scaffolding_stubs.h" #endif +namespace { +// keys +const wchar_t* kIdKey = L"id"; +const wchar_t* kIndexKey = L"index"; +const wchar_t* kWindowIdKey = L"windowId"; +const wchar_t* kUrlKey = L"url"; +const wchar_t* kTitleKey = L"title"; +const wchar_t* kSelectedKey = L"selected"; +const wchar_t* kFocusedKey = L"focused"; +const wchar_t* kFavIconUrlKey = L"favIconUrl"; +const wchar_t* kLeftKey = L"left"; +const wchar_t* kTopKey = L"top"; +const wchar_t* kWidthKey = L"width"; +const wchar_t* kHeightKey = L"height"; +const wchar_t* kTabsKey = L"tabs"; +} + // Forward declare static helper functions defined below. -static DictionaryValue* CreateWindowValue(Browser* browser); +static DictionaryValue* CreateWindowValue(Browser* browser, bool populate_tabs); static ListValue* CreateTabList(Browser* browser); static bool GetIndexOfTabId(const TabStripModel* tab_strip, int tab_id, int* tab_index); +static Browser *GetBrowserInProfileWithId(Profile* profile, + const int window_id); // ExtensionTabUtil int ExtensionTabUtil::GetWindowId(const Browser* browser) { @@ -56,53 +75,68 @@ DictionaryValue* ExtensionTabUtil::CreateTabValue( DictionaryValue* ExtensionTabUtil::CreateTabValue( const TabContents* contents, TabStripModel* tab_strip, int tab_index) { DictionaryValue* result = new DictionaryValue(); - result->SetInteger(L"id", ExtensionTabUtil::GetTabId(contents)); - result->SetInteger(L"index", tab_index); - result->SetInteger(L"windowId", ExtensionTabUtil::GetWindowIdOfTab(contents)); - result->SetString(L"url", contents->GetURL().spec()); - result->SetString(L"title", UTF16ToWide(contents->GetTitle())); - result->SetBoolean(L"selected", + result->SetInteger(kIdKey, ExtensionTabUtil::GetTabId(contents)); + result->SetInteger(kIndexKey, tab_index); + result->SetInteger(kWindowIdKey, + ExtensionTabUtil::GetWindowIdOfTab(contents)); + result->SetString(kUrlKey, contents->GetURL().spec()); + result->SetString(kTitleKey, UTF16ToWide(contents->GetTitle())); + result->SetBoolean(kSelectedKey, tab_strip && tab_index == tab_strip->selected_index()); NavigationEntry* entry = contents->controller().GetActiveEntry(); if (entry) { if (entry->favicon().is_valid()) - result->SetString(L"favIconUrl", entry->favicon().url().spec()); + result->SetString(kFavIconUrlKey, entry->favicon().url().spec()); } return result; } -bool GetWindowsFunction::RunImpl() { - std::set<int> window_ids; +static bool GetWindowFunctionHelper(Browser *browser, Profile* profile, + scoped_ptr<Value>* result) { + // TODO(rafaelw): need "not found" error message. + if (browser == NULL || browser->profile() != profile) + return false; - // Look for |ids| named parameter as list of id's to fetch. - if (args_->IsType(Value::TYPE_DICTIONARY)) { - ListValue *window_id_list; - const DictionaryValue *args = static_cast<const DictionaryValue*>(args_); - EXTENSION_FUNCTION_VALIDATE(args->GetList(L"ids", &window_id_list)); - for (ListValue::iterator id = window_id_list->begin(); - id != window_id_list->end(); ++id) { - int window_id; - EXTENSION_FUNCTION_VALIDATE((*id)->GetAsInteger(&window_id)); - window_ids.insert(window_id); - } - } + result->reset(CreateWindowValue(browser, false)); + + return true; +} + +// Windows --------------------------------------------------------------------- - // Default to all windows. - bool all_windows = (window_ids.size() == 0); +bool GetWindowFunction::RunImpl() { + int window_id; + EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&window_id)); + + Browser *target = GetBrowserInProfileWithId(profile(), window_id); + return GetWindowFunctionHelper(target, profile(), &result_); +} + +bool GetCurrentWindowFunction::RunImpl() { + return GetWindowFunctionHelper(dispatcher_->browser(), profile(), &result_); +} + +bool GetFocusedWindowFunction::RunImpl() { + return GetWindowFunctionHelper(BrowserList::GetLastActive(), profile(), + &result_); +} + +bool GetAllWindowsFunction::RunImpl() { + bool populate_tabs = false; + if (!args_->IsType(Value::TYPE_NULL)) { + EXTENSION_FUNCTION_VALIDATE(args_->GetAsBoolean(&populate_tabs)); + } result_.reset(new ListValue()); for (BrowserList::const_iterator browser = BrowserList::begin(); - browser != BrowserList::end(); ++browser) { - // Only examine browsers in the current profile. - if ((*browser)->profile() == profile()) { - if (all_windows || (window_ids.find(ExtensionTabUtil:: - GetWindowId(*browser)) != window_ids.end())) { - static_cast<ListValue*>(result_.get())->Append( - CreateWindowValue(*browser)); + browser != BrowserList::end(); ++browser) { + // Only examine browsers in the current profile. + if ((*browser)->profile() == profile()) { + static_cast<ListValue*>(result_.get())-> + Append(CreateWindowValue(*browser, populate_tabs)); } - } } return true; @@ -112,10 +146,12 @@ bool CreateWindowFunction::RunImpl() { scoped_ptr<GURL> url(new GURL()); // Look for optional url. - if (args_->IsType(Value::TYPE_DICTIONARY)) { + if (!args_->IsType(Value::TYPE_NULL)) { + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY)); const DictionaryValue *args = static_cast<const DictionaryValue*>(args_); std::string url_input; - if (args->GetString(L"url", &url_input)) { + if (args->HasKey(kUrlKey)) { + EXTENSION_FUNCTION_VALIDATE(args->GetString(kUrlKey, &url_input)); url.reset(new GURL(url_input)); if (!url->is_valid()) { // TODO(rafaelw): need error message/callback here @@ -143,17 +179,25 @@ bool CreateWindowFunction::RunImpl() { if (args_->IsType(Value::TYPE_DICTIONARY)) { const DictionaryValue *args = static_cast<const DictionaryValue*>(args_); int bounds_val; - if (args->GetInteger(L"left", &bounds_val)) + if (args->HasKey(kLeftKey)) { + EXTENSION_FUNCTION_VALIDATE(args->GetInteger(kLeftKey, &bounds_val)); bounds.set_x(bounds_val); + } - if (args->GetInteger(L"top", &bounds_val)) + if (args->HasKey(kTopKey)) { + EXTENSION_FUNCTION_VALIDATE(args->GetInteger(kTopKey, &bounds_val)); bounds.set_y(bounds_val); + } - if (args->GetInteger(L"width", &bounds_val)) + if (args->HasKey(kWidthKey)) { + EXTENSION_FUNCTION_VALIDATE(args->GetInteger(kWidthKey, &bounds_val)); bounds.set_width(bounds_val); + } - if (args->GetInteger(L"height", &bounds_val)) + if (args->HasKey(kHeightKey)) { + EXTENSION_FUNCTION_VALIDATE(args->GetInteger(kHeightKey, &bounds_val)); bounds.set_height(bounds_val); + } } Browser *new_window = Browser::Create(dispatcher_->profile()); @@ -169,7 +213,7 @@ bool CreateWindowFunction::RunImpl() { // TODO(rafaelw): support |focused|, |zIndex| - result_.reset(CreateWindowValue(new_window)); + result_.reset(CreateWindowValue(new_window, false)); return true; } @@ -200,12 +244,44 @@ bool RemoveWindowFunction::RunImpl() { return true; } +// Tabs --------------------------------------------------------------------- -bool GetTabsForWindowFunction::RunImpl() { - EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_NULL)); +bool GetSelectedTabFunction::RunImpl() { + int window_id; + Browser *browser; + // windowId defaults to "current" window. + if (!args_->IsType(Value::TYPE_NULL)) { + EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&window_id)); + browser = GetBrowserInProfileWithId(profile(), window_id); + } else { + browser = dispatcher_->browser(); + } - Browser* browser = dispatcher_->browser(); if (!browser) + // TODO(rafaelw): return a "no 'current' browser" error. + return false; + + TabStripModel* tab_strip = browser->tabstrip_model(); + result_.reset(ExtensionTabUtil::CreateTabValue( + tab_strip->GetSelectedTabContents(), + tab_strip, + tab_strip->selected_index())); + return true; +} + +bool GetAllTabsInWindowFunction::RunImpl() { + int window_id; + Browser *browser; + // windowId defaults to "current" window. + if (!args_->IsType(Value::TYPE_NULL)) { + EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&window_id)); + browser = GetBrowserInProfileWithId(profile(), window_id); + } else { + browser = dispatcher_->browser(); + } + + if (!browser) + // TODO(rafaelw): return a "no 'current' browser" error. return false; result_.reset(CreateTabList(browser)); @@ -217,8 +293,18 @@ bool CreateTabFunction::RunImpl() { EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY)); const DictionaryValue *args = static_cast<const DictionaryValue*>(args_); - Browser* browser = BrowserList::GetLastActive(); + int window_id; + Browser *browser; + // windowId defaults to "current" window. + if (args->HasKey(kWindowIdKey)) { + EXTENSION_FUNCTION_VALIDATE(args->GetInteger(kWindowIdKey, &window_id)); + browser = GetBrowserInProfileWithId(profile(), window_id); + } else { + browser = dispatcher_->browser(); + } + if (!browser) + // TODO(rafaelw): return a "no 'current' browser" error. return false; TabStripModel *tab_strip = browser->tabstrip_model(); @@ -228,18 +314,29 @@ bool CreateTabFunction::RunImpl() { // -title // -favIconUrl - std::string url; - args->GetString(L"url", &url); + std::string url_string; + scoped_ptr<GURL> url; + if (args->HasKey(kUrlKey)) { + EXTENSION_FUNCTION_VALIDATE(args->GetString(kUrlKey, &url_string)); + url.reset(new GURL(url_string)); + + // TODO(rafaelw): return an "invalid url" error. + if (!url->is_valid()) + return false; + } // Default to foreground for the new tab. The presence of 'selected' property // will override this default. bool selected = true; - args->GetBoolean(L"selected", &selected); + if (args->HasKey(kSelectedKey)) + EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(kSelectedKey, &selected)); // If index is specified, honor the value, but keep it bound to // 0 <= index <= tab_strip->count() int index = -1; - args->GetInteger(L"index", &index); + if (args->HasKey(kIndexKey)) + EXTENSION_FUNCTION_VALIDATE(args->GetInteger(kIndexKey, &index)); + if (index < 0) { // Default insert behavior index = -1; @@ -248,7 +345,7 @@ bool CreateTabFunction::RunImpl() { index = tab_strip->count(); } - TabContents* contents = browser->AddTabWithURL(GURL(url), GURL(), + TabContents* contents = browser->AddTabWithURL(*(url.get()), GURL(), PageTransition::LINK, selected, index, NULL); index = tab_strip->GetIndexOfTabContents(contents); @@ -263,27 +360,41 @@ bool GetTabFunction::RunImpl() { int tab_id; EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&tab_id)); - Browser* browser = BrowserList::GetLastActive(); - if (!browser) - return false; + int tab_index = -1; + Browser *target = NULL; + TabStripModel *tab_strip = NULL; + for (BrowserList::const_iterator browser = BrowserList::begin(); + browser != BrowserList::end(); ++browser) { + if ((*browser)->profile() == profile()) { + target = *browser; + tab_strip = (*browser)->tabstrip_model(); + if (GetIndexOfTabId(tab_strip, tab_id, &tab_index)) { + break; + } + } + } - int tab_index; - TabStripModel* tab_strip = browser->tabstrip_model(); - // TODO(rafaelw): return an error if the tab is not found by |tab_id| - if (!GetIndexOfTabId(tab_strip, tab_id, &tab_index)) + if (target == NULL || tab_index == -1) { + // TODO(rafaelw): need "not found" error message. return false; + } - result_.reset(ExtensionTabUtil::CreateTabValue( - tab_strip->GetTabContentsAt(tab_index), tab_strip, tab_index)); + TabContents *contents = target->tabstrip_model()->GetTabContentsAt(tab_index); + result_.reset(ExtensionTabUtil::CreateTabValue(contents, tab_strip, + tab_index)); return true; } bool UpdateTabFunction::RunImpl() { int tab_id; - EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY)); - const DictionaryValue *args = static_cast<const DictionaryValue*>(args_); - EXTENSION_FUNCTION_VALIDATE(args->GetInteger(L"id", &tab_id)); - + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_LIST)); + const ListValue *args = static_cast<const ListValue*>(args_); + EXTENSION_FUNCTION_VALIDATE(args->GetInteger(0, &tab_id)); + DictionaryValue *update_props; + EXTENSION_FUNCTION_VALIDATE(args->GetDictionary(1, &update_props)); + + // TODO(rafaelw): Need to search for appropriate browser that contains + // |tab_id|. Browser* browser = BrowserList::GetLastActive(); if (!browser) return false; @@ -303,22 +414,26 @@ bool UpdateTabFunction::RunImpl() { // Navigate the tab to a new location if the url different. std::string url; - if (args->GetString(L"url", &url)) { + if (update_props->HasKey(kUrlKey)) { + EXTENSION_FUNCTION_VALIDATE(update_props->GetString(kUrlKey, &url)); GURL new_gurl(url); - if (new_gurl.is_valid()) { - controller.LoadURL(new_gurl, GURL(), PageTransition::LINK); - } else { - // TODO(rafaelw): return some reasonable error? - } + + // TODO(rafaelw): return "invalid url" here. + if (!new_gurl.is_valid()) + return false; + + controller.LoadURL(new_gurl, GURL(), PageTransition::LINK); } - bool selected; + bool selected = false; // TODO(rafaelw): Setting |selected| from js doesn't make much sense. // Move tab selection management up to window. - if (args->GetBoolean(L"selected", &selected) && - selected && - tab_strip->selected_index() != tab_index) { - tab_strip->SelectTabContentsAt(tab_index, false); + if (update_props->HasKey(kSelectedKey)) { + EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(kSelectedKey, + &selected)); + if (selected && tab_strip->selected_index() != tab_index) { + tab_strip->SelectTabContentsAt(tab_index, false); + } } return true; @@ -326,20 +441,23 @@ bool UpdateTabFunction::RunImpl() { bool MoveTabFunction::RunImpl() { int tab_id; + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_LIST)); + const ListValue *args = static_cast<const ListValue*>(args_); + EXTENSION_FUNCTION_VALIDATE(args->GetInteger(0, &tab_id)); + DictionaryValue *update_props; + EXTENSION_FUNCTION_VALIDATE(args->GetDictionary(1, &update_props)); + int new_index; - EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY)); - const DictionaryValue *args = static_cast<const DictionaryValue*>(args_); - EXTENSION_FUNCTION_VALIDATE(args->GetInteger(L"id", &tab_id)); - EXTENSION_FUNCTION_VALIDATE(args->GetInteger(L"index", &new_index)); + EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(kIndexKey, &new_index)); EXTENSION_FUNCTION_VALIDATE(new_index >= 0); + // TODO(rafaelw): need to support finding the tab by id in any browser, + // not just the currently active browser. Browser* browser = BrowserList::GetLastActive(); if (!browser) return false; - int tab_index; TabStripModel* tab_strip = browser->tabstrip_model(); - // TODO(rafaelw): return an error if the tab is not found by |tab_id| if (!GetIndexOfTabId(tab_strip, tab_id, &tab_index)) return false; @@ -380,19 +498,24 @@ bool RemoveTabFunction::RunImpl() { } // static helpers -static DictionaryValue* CreateWindowValue(Browser* browser) { +// if |populate| is true, each window gets a list property |tabs| which contains +// fully populated tab objects. +static DictionaryValue* CreateWindowValue(Browser* browser, + bool populate_tabs) { DictionaryValue* result = new DictionaryValue(); - result->SetInteger(L"id", ExtensionTabUtil::GetWindowId(browser)); - result->SetBoolean(L"focused", browser->window()->IsActive()); + result->SetInteger(kIdKey, ExtensionTabUtil::GetWindowId(browser)); + result->SetBoolean(kFocusedKey, browser->window()->IsActive()); gfx::Rect bounds = browser->window()->GetNormalBounds(); // TODO(rafaelw): zIndex ? - result->SetInteger(L"left", bounds.x()); - result->SetInteger(L"top", bounds.y()); - result->SetInteger(L"width", bounds.width()); - result->SetInteger(L"height", bounds.height()); + result->SetInteger(kLeftKey, bounds.x()); + result->SetInteger(kTopKey, bounds.y()); + result->SetInteger(kWidthKey, bounds.width()); + result->SetInteger(kHeightKey, bounds.height()); - result->Set(L"tabs", CreateTabList(browser)); + if (populate_tabs) { + result->Set(kTabsKey, CreateTabList(browser)); + } return result; } @@ -419,3 +542,14 @@ static bool GetIndexOfTabId(const TabStripModel* tab_strip, int tab_id, } return false; } + +static Browser *GetBrowserInProfileWithId(Profile* profile, + const int window_id) { + for (BrowserList::const_iterator browser = BrowserList::begin(); + browser != BrowserList::end(); ++browser) { + if ((*browser)->profile() == profile && + ExtensionTabUtil::GetWindowId(*browser) == window_id) + return *browser; + } + return NULL; +} diff --git a/chrome/browser/extensions/extension_tabs_module.h b/chrome/browser/extensions/extension_tabs_module.h index c139f6a..35f59b42 100644 --- a/chrome/browser/extensions/extension_tabs_module.h +++ b/chrome/browser/extensions/extension_tabs_module.h @@ -22,7 +22,17 @@ class ExtensionTabUtil { const TabContents* tab_contents, TabStripModel* tab_strip, int tab_index); }; -class GetWindowsFunction : public SyncExtensionFunction { +// Windows +class GetWindowFunction : public SyncExtensionFunction { + virtual bool RunImpl(); +}; +class GetCurrentWindowFunction : public SyncExtensionFunction { + virtual bool RunImpl(); +}; +class GetFocusedWindowFunction : public SyncExtensionFunction { + virtual bool RunImpl(); +}; +class GetAllWindowsFunction : public SyncExtensionFunction { virtual bool RunImpl(); }; class CreateWindowFunction : public SyncExtensionFunction { @@ -31,13 +41,18 @@ class CreateWindowFunction : public SyncExtensionFunction { class RemoveWindowFunction : public SyncExtensionFunction { virtual bool RunImpl(); }; -class GetTabsForWindowFunction : public SyncExtensionFunction { + +// Tabs +class GetTabFunction : public SyncExtensionFunction { virtual bool RunImpl(); }; -class CreateTabFunction : public SyncExtensionFunction { +class GetSelectedTabFunction : public SyncExtensionFunction { virtual bool RunImpl(); }; -class GetTabFunction : public SyncExtensionFunction { +class GetAllTabsInWindowFunction : public SyncExtensionFunction { + virtual bool RunImpl(); +}; +class CreateTabFunction : public SyncExtensionFunction { virtual bool RunImpl(); }; class UpdateTabFunction : public SyncExtensionFunction { diff --git a/chrome/renderer/extensions/extension_api_client_unittest.cc b/chrome/renderer/extensions/extension_api_client_unittest.cc index 172263a..6233dfb 100755 --- a/chrome/renderer/extensions/extension_api_client_unittest.cc +++ b/chrome/renderer/extensions/extension_api_client_unittest.cc @@ -75,7 +75,7 @@ TEST_F(ExtensionAPIClientTest, CallbackDispatching) { " 'incorrect result');" " console.log('pass')" "}" - "chromium.tabs.createTab({}, callback);" + "chromium.tabs.create({}, callback);" ); EXPECT_EQ("", GetConsoleMessage()); @@ -102,72 +102,210 @@ TEST_F(ExtensionAPIClientTest, CallbackDispatching) { // extension functions. We test both error and success conditions, but do not // test errors exhaustively as json schema code is well tested by itself. -TEST_F(ExtensionAPIClientTest, GetTabsForWindow) { - ExpectJsFail("chromium.tabs.getTabsForWindow(42, function(){});", +// Window API tests + +TEST_F(ExtensionAPIClientTest, GetWindow) { + ExpectJsFail("chromium.windows.get(32, function(){}, 20);", "Uncaught Error: Too many arguments."); - ExpectJsPass("chromium.tabs.getTabsForWindow(function(){})", - "GetTabsForWindow", "null"); + ExpectJsFail("chromium.windows.get(32);", + "Uncaught Error: Parameter 1 is required."); + + ExpectJsFail("chromium.windows.get('abc', function(){});", + "Uncaught Error: Invalid value for argument 0. " + "Expected 'integer' but got 'string'."); + + ExpectJsFail("chromium.windows.get(1, 1);", + "Uncaught Error: Invalid value for argument 1. " + "Expected 'function' but got 'integer'."); + + ExpectJsPass("chromium.windows.get(2, function(){})", + "GetWindow", "2"); } -TEST_F(ExtensionAPIClientTest, GetTab) { - ExpectJsFail("chromium.tabs.getTab(null, function(){});", +TEST_F(ExtensionAPIClientTest, GetCurentWindow) { + ExpectJsFail("chromium.windows.getCurrent(function(){}, 20);", + "Uncaught Error: Too many arguments."); + + ExpectJsFail("chromium.windows.getCurrent();", + "Uncaught Error: Parameter 0 is required."); + + ExpectJsFail("chromium.windows.getCurrent('abc');", + "Uncaught Error: Invalid value for argument 0. " + "Expected 'function' but got 'string'."); + + ExpectJsPass("chromium.windows.getCurrent(function(){})", + "GetCurrentWindow", "null"); +} + +TEST_F(ExtensionAPIClientTest, GetFocusedWindow) { + ExpectJsFail("chromium.windows.getFocused(function(){}, 20);", + "Uncaught Error: Too many arguments."); + + ExpectJsFail("chromium.windows.getFocused();", "Uncaught Error: Parameter 0 is required."); - ExpectJsPass("chromium.tabs.getTab(42)", "GetTab", "42"); + ExpectJsFail("chromium.windows.getFocused('abc');", + "Uncaught Error: Invalid value for argument 0. " + "Expected 'function' but got 'string'."); + + ExpectJsPass("chromium.windows.getFocused(function(){})", + "GetFocusedWindow", "null"); +} + +TEST_F(ExtensionAPIClientTest, GetAllWindows) { + ExpectJsFail("chromium.windows.getAll(true, function(){}, 20);", + "Uncaught Error: Too many arguments."); + + ExpectJsFail("chromium.windows.getAll(1, function(){});", + "Uncaught Error: Invalid value for argument 0. " + "Expected 'boolean' but got 'integer'."); + + ExpectJsPass("chromium.windows.getAll(true, function(){})", + "GetAllWindows", "true"); + + ExpectJsPass("chromium.windows.getAll(null, function(){})", + "GetAllWindows", "null"); + + ExpectJsPass("chromium.windows.getAll(undefined, function(){})", + "GetAllWindows", "null"); +} + +// Tab API tests + +TEST_F(ExtensionAPIClientTest, GetTab) { + ExpectJsFail("chromium.tabs.get(32, function(){}, 20);", + "Uncaught Error: Too many arguments."); + + ExpectJsFail("chromium.tabs.get(32);", + "Uncaught Error: Parameter 1 is required."); + + ExpectJsFail("chromium.tabs.get('abc', function(){});", + "Uncaught Error: Invalid value for argument 0. " + "Expected 'integer' but got 'string'."); + + ExpectJsFail("chromium.tabs.get(1, 1);", + "Uncaught Error: Invalid value for argument 1. " + "Expected 'function' but got 'integer'."); + + ExpectJsPass("chromium.tabs.get(2, function(){})", + "GetTab", "2"); +} + +TEST_F(ExtensionAPIClientTest, GetSelectedTab) { + ExpectJsFail("chromium.tabs.getSelected(32, function(){}, 20);", + "Uncaught Error: Too many arguments."); + + ExpectJsFail("chromium.tabs.getSelected(32);", + "Uncaught Error: Parameter 1 is required."); + + ExpectJsFail("chromium.tabs.getSelected('abc', function(){});", + "Uncaught Error: Invalid value for argument 0. " + "Expected 'integer' but got 'string'."); + + ExpectJsFail("chromium.tabs.getSelected(1, 1);", + "Uncaught Error: Invalid value for argument 1. " + "Expected 'function' but got 'integer'."); + + ExpectJsPass("chromium.tabs.getSelected(2, function(){})", + "GetSelectedTab", "2"); + + ExpectJsPass("chromium.tabs.getSelected(null, function(){})", + "GetSelectedTab", "null"); +} + + +TEST_F(ExtensionAPIClientTest, GetAllTabsInWindow) { + ExpectJsFail("chromium.tabs.getAllInWindow(42, function(){}, 'asd');", + "Uncaught Error: Too many arguments."); + + ExpectJsFail("chromium.tabs.getAllInWindow(32);", + "Uncaught Error: Parameter 1 is required."); + + ExpectJsFail("chromium.tabs.getAllInWindow(1, 1);", + "Uncaught Error: Invalid value for argument 1. " + "Expected 'function' but got 'integer'."); + + ExpectJsFail("chromium.tabs.getAllInWindow('asd', function(){});", + "Uncaught Error: Invalid value for argument 0. " + "Expected 'integer' but got 'string'."); + + ExpectJsPass("chromium.tabs.getAllInWindow(32, function(){})", + "GetAllTabsInWindow", "32"); + + ExpectJsPass("chromium.tabs.getAllInWindow(undefined, function(){})", + "GetAllTabsInWindow", "null"); } TEST_F(ExtensionAPIClientTest, CreateTab) { - ExpectJsFail("chromium.tabs.createTab({windowId: 'foo'}, function(){});", + ExpectJsFail("chromium.tabs.create({windowId: 'foo'}, function(){});", "Uncaught Error: Invalid value for argument 0. Property " "'windowId': Expected 'integer' but got 'string'."); - ExpectJsFail("chromium.tabs.createTab({url: 42}, function(){});", + ExpectJsFail("chromium.tabs.create({url: 42}, function(){});", "Uncaught Error: Invalid value for argument 0. Property " "'url': Expected 'string' but got 'integer'."); - ExpectJsFail("chromium.tabs.createTab({foo: 42}, function(){});", + ExpectJsFail("chromium.tabs.create({foo: 42}, function(){});", "Uncaught Error: Invalid value for argument 0. Property " "'foo': Unexpected property."); - ExpectJsPass("chromium.tabs.createTab({" + ExpectJsPass("chromium.tabs.create({" " url:'http://www.google.com/'," " selected:true," + " index: 2," " windowId:4" "})", "CreateTab", "{\"url\":\"http://www.google.com/\"," "\"selected\":true," + "\"index\":2," "\"windowId\":4}"); } TEST_F(ExtensionAPIClientTest, UpdateTab) { - ExpectJsFail("chromium.tabs.updateTab({id: null});", - "Uncaught Error: Invalid value for argument 0. Property " - "'id': Property is required."); - ExpectJsFail("chromium.tabs.updateTab({id: 42, windowId: 'foo'});", - "Uncaught Error: Invalid value for argument 0. Property " - "'windowId': Expected 'integer' but got 'string'."); - ExpectJsFail("chromium.tabs.updateTab({id: 42, url: 42});", - "Uncaught Error: Invalid value for argument 0. Property " + ExpectJsFail("chromium.tabs.update(null);", + "Uncaught Error: Parameter 0 is required."); + ExpectJsFail("chromium.tabs.update(42, {selected: 'foo'});", + "Uncaught Error: Invalid value for argument 1. Property " + "'selected': Expected 'boolean' but got 'string'."); + ExpectJsFail("chromium.tabs.update(42, {url: 42});", + "Uncaught Error: Invalid value for argument 1. Property " "'url': Expected 'string' but got 'integer'."); - ExpectJsPass("chromium.tabs.updateTab({" - " id:42," + ExpectJsPass("chromium.tabs.update(42, {" " url:'http://www.google.com/'," - " selected:true," - " windowId:4" + " selected:true" "})", "UpdateTab", - "{\"id\":42," - "\"url\":\"http://www.google.com/\"," - "\"selected\":true," - "\"windowId\":4}"); + "[42," + "{\"url\":\"http://www.google.com/\"," + "\"selected\":true}]"); +} + +TEST_F(ExtensionAPIClientTest, MoveTab) { + ExpectJsFail("chromium.tabs.move(null);", + "Uncaught Error: Parameter 0 is required."); + ExpectJsFail("chromium.tabs.move(42, {index: 'foo'});", + "Uncaught Error: Invalid value for argument 1. Property " + "'index': Expected 'integer' but got 'string'."); + ExpectJsFail("chromium.tabs.move(42, {index: 3, windowId: 'foo'});", + "Uncaught Error: Invalid value for argument 1. Property " + "'windowId': Expected 'integer' but got 'string'."); + + ExpectJsPass("chromium.tabs.move(42, {" + " index:3," + " windowId:21" + "})", + "MoveTab", + "[42," + "{\"index\":3," + "\"windowId\":21}]"); } TEST_F(ExtensionAPIClientTest, RemoveTab) { - ExpectJsFail("chromium.tabs.removeTab('foobar', function(){});", + ExpectJsFail("chromium.tabs.remove('foobar', function(){});", "Uncaught Error: Too many arguments."); - ExpectJsPass("chromium.tabs.removeTab(21)", "RemoveTab", "21"); + ExpectJsPass("chromium.tabs.remove(21)", "RemoveTab", "21"); } // Bookmark API tests diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd index cda253b..c59e98c 100755 --- 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. --> +without changes to the corresponding grd file. --> <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 00bb0fa..d1907d8 100644 --- a/chrome/renderer/resources/extension_process_bindings.js +++ b/chrome/renderer/resources/extension_process_bindings.js @@ -10,11 +10,15 @@ var chromium; (function() { native function GetNextCallbackId(); + native function GetWindow(); + native function GetCurrentWindow(); + native function GetFocusedWindow(); native function CreateWindow(); native function RemoveWindow(); - native function GetWindows(); - native function GetTabsForWindow(); + native function GetAllWindows(); native function GetTab(); + native function GetSelectedTab(); + native function GetAllTabsInWindow(); native function CreateTab(); native function UpdateTab(); native function MoveTab(); @@ -95,24 +99,42 @@ var chromium; // Windows. chromium.windows = {}; - chromium.windows.getWindows = function(windowQuery, callback) { + chromium.windows.get = function(windowId, callback) { validate(arguments, arguments.callee.params); - sendRequest(GetWindows, windowQuery, callback); + sendRequest(GetWindow, windowId, callback); }; - chromium.windows.getWindows.params = [ - { - type: "object", - properties: { - ids: { - type: "array", - items: chromium.types.pInt, - minItems: 1 - } - }, - optional: true - }, - chromium.types.optFun + chromium.windows.get.params = [ + chromium.types.pInt, + chromium.types.fun + ]; + + chromium.windows.getCurrent = function(callback) { + validate(arguments, arguments.callee.params); + sendRequest(GetCurrentWindow, null, callback); + }; + + chromium.windows.getCurrent.params = [ + chromium.types.fun + ]; + + chromium.windows.getFocused = function(callback) { + validate(arguments, arguments.callee.params); + sendRequest(GetFocusedWindow, null, callback); + }; + + chromium.windows.getFocused.params = [ + chromium.types.fun + ]; + + chromium.windows.getAll = function(populate, callback) { + validate(arguments, arguments.callee.params); + sendRequest(GetAllWindows, populate, callback); + }; + + chromium.windows.getAll.params = [ + chromium.types.optBool, + chromium.types.fun ]; chromium.windows.createWindow = function(createData, callback) { @@ -146,49 +168,64 @@ var chromium; // sends (windowId). // *WILL* be followed by tab-attached AND then tab-selection-changed. - chromium.windows.onWindowCreated = new chromium.Event("window-created"); + chromium.windows.onCreated = new chromium.Event("window-created"); // sends (windowId). // *WILL* be preceded by sequences of tab-removed AND then // tab-selection-changed -- one for each tab that was contained in the window // that closed - chromium.windows.onWindowRemoved = new chromium.Event("window-removed"); + chromium.windows.onRemoved = new chromium.Event("window-removed"); + + // sends (windowId). + chromium.windows.onFocusChanged = + new chromium.Event("window-focus-changed"); //---------------------------------------------------------------------------- // Tabs chromium.tabs = {}; - // TODO(aa): This should eventually take an optional windowId param. - chromium.tabs.getTabsForWindow = function(callback) { + chromium.tabs.get = function(tabId, callback) { validate(arguments, arguments.callee.params); - sendRequest(GetTabsForWindow, null, callback); + sendRequest(GetTab, tabId, callback); }; - chromium.tabs.getTabsForWindow.params = [ - chromium.types.optFun + chromium.tabs.get.params = [ + chromium.types.pInt, + chromium.types.fun + ]; + + chromium.tabs.getSelected = function(windowId, callback) { + validate(arguments, arguments.callee.params); + sendRequest(GetSelectedTab, windowId, callback); + }; + + chromium.tabs.getSelected.params = [ + chromium.types.optPInt, + chromium.types.fun ]; - chromium.tabs.getTab = function(tabId, callback) { + chromium.tabs.getAllInWindow = function(windowId, callback) { validate(arguments, arguments.callee.params); - sendRequest(GetTab, tabId, callback); + sendRequest(GetAllTabsInWindow, windowId, callback); }; - chromium.tabs.getTab.params = [ - chromium.types.pInt, - chromium.types.optFun + chromium.tabs.getAllInWindow.params = [ + chromium.types.optPInt, + chromium.types.fun ]; - chromium.tabs.createTab = function(tab, callback) { + chromium.tabs.create = function(tab, callback) { validate(arguments, arguments.callee.params); sendRequest(CreateTab, tab, callback); }; - chromium.tabs.createTab.params = [ + chromium.tabs.create.params = [ { type: "object", properties: { windowId: chromium.types.optPInt, + index: chromium.types.optPInt, url: chromium.types.optStr, selected: chromium.types.optBool } @@ -196,73 +233,74 @@ var chromium; chromium.types.optFun ]; - chromium.tabs.updateTab = function(tab) { + chromium.tabs.update = function(tabId, updates, callback) { validate(arguments, arguments.callee.params); - sendRequest(UpdateTab, tab); + sendRequest(UpdateTab, [tabId, updates], callback); }; - chromium.tabs.updateTab.params = [ + chromium.tabs.update.params = [ + chromium.types.pInt, { type: "object", properties: { - id: chromium.types.pInt, - windowId: chromium.types.optPInt, url: chromium.types.optStr, selected: chromium.types.optBool } - } + }, + chromium.types.optFun ]; - chromium.tabs.moveTab = function(tab) { + chromium.tabs.move = function(tabId, moveProps, callback) { validate(arguments, arguments.callee.params); - sendRequest(MoveTab, tab); + sendRequest(MoveTab, [tabId, moveProps], callback); }; - chromium.tabs.moveTab.params = [ + chromium.tabs.move.params = [ + chromium.types.pInt, { type: "object", properties: { - id: chromium.types.pInt, windowId: chromium.types.optPInt, index: chromium.types.pInt } - } + }, + chromium.types.optFun ]; - chromium.tabs.removeTab = function(tabId) { + chromium.tabs.remove = function(tabId) { validate(arguments, arguments.callee.params); sendRequest(RemoveTab, tabId); }; - chromium.tabs.removeTab.params = [ + chromium.tabs.remove.params = [ chromium.types.pInt ]; - // Sends ({tabId, windowId, index}). + // Sends ({Tab}). // Will *NOT* be followed by tab-attached - it is implied. // *MAY* be followed by tab-selection-changed. - chromium.tabs.onTabCreated = new chromium.Event("tab-created"); + chromium.tabs.onCreated = new chromium.Event("tab-created"); - // Wends ({tabId, windowId, fromIndex, toIndex}). + // Sends (tabId, {windowId, fromIndex, toIndex}). // Tabs can only "move" within a window. - chromium.tabs.onTabMoved = new chromium.Event("tab-moved"); + chromium.tabs.onMoved = new chromium.Event("tab-moved"); - // Sends ({tabId, windowId, index}). - chromium.tabs.onTabSelectionChanged = + // Sends (tabId, {windowId}). + chromium.tabs.onSelectionChanged = new chromium.Event("tab-selection-changed"); - // Sends ({tabId, windowId, index}). + // Sends (tabId, {newWindowId, newPosition}). // *MAY* be followed by tab-selection-changed. - chromium.tabs.onTabAttached = new chromium.Event("tab-attached"); + chromium.tabs.onAttached = new chromium.Event("tab-attached"); - // Sends ({tabId, windowId, index}). + // Sends (tabId, {oldWindowId, oldPosition}). // *WILL* be followed by tab-selection-changed. - chromium.tabs.onTabDetached = new chromium.Event("tab-detached"); + chromium.tabs.onDetached = new chromium.Event("tab-detached"); // Sends (tabId). // *WILL* be followed by tab-selection-changed. // Will *NOT* be followed or preceded by tab-detached. - chromium.tabs.onTabRemoved = new chromium.Event("tab-removed"); + chromium.tabs.onRemoved = new chromium.Event("tab-removed"); //---------------------------------------------------------------------------- diff --git a/chrome/test/data/extensions/samples/gmail/gmail_checker.html b/chrome/test/data/extensions/samples/gmail/gmail_checker.html index e52d78d..f754ad7 100644 --- a/chrome/test/data/extensions/samples/gmail/gmail_checker.html +++ b/chrome/test/data/extensions/samples/gmail/gmail_checker.html @@ -86,7 +86,7 @@ function requestUnreadFeed() { } function goToInbox() { - chromium.tabs.createTab({url:"http://www.gmail.com/"}); + chromium.tabs.create({url:"http://www.gmail.com/"}); } </script> diff --git a/chrome/test/data/extensions/samples/subscribe/toolstrip.html b/chrome/test/data/extensions/samples/subscribe/toolstrip.html index 6822215..cc6ca3a 100644 --- a/chrome/test/data/extensions/samples/subscribe/toolstrip.html +++ b/chrome/test/data/extensions/samples/subscribe/toolstrip.html @@ -45,7 +45,7 @@ function handleClick() {
if (enabled) {
var url = "http://www.google.com/reader/view/feed/" + feedUrl;
- chromium.tabs.createTab({url: url});
+ chromium.tabs.create({url: url});
}
}
</script>
diff --git a/chrome/test/data/extensions/samples/tabs/tabs_api.html b/chrome/test/data/extensions/samples/tabs/tabs_api.html index 022d1a7..abcf802 100644 --- a/chrome/test/data/extensions/samples/tabs/tabs_api.html +++ b/chrome/test/data/extensions/samples/tabs/tabs_api.html @@ -6,16 +6,32 @@ tabs = {}; tabIds = []; +focusedWindowId = undefined; +currentWindowId = undefined; + +function bootStrap() { + chromium.windows.getCurrent(function(currentWindow) { + currentWindowId = currentWindow.id; + chromium.windows.getFocused(function(focusedWindow) { + focusedWindowId = focusedWindow.id; + loadWindowList(); + }); + }); +} + function loadWindowList() { - chromium.windows.getWindows(undefined, function(windowList) { + chromium.windows.getAll(true, function(windowList) { tabs = {}; tabIds = []; for (var i = 0; i < windowList.length; i++) { - for (var j = 0; j < windowList[i].tabs.length; j++) { - tabIds[tabIds.length] = windowList[i].tabs[j].id; - tabs[windowList[i].tabs[j].id] = windowList[i].tabs[j]; - } - } + windowList[i].current = (windowList[i].id == currentWindowId); + windowList[i].focused = (windowList[i].id == focusedWindowId); + + for (var j = 0; j < windowList[i].tabs.length; j++) { + tabIds[tabIds.length] = windowList[i].tabs[j].id; + tabs[windowList[i].tabs[j].id] = windowList[i].tabs[j]; + } + } var input = new JsExprContext(windowList); var output = document.getElementById('windowList'); @@ -25,9 +41,7 @@ function loadWindowList() { function updateTabData(id) { var retval = { - id: id, url: document.getElementById('url_' + id).value, - windowId: parseInt(document.getElementById('windowId_' + id).value), selected: document.getElementById('selected_' + id).value ? true : false } @@ -35,22 +49,31 @@ function updateTabData(id) { } function updateTab(id){ - chromium.tabs.updateTab(updateTabData(id)); + try { + chromium.tabs.update(id, updateTabData(id)); + } catch (e) { + alert(e); + } } + function moveTabData(id) { return { - 'id': id, - 'index': parseInt(document.getElementById('index_' + id).value), - 'windowId': parseInt(document.getElementById('windowId_' + id).value) + 'index': parseInt(document.getElementById('index_' + id).value), + 'windowId': parseInt(document.getElementById('windowId_' + id).value) } } function moveTab(id) { - chromium.tabs.moveTab(moveTabData(id)); + try { + chromium.tabs.move(id, moveTabData(id)); + } catch (e) { + alert(e); + } } function createTabData(id) { return { + 'index': parseInt(document.getElementById('index_' + id).value), 'windowId': parseInt(document.getElementById('windowId_' + id).value), 'url': document.getElementById('url_' + id).value, 'selected': document.getElementById('selected_' + id).value ? true : false @@ -58,20 +81,38 @@ function createTabData(id) { } function createTab() { - chromium.tabs.createTab(createTabData('new')); + var args = createTabData('new') + + if (!isInt(args.windowId)) + delete args.windowId; + if (!isInt(args.index)) + delete args.index; + + try { + chromium.tabs.create(args); + } catch (e) { + alert(e); + } } function updateAll() { - - for (var i = 0; i < tabIds.length; i++) { - chromium.tabs.updateTab(updateTabData(tabIds[i])); + try { + for (var i = 0; i < tabIds.length; i++) { + chromium.tabs.update(tabIds[i], updateTabData(tabIds[i])); + } + } catch(e) { + alert(e); } } function moveAll() { appendToLog('moving all'); - for (var i = 0; i < tabIds.length; i++) { - chromium.tabs.moveTab(moveTabData(tabIds[i])); + try { + for (var i = 0; i < tabIds.length; i++) { + chromium.tabs.move(tabIds[i], moveTabData(tabIds[i])); + } + } catch(e) { + alert(e); } } @@ -84,43 +125,49 @@ function clearLog() { document.getElementById('log').innerHTML = ''; } -chromium.windows.onWindowCreated.addListener(function(windowId) { - appendToLog('onWindowCreated -- window: ' + windowId); +chromium.windows.onCreated.addListener(function(windowId) { + appendToLog('windows.onCreated -- window: ' + windowId); loadWindowList(); }); -chromium.windows.onWindowRemoved.addListener(function(windowId) { - appendToLog('onWindowRemoved -- window: ' + windowId); +chromium.windows.onFocusChanged.addListener(function(windowId) { + focusedWindowId = windowId; + appendToLog('windows.onFocusChanged -- window: ' + windowId); loadWindowList(); }); -chromium.tabs.onTabCreated.addListener(function(data) { - appendToLog('onTabCreated -- window: ' + data.windowId + ' tab: ' + data.tabId + ' index ' + data.index); +chromium.windows.onRemoved.addListener(function(windowId) { + appendToLog('windows.onRemoved -- window: ' + windowId); loadWindowList(); }); -chromium.tabs.onTabAttached.addListener(function(data) { - appendToLog('onTabAttached -- window: ' + data.windowId + ' tab: ' + data.tabId + ' index ' + data.index); +chromium.tabs.onCreated.addListener(function(tab) { + appendToLog('tabs.onCreated -- window: ' + tab.windowId + ' tab: ' + tab.id + ' index ' + tab.index + ' url ' + tab.url); loadWindowList(); }); -chromium.tabs.onTabMoved.addListener(function(data) { - appendToLog('onTabMoved -- window: ' + data.windowId + ' tab: ' + data.tabId + ' from ' + data.fromIndex + ' to ' + data.toIndex); +chromium.tabs.onAttached.addListener(function(tabId, props) { + appendToLog('tabs.onAttached -- window: ' + props.newWindowId + ' tab: ' + tabId + ' index ' + props.newPosition); loadWindowList(); }); -chromium.tabs.onTabDetached.addListener(function(data) { - appendToLog('onTabDetached -- window: ' + data.windowId + ' tab: ' + data.tabId + ' index ' + data.index); +chromium.tabs.onMoved.addListener(function(tabId, props) { + appendToLog('tabs.onMoved -- window: ' + props.windowId + ' tab: ' + tabId + ' from ' + props.fromIndex + ' to ' + props.toIndex); loadWindowList(); }); -chromium.tabs.onTabSelectionChanged.addListener(function(data) { - appendToLog('onTabSelectionChanged -- window: ' + data.windowId + ' tab: ' + data.tabId + ' index ' + data.index); +chromium.tabs.onDetached.addListener(function(tabId, props) { + appendToLog('tabs.onDetached -- window: ' + props.oldWindowId + ' tab: ' + tabId + ' index ' + props.oldPosition); loadWindowList(); }); -chromium.tabs.onTabRemoved.addListener(function(tabId) { - appendToLog('onTabRemoved -- tab: ' + tabId); +chromium.tabs.onSelectionChanged.addListener(function(tabId, props) { + appendToLog('tabs.onSelectionChanged -- window: ' + props.windowId + ' tab: ' + tabId); + loadWindowList(); +}); + +chromium.tabs.onRemoved.addListener(function(tabId) { + appendToLog('tabs.onRemoved -- tab: ' + tabId); loadWindowList(); }); @@ -147,15 +194,51 @@ function createWindow() { delete args.height; if (!args.url) delete args.url; + + try { + chromium.windows.createWindow(args); + } catch(e) { + alert(e); + } +} + +function refreshWindow(windowId) { + chromium.windows.get(windowId, function(window) { + chromium.tabs.getAllInWindow(window.id, function(tabList) { + window.tabs = tabList; + var input = new JsExprContext(window); + var output = document.getElementById('window_' + window.id); + jstProcess(input, output); + + appendToLog('window refreshed -- windowId: ' + window.id + ' tab count:' + window.tabs.length); + }); + }); +} - chromium.windows.createWindow(args); +function refreshTab(tabId) { + chromium.tabs.get(tabId, function(tab) { + var input = new JsExprContext(tab); + var output = document.getElementById('tab_' + tab.id); + jstProcess(input, output); + appendToLog('tab refreshed -- tabId: ' + tab.id + ' url:' + tab.url); + }); +} + +function refreshSelectedTab(windowId) { + chromium.tabs.getSelected(windowId, function(tab) { + var input = new JsExprContext(tab); + var output = document.getElementById('tab_' + tab.id); + jstProcess(input, output); + appendToLog('selected tab refreshed -- tabId: ' + tab.id + ' url:' + tab.url); + }); } </script> </head> - <body onload="loadWindowList();"> + <body onload="bootStrap();"> <div id="windowList"> - <div style="background-color: #AAEEEE; margin: 4px; padding: 8px; margin: 20px" jsselect="$this"> + <div style="background-color: #AAEEEE; margin: 4px; padding: 8px; margin: 20px" jsselect="$this" + jsvalues="id:'window_' + id"> <div style="font-style: italic; width: 80px; display: inline-block"> Window: <span jscontent="id"></span> </div> @@ -165,33 +248,39 @@ function createWindow() { width: <input style="width: 60px" type="text" jsvalues="value:$this.width;id:'width_' + id" /> height: <input style="width: 60px" type="text" jsvalues="value:$this.height;id:'height_' + id" /> <input type="checkbox" jsvalues="checked:focused; id:'focused_' + id" /> Focused + <input type="checkbox" jsvalues="checked:current; id:'current_' + id" /> Current + <button onclick="refreshWindow(this.jstdata);" jsvalues=".jstdata:id">Refresh</button> </div> <div id="tabList"> - <div style="background-color: #EEEEEE; margin: 8px; padding: 4px" jsselect="tabs"> - <div style="margin: 8px"> - <div style="font-style: italic; width: 80px; display: inline-block" jscontent="'TabId: ' + id"></div> - <div style="width: 300px; display: inline-block"> - index: <input style="width: 20px" type="text" jsvalues="value:$this.index;id:'index_' + id" /> - windowId: <input style="width: 20px" type="text" jsvalues="value:windowId;id:'windowId_' + id" /> - <button onclick="moveTab(this.jstdata);" jsvalues=".jstdata:id">Move</button> - </div> - </div> - <div style="margin: 8px"> - <div> - <div style="width: 40px; display:inline-block">title:</div> - <input style="width: 90%" type="text" jsvalues="value:title;id:'title_' + id" /> + <div jsselect="tabs"> + <div style="background-color: #EEEEEE; margin: 8px; padding: 4px" jsvalues="id:'tab_' + id"> + <div style="margin: 8px"> + <div style="font-style: italic; width: 80px; display: inline-block" jscontent="'TabId: ' + id"></div> + <div style="width: 300px; display: inline-block"> + index: <input style="width: 20px" type="text" jsvalues="value:$this.index;id:'index_' + id" /> + windowId: <input style="width: 20px" type="text" jsvalues="value:windowId;id:'windowId_' + id" /> + <button onclick="moveTab(this.jstdata);" jsvalues=".jstdata:id">Move</button> + <button onclick="refreshTab(this.jstdata);" jsvalues=".jstdata:id">Refresh</button> + </div> </div> - <div> - <div style="width: 40px; display:inline-block">url:</div> - <input style="width: 90%" type="text" jsvalues="value:url;id:'url_' + id" /> + <div style="margin: 8px"> + <div> + <div style="width: 40px; display:inline-block">title:</div> + <input style="width: 90%" type="text" jsvalues="value:title;id:'title_' + id" /> + </div> + <div> + <div style="width: 40px; display:inline-block">url:</div> + <input style="width: 90%" type="text" jsvalues="value:url;id:'url_' + id" /> + </div> + <div><input type="checkbox" jsvalues="checked:selected; id:'selected_' + id" /> Selected</div> </div> - <div><input type="checkbox" jsvalues="checked:selected; id:'selected_' + id" /> Selected</div> + <button onclick="updateTab(this.jstdata)" jsvalues=".jstdata:id">Update Tab</button> + <button onclick="chromium.tabs.remove(this.jstdata);" jsvalues=".jstdata:id">Close Tab</button> </div> - <button onclick="updateTab(this.jstdata)" jsvalues=".jstdata:id">Update Tab</button> - <button onclick="chromium.tabs.removeTab(this.jstdata);" jsvalues=".jstdata:id">Close Tab</button> </div> </div> <button onclick="chromium.windows.removeWindow(this.jstdata);" jsvalues=".jstdata:id">Close Window</button> + <button onclick="refreshSelectedTab(this.jstdata);" jsvalues=".jstdata:id">Refresh Selected Tab</button> </div> </div> <div style="background-color: #EEEEBB; margin: 20px; padding: 8px"> |