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_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/common/url_constants.h"
17 #include "components/sessions/session_id.h"
18 #include "content/public/browser/navigation_controller.h"
19 #include "content/public/browser/navigation_entry.h"
20 #include "content/public/browser/render_frame_host.h"
21 #include "content/public/browser/render_view_host.h"
22 #include "content/public/browser/save_page_type.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/browser/web_contents_delegate.h"
27 using content::NavigationController;
28 using content::NavigationEntry;
29 using content::OpenURLParams;
30 using content::RenderFrameHost;
31 using content::RenderViewHost;
32 using content::Referrer;
33 using content::WebContents;
37 void ResumeAppleEventAndSendReply(NSAppleEventManagerSuspensionID suspension_id,
38 const base::Value* result_value) {
39 NSAppleEventDescriptor* result_descriptor =
40 chrome::mac::ValueToAppleEventDescriptor(result_value);
42 NSAppleEventManager* manager = [NSAppleEventManager sharedAppleEventManager];
43 NSAppleEventDescriptor* reply_event =
44 [manager replyAppleEventForSuspensionID:suspension_id];
45 [reply_event setParamDescriptor:result_descriptor
46 forKeyword:keyDirectObject];
47 [manager resumeWithSuspensionID:suspension_id];
52 @interface TabAppleScript()
53 @property (nonatomic, copy) NSString* tempURL;
56 @implementation TabAppleScript
58 @synthesize tempURL = tempURL_;
61 if ((self = [super init])) {
63 SessionID::id_type futureSessionIDOfTab = session.id() + 1;
64 // Holds the SessionID that the new tab is going to get.
65 base::scoped_nsobject<NSNumber> numID(
66 [[NSNumber alloc] initWithInt:futureSessionIDOfTab]);
67 [self setUniqueID:numID];
77 - (id)initWithWebContents:(content::WebContents*)webContents {
83 if ((self = [super init])) {
84 // It is safe to be weak; if a tab goes away (e.g. the user closes a tab)
85 // the AppleScript runtime calls tabs in AppleScriptWindow and this
86 // particular tab is never returned.
87 webContents_ = webContents;
88 SessionTabHelper* session_tab_helper =
89 SessionTabHelper::FromWebContents(webContents);
90 base::scoped_nsobject<NSNumber> numID(
91 [[NSNumber alloc] initWithInt:session_tab_helper->session_id().id()]);
92 [self setUniqueID:numID];
97 - (void)setWebContents:(content::WebContents*)webContents {
99 // It is safe to be weak; if a tab goes away (e.g. the user closes a tab)
100 // the AppleScript runtime calls tabs in AppleScriptWindow and this
101 // particular tab is never returned.
102 webContents_ = webContents;
103 SessionTabHelper* session_tab_helper =
104 SessionTabHelper::FromWebContents(webContents);
105 base::scoped_nsobject<NSNumber> numID(
106 [[NSNumber alloc] initWithInt:session_tab_helper->session_id().id()]);
107 [self setUniqueID:numID];
110 [self setURL:[self tempURL]];
118 NavigationEntry* entry = webContents_->GetController().GetActiveEntry();
122 const GURL& url = entry->GetVirtualURL();
123 return base::SysUTF8ToNSString(url.spec());
126 - (void)setURL:(NSString*)aURL {
127 // If a scripter sets a URL before the node is added save it at a temporary
130 [self setTempURL:aURL];
134 GURL url(base::SysNSStringToUTF8(aURL));
135 // check for valid url.
136 if (!url.is_empty() && !url.is_valid()) {
137 AppleScript::SetError(AppleScript::errInvalidURL);
141 NavigationEntry* entry = webContents_->GetController().GetActiveEntry();
145 const GURL& previousURL = entry->GetVirtualURL();
146 webContents_->OpenURL(OpenURLParams(
148 content::Referrer(previousURL, blink::WebReferrerPolicyDefault),
150 ui::PAGE_TRANSITION_TYPED,
155 NavigationEntry* entry = webContents_->GetController().GetActiveEntry();
159 base::string16 title = entry ? entry->GetTitle() : base::string16();
160 return base::SysUTF16ToNSString(title);
163 - (NSNumber*)loading {
164 BOOL loadingValue = webContents_->IsLoading() ? YES : NO;
165 return [NSNumber numberWithBool:loadingValue];
168 - (void)handlesUndoScriptCommand:(NSScriptCommand*)command {
169 webContents_->Undo();
172 - (void)handlesRedoScriptCommand:(NSScriptCommand*)command {
173 webContents_->Redo();
176 - (void)handlesCutScriptCommand:(NSScriptCommand*)command {
180 - (void)handlesCopyScriptCommand:(NSScriptCommand*)command {
181 webContents_->Copy();
184 - (void)handlesPasteScriptCommand:(NSScriptCommand*)command {
185 webContents_->Paste();
188 - (void)handlesSelectAllScriptCommand:(NSScriptCommand*)command {
189 webContents_->SelectAll();
192 - (void)handlesGoBackScriptCommand:(NSScriptCommand*)command {
193 NavigationController& navigationController = webContents_->GetController();
194 if (navigationController.CanGoBack())
195 navigationController.GoBack();
198 - (void)handlesGoForwardScriptCommand:(NSScriptCommand*)command {
199 NavigationController& navigationController = webContents_->GetController();
200 if (navigationController.CanGoForward())
201 navigationController.GoForward();
204 - (void)handlesReloadScriptCommand:(NSScriptCommand*)command {
205 NavigationController& navigationController = webContents_->GetController();
206 const bool checkForRepost = true;
207 navigationController.Reload(checkForRepost);
210 - (void)handlesStopScriptCommand:(NSScriptCommand*)command {
211 webContents_->Stop();
214 - (void)handlesPrintScriptCommand:(NSScriptCommand*)command {
216 printing::PrintViewManager::FromWebContents(webContents_)->PrintNow();
218 AppleScript::SetError(AppleScript::errInitiatePrinting);
222 - (void)handlesSaveScriptCommand:(NSScriptCommand*)command {
223 NSDictionary* dictionary = [command evaluatedArguments];
225 NSURL* fileURL = [dictionary objectForKey:@"File"];
226 // Scripter has not specifed the location at which to save, so we prompt for
229 webContents_->OnSavePage();
233 base::FilePath mainFile(base::SysNSStringToUTF8([fileURL path]));
234 // We create a directory path at the folder within which the file exists.
235 // Eg. if main_file = '/Users/Foo/Documents/Google.html'
236 // then directory_path = '/Users/Foo/Documents/Google_files/'.
237 base::FilePath directoryPath = mainFile.RemoveExtension();
238 directoryPath = directoryPath.InsertBeforeExtension(std::string("_files/"));
240 NSString* saveType = [dictionary objectForKey:@"FileType"];
242 content::SavePageType savePageType = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
244 if ([saveType isEqualToString:@"only html"]) {
245 savePageType = content::SAVE_PAGE_TYPE_AS_ONLY_HTML;
246 } else if ([saveType isEqualToString:@"complete html"]) {
247 savePageType = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
249 AppleScript::SetError(AppleScript::errInvalidSaveType);
254 webContents_->SavePage(mainFile, directoryPath, savePageType);
257 - (void)handlesCloseScriptCommand:(NSScriptCommand*)command {
258 webContents_->GetDelegate()->CloseContents(webContents_);
261 - (void)handlesViewSourceScriptCommand:(NSScriptCommand*)command {
262 NavigationEntry* entry =
263 webContents_->GetController().GetLastCommittedEntry();
265 webContents_->OpenURL(
266 OpenURLParams(GURL(content::kViewSourceScheme + std::string(":") +
267 entry->GetURL().spec()),
270 ui::PAGE_TRANSITION_LINK,
275 - (id)handlesExecuteJavascriptScriptCommand:(NSScriptCommand*)command {
276 content::RenderFrameHost* frame = webContents_->GetMainFrame();
282 NSAppleEventManager* manager = [NSAppleEventManager sharedAppleEventManager];
283 NSAppleEventManagerSuspensionID suspensionID =
284 [manager suspendCurrentAppleEvent];
285 content::RenderFrameHost::JavaScriptResultCallback callback =
286 base::Bind(&ResumeAppleEventAndSendReply, suspensionID);
288 base::string16 script = base::SysNSStringToUTF16(
289 [[command evaluatedArguments] objectForKey:@"javascript"]);
290 frame->ExecuteJavaScript(script, callback);