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"
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_id.h"
14 #include "chrome/browser/sessions/session_tab_helper.h"
15 #include "chrome/browser/ui/cocoa/applescript/apple_event_util.h"
16 #include "chrome/browser/ui/cocoa/applescript/error_applescript.h"
17 #include "chrome/common/url_constants.h"
18 #include "content/public/browser/navigation_controller.h"
19 #include "content/public/browser/navigation_entry.h"
20 #include "content/public/browser/render_view_host.h"
21 #include "content/public/browser/save_page_type.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/browser/web_contents_delegate.h"
26 using content::NavigationController;
27 using content::NavigationEntry;
28 using content::OpenURLParams;
29 using content::RenderViewHost;
30 using content::Referrer;
31 using content::WebContents;
35 void ResumeAppleEventAndSendReply(NSAppleEventManagerSuspensionID suspension_id,
36 const base::Value* result_value) {
37 NSAppleEventDescriptor* result_descriptor =
38 chrome::mac::ValueToAppleEventDescriptor(result_value);
40 NSAppleEventManager* manager = [NSAppleEventManager sharedAppleEventManager];
41 NSAppleEventDescriptor* reply_event =
42 [manager replyAppleEventForSuspensionID:suspension_id];
43 [reply_event setParamDescriptor:result_descriptor
44 forKeyword:keyDirectObject];
45 [manager resumeWithSuspensionID:suspension_id];
50 @interface TabAppleScript()
51 @property (nonatomic, copy) NSString* tempURL;
54 @implementation TabAppleScript
56 @synthesize tempURL = tempURL_;
59 if ((self = [super init])) {
61 SessionID::id_type futureSessionIDOfTab = session.id() + 1;
62 // Holds the SessionID that the new tab is going to get.
63 base::scoped_nsobject<NSNumber> numID(
64 [[NSNumber alloc] initWithInt:futureSessionIDOfTab]);
65 [self setUniqueID:numID];
75 - (id)initWithWebContents:(content::WebContents*)webContents {
81 if ((self = [super init])) {
82 // It is safe to be weak; if a tab goes away (e.g. the user closes a tab)
83 // the AppleScript runtime calls tabs in AppleScriptWindow and this
84 // particular tab is never returned.
85 webContents_ = webContents;
86 SessionTabHelper* session_tab_helper =
87 SessionTabHelper::FromWebContents(webContents);
88 base::scoped_nsobject<NSNumber> numID(
89 [[NSNumber alloc] initWithInt:session_tab_helper->session_id().id()]);
90 [self setUniqueID:numID];
95 - (void)setWebContents:(content::WebContents*)webContents {
97 // It is safe to be weak; if a tab goes away (e.g. the user closes a tab)
98 // the AppleScript runtime calls tabs in AppleScriptWindow and this
99 // particular tab is never returned.
100 webContents_ = webContents;
101 SessionTabHelper* session_tab_helper =
102 SessionTabHelper::FromWebContents(webContents);
103 base::scoped_nsobject<NSNumber> numID(
104 [[NSNumber alloc] initWithInt:session_tab_helper->session_id().id()]);
105 [self setUniqueID:numID];
108 [self setURL:[self tempURL]];
116 NavigationEntry* entry = webContents_->GetController().GetActiveEntry();
120 const GURL& url = entry->GetVirtualURL();
121 return base::SysUTF8ToNSString(url.spec());
124 - (void)setURL:(NSString*)aURL {
125 // If a scripter sets a URL before the node is added save it at a temporary
128 [self setTempURL:aURL];
132 GURL url(base::SysNSStringToUTF8(aURL));
133 // check for valid url.
134 if (!url.is_empty() && !url.is_valid()) {
135 AppleScript::SetError(AppleScript::errInvalidURL);
139 NavigationEntry* entry = webContents_->GetController().GetActiveEntry();
143 const GURL& previousURL = entry->GetVirtualURL();
144 webContents_->OpenURL(OpenURLParams(
146 content::Referrer(previousURL, blink::WebReferrerPolicyDefault),
148 content::PAGE_TRANSITION_TYPED,
153 NavigationEntry* entry = webContents_->GetController().GetActiveEntry();
157 base::string16 title = entry ? entry->GetTitle() : base::string16();
158 return base::SysUTF16ToNSString(title);
161 - (NSNumber*)loading {
162 BOOL loadingValue = webContents_->IsLoading() ? YES : NO;
163 return [NSNumber numberWithBool:loadingValue];
166 - (void)handlesUndoScriptCommand:(NSScriptCommand*)command {
167 RenderViewHost* view = webContents_->GetRenderViewHost();
176 - (void)handlesRedoScriptCommand:(NSScriptCommand*)command {
177 RenderViewHost* view = webContents_->GetRenderViewHost();
186 - (void)handlesCutScriptCommand:(NSScriptCommand*)command {
187 RenderViewHost* view = webContents_->GetRenderViewHost();
196 - (void)handlesCopyScriptCommand:(NSScriptCommand*)command {
197 RenderViewHost* view = webContents_->GetRenderViewHost();
206 - (void)handlesPasteScriptCommand:(NSScriptCommand*)command {
207 RenderViewHost* view = webContents_->GetRenderViewHost();
216 - (void)handlesSelectAllScriptCommand:(NSScriptCommand*)command {
217 RenderViewHost* view = webContents_->GetRenderViewHost();
226 - (void)handlesGoBackScriptCommand:(NSScriptCommand*)command {
227 NavigationController& navigationController = webContents_->GetController();
228 if (navigationController.CanGoBack())
229 navigationController.GoBack();
232 - (void)handlesGoForwardScriptCommand:(NSScriptCommand*)command {
233 NavigationController& navigationController = webContents_->GetController();
234 if (navigationController.CanGoForward())
235 navigationController.GoForward();
238 - (void)handlesReloadScriptCommand:(NSScriptCommand*)command {
239 NavigationController& navigationController = webContents_->GetController();
240 const bool checkForRepost = true;
241 navigationController.Reload(checkForRepost);
244 - (void)handlesStopScriptCommand:(NSScriptCommand*)command {
245 RenderViewHost* view = webContents_->GetRenderViewHost();
247 // We tolerate Stop being called even before a view has been created.
248 // So just log a warning instead of a NOTREACHED().
249 DLOG(WARNING) << "Stop: no view for handle ";
256 - (void)handlesPrintScriptCommand:(NSScriptCommand*)command {
258 printing::PrintViewManager::FromWebContents(webContents_)->PrintNow();
260 AppleScript::SetError(AppleScript::errInitiatePrinting);
264 - (void)handlesSaveScriptCommand:(NSScriptCommand*)command {
265 NSDictionary* dictionary = [command evaluatedArguments];
267 NSURL* fileURL = [dictionary objectForKey:@"File"];
268 // Scripter has not specifed the location at which to save, so we prompt for
271 webContents_->OnSavePage();
275 base::FilePath mainFile(base::SysNSStringToUTF8([fileURL path]));
276 // We create a directory path at the folder within which the file exists.
277 // Eg. if main_file = '/Users/Foo/Documents/Google.html'
278 // then directory_path = '/Users/Foo/Documents/Google_files/'.
279 base::FilePath directoryPath = mainFile.RemoveExtension();
280 directoryPath = directoryPath.InsertBeforeExtension(std::string("_files/"));
282 NSString* saveType = [dictionary objectForKey:@"FileType"];
284 content::SavePageType savePageType = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
286 if ([saveType isEqualToString:@"only html"]) {
287 savePageType = content::SAVE_PAGE_TYPE_AS_ONLY_HTML;
288 } else if ([saveType isEqualToString:@"complete html"]) {
289 savePageType = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
291 AppleScript::SetError(AppleScript::errInvalidSaveType);
296 webContents_->SavePage(mainFile, directoryPath, savePageType);
299 - (void)handlesCloseScriptCommand:(NSScriptCommand*)command {
300 webContents_->GetDelegate()->CloseContents(webContents_);
303 - (void)handlesViewSourceScriptCommand:(NSScriptCommand*)command {
304 NavigationEntry* entry =
305 webContents_->GetController().GetLastCommittedEntry();
307 webContents_->OpenURL(
308 OpenURLParams(GURL(content::kViewSourceScheme + std::string(":") +
309 entry->GetURL().spec()),
312 content::PAGE_TRANSITION_LINK,
317 - (id)handlesExecuteJavascriptScriptCommand:(NSScriptCommand*)command {
318 RenderViewHost* view = webContents_->GetRenderViewHost();
324 NSAppleEventManager* manager = [NSAppleEventManager sharedAppleEventManager];
325 NSAppleEventManagerSuspensionID suspensionID =
326 [manager suspendCurrentAppleEvent];
327 content::RenderViewHost::JavascriptResultCallback callback =
328 base::Bind(&ResumeAppleEventAndSendReply, suspensionID);
330 base::string16 script = base::SysNSStringToUTF16(
331 [[command evaluatedArguments] objectForKey:@"javascript"]);
332 view->ExecuteJavascriptInWebFrameCallbackResult(
333 base::string16(), // frame_xpath