Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / applescript / tab_applescript.mm
blob8c70436851f66f15ece85e1a063f3f57b995cb43
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "chrome/browser/ui/cocoa/applescript/tab_applescript.h"
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "base/logging.h"
10 #import "base/mac/scoped_nsobject.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "chrome/browser/printing/print_view_manager.h"
13 #include "chrome/browser/sessions/session_tab_helper.h"
14 #include "chrome/browser/ui/cocoa/applescript/apple_event_util.h"
15 #include "chrome/browser/ui/cocoa/applescript/error_applescript.h"
16 #include "chrome/browser/ui/cocoa/applescript/metrics_applescript.h"
17 #include "chrome/common/chrome_isolated_world_ids.h"
18 #include "chrome/common/url_constants.h"
19 #include "components/sessions/session_id.h"
20 #include "content/public/browser/navigation_controller.h"
21 #include "content/public/browser/navigation_entry.h"
22 #include "content/public/browser/render_frame_host.h"
23 #include "content/public/browser/render_view_host.h"
24 #include "content/public/browser/save_page_type.h"
25 #include "content/public/browser/web_contents.h"
26 #include "content/public/browser/web_contents_delegate.h"
27 #include "url/gurl.h"
29 using content::NavigationController;
30 using content::NavigationEntry;
31 using content::OpenURLParams;
32 using content::RenderFrameHost;
33 using content::RenderViewHost;
34 using content::Referrer;
35 using content::WebContents;
37 namespace {
39 void ResumeAppleEventAndSendReply(NSAppleEventManagerSuspensionID suspension_id,
40                                   const base::Value* result_value) {
41   NSAppleEventDescriptor* result_descriptor =
42       chrome::mac::ValueToAppleEventDescriptor(result_value);
44   NSAppleEventManager* manager = [NSAppleEventManager sharedAppleEventManager];
45   NSAppleEventDescriptor* reply_event =
46       [manager replyAppleEventForSuspensionID:suspension_id];
47   [reply_event setParamDescriptor:result_descriptor
48                        forKeyword:keyDirectObject];
49   [manager resumeWithSuspensionID:suspension_id];
52 }  // namespace
54 @interface TabAppleScript()
55 @property (nonatomic, copy) NSString* tempURL;
56 @end
58 @implementation TabAppleScript
60 @synthesize tempURL = tempURL_;
62 - (id)init {
63   if ((self = [super init])) {
64     SessionID session;
65     SessionID::id_type futureSessionIDOfTab = session.id() + 1;
66     // Holds the SessionID that the new tab is going to get.
67     base::scoped_nsobject<NSNumber> numID(
68         [[NSNumber alloc] initWithInt:futureSessionIDOfTab]);
69     [self setUniqueID:numID];
70   }
71   return self;
74 - (void)dealloc {
75   [tempURL_ release];
76   [super dealloc];
79 - (id)initWithWebContents:(content::WebContents*)webContents {
80   if (!webContents) {
81     [self release];
82     return nil;
83   }
85   if ((self = [super init])) {
86     // It is safe to be weak; if a tab goes away (e.g. the user closes a tab)
87     // the AppleScript runtime calls tabs in AppleScriptWindow and this
88     // particular tab is never returned.
89     webContents_ = webContents;
90     SessionTabHelper* session_tab_helper =
91         SessionTabHelper::FromWebContents(webContents);
92     base::scoped_nsobject<NSNumber> numID(
93         [[NSNumber alloc] initWithInt:session_tab_helper->session_id().id()]);
94     [self setUniqueID:numID];
95   }
96   return self;
99 - (void)setWebContents:(content::WebContents*)webContents {
100   DCHECK(webContents);
101   // It is safe to be weak; if a tab goes away (e.g. the user closes a tab)
102   // the AppleScript runtime calls tabs in AppleScriptWindow and this
103   // particular tab is never returned.
104   webContents_ = webContents;
105   SessionTabHelper* session_tab_helper =
106       SessionTabHelper::FromWebContents(webContents);
107   base::scoped_nsobject<NSNumber> numID(
108       [[NSNumber alloc] initWithInt:session_tab_helper->session_id().id()]);
109   [self setUniqueID:numID];
111   if ([self tempURL])
112     [self setURL:[self tempURL]];
115 - (NSString*)URL {
116   if (!webContents_) {
117     return nil;
118   }
120   NavigationEntry* entry = webContents_->GetController().GetActiveEntry();
121   if (!entry) {
122     return nil;
123   }
124   const GURL& url = entry->GetVirtualURL();
125   return base::SysUTF8ToNSString(url.spec());
128 - (void)setURL:(NSString*)aURL {
129   // If a scripter sets a URL before the node is added save it at a temporary
130   // location.
131   if (!webContents_) {
132     [self setTempURL:aURL];
133     return;
134   }
136   GURL url(base::SysNSStringToUTF8(aURL));
137   // check for valid url.
138   if (!url.is_empty() && !url.is_valid()) {
139     AppleScript::SetError(AppleScript::errInvalidURL);
140     return;
141   }
143   NavigationEntry* entry = webContents_->GetController().GetActiveEntry();
144   if (!entry)
145     return;
147   const GURL& previousURL = entry->GetVirtualURL();
148   webContents_->OpenURL(OpenURLParams(
149       url,
150       content::Referrer(previousURL, blink::WebReferrerPolicyDefault),
151       CURRENT_TAB,
152       ui::PAGE_TRANSITION_TYPED,
153       false));
156 - (NSString*)title {
157   NavigationEntry* entry = webContents_->GetController().GetActiveEntry();
158   if (!entry)
159     return nil;
161   base::string16 title = entry ? entry->GetTitle() : base::string16();
162   return base::SysUTF16ToNSString(title);
165 - (NSNumber*)loading {
166   BOOL loadingValue = webContents_->IsLoading() ? YES : NO;
167   return [NSNumber numberWithBool:loadingValue];
170 - (void)handlesUndoScriptCommand:(NSScriptCommand*)command {
171   AppleScript::LogAppleScriptUMA(AppleScript::AppleScriptCommand::TAB_UNDO);
172   webContents_->Undo();
175 - (void)handlesRedoScriptCommand:(NSScriptCommand*)command {
176   AppleScript::LogAppleScriptUMA(AppleScript::AppleScriptCommand::TAB_REDO);
177   webContents_->Redo();
180 - (void)handlesCutScriptCommand:(NSScriptCommand*)command {
181   AppleScript::LogAppleScriptUMA(AppleScript::AppleScriptCommand::TAB_CUT);
182   webContents_->Cut();
185 - (void)handlesCopyScriptCommand:(NSScriptCommand*)command {
186   AppleScript::LogAppleScriptUMA(AppleScript::AppleScriptCommand::TAB_COPY);
187   webContents_->Copy();
190 - (void)handlesPasteScriptCommand:(NSScriptCommand*)command {
191   AppleScript::LogAppleScriptUMA(AppleScript::AppleScriptCommand::TAB_PASTE);
192   webContents_->Paste();
195 - (void)handlesSelectAllScriptCommand:(NSScriptCommand*)command {
196   AppleScript::LogAppleScriptUMA(
197       AppleScript::AppleScriptCommand::TAB_SELECT_ALL);
198   webContents_->SelectAll();
201 - (void)handlesGoBackScriptCommand:(NSScriptCommand*)command {
202   AppleScript::LogAppleScriptUMA(AppleScript::AppleScriptCommand::TAB_GO_BACK);
203   NavigationController& navigationController = webContents_->GetController();
204   if (navigationController.CanGoBack())
205     navigationController.GoBack();
208 - (void)handlesGoForwardScriptCommand:(NSScriptCommand*)command {
209   AppleScript::LogAppleScriptUMA(
210       AppleScript::AppleScriptCommand::TAB_GO_FORWARD);
211   NavigationController& navigationController = webContents_->GetController();
212   if (navigationController.CanGoForward())
213     navigationController.GoForward();
216 - (void)handlesReloadScriptCommand:(NSScriptCommand*)command {
217   AppleScript::LogAppleScriptUMA(AppleScript::AppleScriptCommand::TAB_RELOAD);
218   NavigationController& navigationController = webContents_->GetController();
219   const bool checkForRepost = true;
220   navigationController.Reload(checkForRepost);
223 - (void)handlesStopScriptCommand:(NSScriptCommand*)command {
224   AppleScript::LogAppleScriptUMA(AppleScript::AppleScriptCommand::TAB_STOP);
225   webContents_->Stop();
228 - (void)handlesPrintScriptCommand:(NSScriptCommand*)command {
229   AppleScript::LogAppleScriptUMA(AppleScript::AppleScriptCommand::TAB_PRINT);
230   bool initiated =
231       printing::PrintViewManager::FromWebContents(webContents_)->PrintNow();
232   if (!initiated) {
233     AppleScript::SetError(AppleScript::errInitiatePrinting);
234   }
237 - (void)handlesSaveScriptCommand:(NSScriptCommand*)command {
238   AppleScript::LogAppleScriptUMA(AppleScript::AppleScriptCommand::TAB_SAVE);
239   NSDictionary* dictionary = [command evaluatedArguments];
241   NSURL* fileURL = [dictionary objectForKey:@"File"];
242   // Scripter has not specifed the location at which to save, so we prompt for
243   // it.
244   if (!fileURL) {
245     webContents_->OnSavePage();
246     return;
247   }
249   base::FilePath mainFile(base::SysNSStringToUTF8([fileURL path]));
250   // We create a directory path at the folder within which the file exists.
251   // Eg.    if main_file = '/Users/Foo/Documents/Google.html'
252   // then directory_path = '/Users/Foo/Documents/Google_files/'.
253   base::FilePath directoryPath = mainFile.RemoveExtension();
254   directoryPath = directoryPath.InsertBeforeExtension(std::string("_files/"));
256   NSString* saveType = [dictionary objectForKey:@"FileType"];
258   content::SavePageType savePageType = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
259   if (saveType) {
260     if ([saveType isEqualToString:@"only html"]) {
261       savePageType = content::SAVE_PAGE_TYPE_AS_ONLY_HTML;
262     } else if ([saveType isEqualToString:@"complete html"]) {
263       savePageType = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
264     } else {
265       AppleScript::SetError(AppleScript::errInvalidSaveType);
266       return;
267     }
268   }
270   webContents_->SavePage(mainFile, directoryPath, savePageType);
273 - (void)handlesCloseScriptCommand:(NSScriptCommand*)command {
274   AppleScript::LogAppleScriptUMA(AppleScript::AppleScriptCommand::TAB_CLOSE);
275   webContents_->GetDelegate()->CloseContents(webContents_);
278 - (void)handlesViewSourceScriptCommand:(NSScriptCommand*)command {
279   AppleScript::LogAppleScriptUMA(
280       AppleScript::AppleScriptCommand::TAB_VIEW_SOURCE);
281   NavigationEntry* entry =
282       webContents_->GetController().GetLastCommittedEntry();
283   if (entry) {
284     webContents_->OpenURL(
285         OpenURLParams(GURL(content::kViewSourceScheme + std::string(":") +
286                            entry->GetURL().spec()),
287                       Referrer(),
288                       NEW_FOREGROUND_TAB,
289                       ui::PAGE_TRANSITION_LINK,
290                       false));
291   }
294 - (id)handlesExecuteJavascriptScriptCommand:(NSScriptCommand*)command {
295   AppleScript::LogAppleScriptUMA(
296       AppleScript::AppleScriptCommand::TAB_EXECUTE_JAVASCRIPT);
297   content::RenderFrameHost* frame = webContents_->GetMainFrame();
298   if (!frame) {
299     NOTREACHED();
300     return nil;
301   }
303   NSAppleEventManager* manager = [NSAppleEventManager sharedAppleEventManager];
304   NSAppleEventManagerSuspensionID suspensionID =
305       [manager suspendCurrentAppleEvent];
306   content::RenderFrameHost::JavaScriptResultCallback callback =
307       base::Bind(&ResumeAppleEventAndSendReply, suspensionID);
309   base::string16 script = base::SysNSStringToUTF16(
310       [[command evaluatedArguments] objectForKey:@"javascript"]);
311   frame->ExecuteJavaScriptInIsolatedWorld(
312       script, callback, chrome::ISOLATED_WORLD_ID_APPLESCRIPT);
314   return nil;
317 @end