├── Scriptinator
├── en.lproj
│ ├── InfoPlist.strings
│ └── Credits.rtf
├── Automation.scpt
├── Scriptinator-Prefix.pch
├── main.m
├── AppDelegate.h
├── Scriptinator.entitlements
├── Images.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Scriptinator-Info.plist
├── AppDelegate.m
└── Base.lproj
│ └── MainMenu.xib
├── ScriptinatorTests
├── en.lproj
│ └── InfoPlist.strings
├── ScriptinatorTests-Info.plist
└── ScriptinatorTests.m
├── Scriptinator.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── craig.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── project.pbxproj
└── README.md
/Scriptinator/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/ScriptinatorTests/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/Scriptinator/Automation.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-14-sandbox-scripting/HEAD/Scriptinator/Automation.scpt
--------------------------------------------------------------------------------
/Scriptinator.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Scriptinator/Scriptinator-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header
3 | //
4 | // The contents of this file are implicitly included at the beginning of every source file.
5 | //
6 |
7 | #ifdef __OBJC__
8 | #import
9 | #endif
10 |
--------------------------------------------------------------------------------
/Scriptinator.xcodeproj/project.xcworkspace/xcuserdata/craig.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-14-sandbox-scripting/HEAD/Scriptinator.xcodeproj/project.xcworkspace/xcuserdata/craig.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/Scriptinator/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // Scriptinator
4 | //
5 | // Created by Craig Hockenberry on 6/21/14.
6 | // Copyright (c) 2014 Craig Hockenberry. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | int main(int argc, const char * argv[])
12 | {
13 | return NSApplicationMain(argc, argv);
14 | }
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Scriptinator
2 | ============
3 |
4 | This is the sample app that I wrote to accompany the article I did for [Issue 14](http://www.objc.io/issue-14) of [objc.io](http://www.objc.io).
5 |
6 | Please refer to _[Scripting from a Sandbox](http://www.objc.io/issue-14/sandbox-scripting.html)_ for more information on how to use this code in your own projects.
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Scriptinator/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // Scriptinator
4 | //
5 | // Created by Craig Hockenberry on 6/21/14.
6 | // Copyright (c) 2014 Craig Hockenberry. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : NSObject
12 |
13 | @property (assign) IBOutlet NSWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Scriptinator/Scriptinator.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-write
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Scriptinator/en.lproj/Credits.rtf:
--------------------------------------------------------------------------------
1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;}
2 | {\colortbl;\red255\green255\blue255;}
3 | \paperw9840\paperh8400
4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
5 |
6 | \f0\b\fs24 \cf0 Engineering:
7 | \b0 \
8 | Some people\
9 | \
10 |
11 | \b Human Interface Design:
12 | \b0 \
13 | Some other people\
14 | \
15 |
16 | \b Testing:
17 | \b0 \
18 | Hopefully not nobody\
19 | \
20 |
21 | \b Documentation:
22 | \b0 \
23 | Whoever\
24 | \
25 |
26 | \b With special thanks to:
27 | \b0 \
28 | Mom\
29 | }
30 |
--------------------------------------------------------------------------------
/ScriptinatorTests/ScriptinatorTests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | com.iconfactory.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ScriptinatorTests/ScriptinatorTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // ScriptinatorTests.m
3 | // ScriptinatorTests
4 | //
5 | // Created by Craig Hockenberry on 6/21/14.
6 | // Copyright (c) 2014 Craig Hockenberry. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ScriptinatorTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation ScriptinatorTests
16 |
17 | - (void)setUp
18 | {
19 | [super setUp];
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 | }
22 |
23 | - (void)tearDown
24 | {
25 | // Put teardown code here. This method is called after the invocation of each test method in the class.
26 | [super tearDown];
27 | }
28 |
29 | - (void)testExample
30 | {
31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
32 | }
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/Scriptinator/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "size" : "16x16",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "size" : "16x16",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "size" : "32x32",
16 | "scale" : "1x"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "size" : "32x32",
21 | "scale" : "2x"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "size" : "128x128",
26 | "scale" : "1x"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "size" : "128x128",
31 | "scale" : "2x"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "size" : "256x256",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "size" : "256x256",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "size" : "512x512",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "size" : "512x512",
51 | "scale" : "2x"
52 | }
53 | ],
54 | "info" : {
55 | "version" : 1,
56 | "author" : "xcode"
57 | }
58 | }
--------------------------------------------------------------------------------
/Scriptinator/Scriptinator-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | com.iconfactory.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSMinimumSystemVersion
26 | ${MACOSX_DEPLOYMENT_TARGET}
27 | NSHumanReadableCopyright
28 | Copyright © 2014 Craig Hockenberry. All rights reserved.
29 | NSMainNibFile
30 | MainMenu
31 | NSPrincipalClass
32 | NSApplication
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Scriptinator/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // Scriptinator
4 | //
5 | // Created by Craig Hockenberry on 6/21/14.
6 | // Copyright (c) 2014 Craig Hockenberry. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | #import // for AppleScript definitions
12 |
13 | @interface AppDelegate ()
14 |
15 | @property (nonatomic) IBOutlet NSTextField *chockifyInputTextField;
16 | @property (nonatomic) IBOutlet NSTextField *chockifyOutputTextField;
17 |
18 | @property (nonatomic) IBOutlet NSTextField *URLOutputTextField;
19 | @property (nonatomic) IBOutlet NSTextField *URLInputTextField;
20 | @property (nonatomic) IBOutlet NSTextView *HTMLTextView;
21 |
22 | @property (nonatomic, strong) dispatch_semaphore_t appleScriptTaskSemaphore;
23 |
24 | @end
25 |
26 | @implementation AppDelegate
27 |
28 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
29 | {
30 | // this semaphore is used by -openNetworkPreferences to ensure synchronous execution of the script
31 | self.appleScriptTaskSemaphore = dispatch_semaphore_create(1);
32 | }
33 |
34 | - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)application
35 | {
36 | return YES;
37 | }
38 |
39 |
40 | #pragma mark - Scripting
41 |
42 | - (NSAppleEventDescriptor *)chockifyEventDescriptorWithString:(NSString *)inputString
43 | {
44 | // parameter
45 | NSAppleEventDescriptor *parameter = [NSAppleEventDescriptor descriptorWithString:inputString];
46 | NSAppleEventDescriptor *parameters = [NSAppleEventDescriptor listDescriptor];
47 | [parameters insertDescriptor:parameter atIndex:1]; // you have to love a language with indices that start at 1 instead of 0
48 |
49 | // target
50 | ProcessSerialNumber psn = {0, kCurrentProcess};
51 | NSAppleEventDescriptor *target = [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber bytes:&psn length:sizeof(ProcessSerialNumber)];
52 |
53 | // function
54 | NSAppleEventDescriptor *function = [NSAppleEventDescriptor descriptorWithString:@"chockify"];
55 |
56 | // event
57 | NSAppleEventDescriptor *event = [NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite eventID:kASSubroutineEvent targetDescriptor:target returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID];
58 | [event setParamDescriptor:function forKeyword:keyASSubroutineName];
59 | [event setParamDescriptor:parameters forKeyword:keyDirectObject];
60 |
61 | return event;
62 | }
63 |
64 | - (NSAppleEventDescriptor *)safariURLEventDescriptor
65 | {
66 | // target
67 | ProcessSerialNumber psn = {0, kCurrentProcess};
68 | NSAppleEventDescriptor *target = [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber bytes:&psn length:sizeof(ProcessSerialNumber)];
69 |
70 | // function
71 | NSAppleEventDescriptor *function = [NSAppleEventDescriptor descriptorWithString:@"safariURL"];
72 |
73 | // event
74 | NSAppleEventDescriptor *event = [NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite eventID:kASSubroutineEvent targetDescriptor:target returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID];
75 | [event setParamDescriptor:function forKeyword:keyASSubroutineName];
76 |
77 | return event;
78 | }
79 |
80 | - (NSAppleEventDescriptor *)setSafariURLEventDescriptorWithString:(NSString *)URLString
81 | {
82 | // parameter
83 | NSAppleEventDescriptor *parameter = [NSAppleEventDescriptor descriptorWithString:URLString];
84 | NSAppleEventDescriptor *parameters = [NSAppleEventDescriptor listDescriptor];
85 | [parameters insertDescriptor:parameter atIndex:1];
86 |
87 | // target
88 | ProcessSerialNumber psn = {0, kCurrentProcess};
89 | NSAppleEventDescriptor *target = [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber bytes:&psn length:sizeof(ProcessSerialNumber)];
90 |
91 | // function
92 | NSAppleEventDescriptor *function = [NSAppleEventDescriptor descriptorWithString:@"setSafariURL"];
93 |
94 | // event
95 | NSAppleEventDescriptor *event = [NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite eventID:kASSubroutineEvent targetDescriptor:target returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID];
96 | [event setParamDescriptor:function forKeyword:keyASSubroutineName];
97 | [event setParamDescriptor:parameters forKeyword:keyDirectObject];
98 |
99 | return event;
100 | }
101 |
102 | - (NSAppleEventDescriptor *)safariHTMLEventDescriptor
103 | {
104 | // target
105 | ProcessSerialNumber psn = {0, kCurrentProcess};
106 | NSAppleEventDescriptor *target = [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber bytes:&psn length:sizeof(ProcessSerialNumber)];
107 |
108 | // function
109 | NSAppleEventDescriptor *function = [NSAppleEventDescriptor descriptorWithString:@"safariHTML"];
110 |
111 | // event
112 | NSAppleEventDescriptor *event = [NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite eventID:kASSubroutineEvent targetDescriptor:target returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID];
113 | [event setParamDescriptor:function forKeyword:keyASSubroutineName];
114 |
115 | return event;
116 | }
117 |
118 | - (NSAppleEventDescriptor *)openNetworkPreferencesEventDescriptor
119 | {
120 | // target
121 | ProcessSerialNumber psn = {0, kCurrentProcess};
122 | NSAppleEventDescriptor *target = [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber bytes:&psn length:sizeof(ProcessSerialNumber)];
123 |
124 | // function
125 | NSAppleEventDescriptor *function = [NSAppleEventDescriptor descriptorWithString:@"openNetworkPreferences"];
126 |
127 | // event
128 | NSAppleEventDescriptor *event = [NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite eventID:kASSubroutineEvent targetDescriptor:target returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID];
129 | [event setParamDescriptor:function forKeyword:keyASSubroutineName];
130 |
131 | return event;
132 | }
133 |
134 | #pragma mark -
135 |
136 | - (NSString *)stringForResultEventDescriptor:(NSAppleEventDescriptor *)resultEventDescriptor
137 | {
138 | NSString *result = nil;
139 |
140 | if (resultEventDescriptor) {
141 | if ([resultEventDescriptor descriptorType] != kAENullEvent) {
142 | if ([resultEventDescriptor descriptorType] == kTXNUnicodeTextData) {
143 | result = [resultEventDescriptor stringValue];
144 | }
145 | }
146 | }
147 |
148 | return result;
149 | }
150 |
151 | - (NSURL *)URLForResultEventDescriptor:(NSAppleEventDescriptor *)resultEventDescriptor
152 | {
153 | NSURL *result = nil;
154 |
155 | NSString *URLString = nil;
156 | if (resultEventDescriptor) {
157 | if ([resultEventDescriptor descriptorType] != kAENullEvent) {
158 | if ([resultEventDescriptor descriptorType] == kTXNUnicodeTextData) {
159 | URLString = [resultEventDescriptor stringValue];
160 | }
161 | }
162 | }
163 |
164 | if (URLString && [URLString length] > 0) {
165 | result = [NSURL URLWithString:URLString];
166 | }
167 |
168 | return result;
169 | }
170 |
171 | #pragma mark - Utility
172 |
173 | - (NSUserAppleScriptTask *)automationScriptTask
174 | {
175 | NSUserAppleScriptTask *result = nil;
176 |
177 | NSError *error;
178 | NSURL *directoryURL = [[NSFileManager defaultManager] URLForDirectory:NSApplicationScriptsDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:&error];
179 | if (directoryURL) {
180 | NSURL *scriptURL = [directoryURL URLByAppendingPathComponent:@"Automation.scpt"];
181 | result = [[NSUserAppleScriptTask alloc] initWithURL:scriptURL error:&error];
182 | if (! result) {
183 | NSLog(@"%s no AppleScript task error = %@", __PRETTY_FUNCTION__, error);
184 | }
185 | }
186 | else {
187 | // NOTE: if you're not running in a sandbox, the directory URL will always be nil
188 | NSLog(@"%s no Application Scripts folder error = %@", __PRETTY_FUNCTION__, error);
189 | }
190 |
191 | return result;
192 | }
193 |
194 | - (void)updateChockifyTextFieldWithString:(NSString *)string
195 | {
196 | NSLog(@"%s string = %@", __PRETTY_FUNCTION__, string);
197 | [self.chockifyOutputTextField setStringValue:string];
198 | }
199 |
200 | - (void)updateURLTextFieldWithURL:(NSURL *)URL
201 | {
202 | NSLog(@"%s URL = %@", __PRETTY_FUNCTION__, URL);
203 | [self.URLOutputTextField setStringValue:[URL absoluteString]];
204 | }
205 |
206 | - (void)updateHTMLTextFieldWithString:(NSString *)string
207 | {
208 | NSLog(@"%s string = %@", __PRETTY_FUNCTION__, string);
209 | [self.HTMLTextView setString:string];
210 | }
211 |
212 | - (void)showNetworkAlert
213 | {
214 | NSAlert *alert = [NSAlert alertWithMessageText:@"Network Preferences Open" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"The Network preferences panel is now open."];
215 | [alert runModal];
216 | }
217 |
218 | #pragma mark - Actions
219 |
220 | - (IBAction)CHOCKIFYDUH:(id)sender
221 | {
222 | // run the script from the application's bundle
223 |
224 | NSURL *URL = [[NSBundle mainBundle] URLForResource:@"Automation" withExtension:@"scpt"];
225 | if (URL) {
226 | NSAppleScript *appleScript = [[NSAppleScript alloc] initWithContentsOfURL:URL error:NULL];
227 |
228 | NSAppleEventDescriptor *event = [self chockifyEventDescriptorWithString:[self.chockifyInputTextField stringValue]];
229 | NSDictionary *error = nil;
230 | NSAppleEventDescriptor *resultEventDescriptor = [appleScript executeAppleEvent:event error:&error];
231 | if (! resultEventDescriptor) {
232 | NSLog(@"%s AppleScript run error = %@", __PRETTY_FUNCTION__, error);
233 | }
234 | else {
235 | NSString *string = [self stringForResultEventDescriptor:resultEventDescriptor];
236 | [self updateChockifyTextFieldWithString:string];
237 | }
238 | }
239 | }
240 |
241 | - (IBAction)bummer:(id)sender
242 | {
243 | // run the script from the application's bundle -- and fail
244 |
245 | NSURL *URL = [[NSBundle mainBundle] URLForResource:@"Automation" withExtension:@"scpt"];
246 | if (URL) {
247 | NSAppleScript *appleScript = [[NSAppleScript alloc] initWithContentsOfURL:URL error:NULL];
248 |
249 | NSAppleEventDescriptor *event = [self safariURLEventDescriptor];
250 | NSDictionary *error = nil;
251 | NSAppleEventDescriptor *resultEventDescriptor = [appleScript executeAppleEvent:event error:&error];
252 | if (! resultEventDescriptor) {
253 | NSLog(@"%s AppleScript run error = %@", __PRETTY_FUNCTION__, error);
254 |
255 | // AppleScript says that Safari isn't running, even when it is...
256 | }
257 | else {
258 | NSURL *URL = [self URLForResultEventDescriptor:resultEventDescriptor];
259 | [self updateURLTextFieldWithURL:URL];
260 | }
261 | }
262 | }
263 |
264 | - (IBAction)installAutomationScript:(id)sender
265 | {
266 | // NOTE: For this to work, you MUST update the Capbilities > App Sandbox > File Access > User Selected File to Read/Write.
267 |
268 | NSError *error;
269 | NSURL *directoryURL = [[NSFileManager defaultManager] URLForDirectory:NSApplicationScriptsDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:&error];
270 | NSOpenPanel *openPanel = [NSOpenPanel openPanel];
271 | [openPanel setDirectoryURL:directoryURL];
272 | [openPanel setCanChooseDirectories:YES];
273 | [openPanel setCanChooseFiles:NO];
274 | [openPanel setPrompt:@"Select Script Folder"];
275 | [openPanel setMessage:@"Please select the User > Library > Application Scripts > com.iconfactory.Scriptinator folder"];
276 | [openPanel beginWithCompletionHandler:^(NSInteger result) {
277 | if (result == NSFileHandlingPanelOKButton) {
278 | NSURL *selectedURL = [openPanel URL];
279 | if ([selectedURL isEqual:directoryURL]) {
280 | NSURL *destinationURL = [selectedURL URLByAppendingPathComponent:@"Automation.scpt"];
281 | NSFileManager *fileManager = [NSFileManager defaultManager];
282 | NSURL *sourceURL = [[NSBundle mainBundle] URLForResource:@"Automation" withExtension:@"scpt"];
283 | NSError *error;
284 | BOOL success = [fileManager copyItemAtURL:sourceURL toURL:destinationURL error:&error];
285 | if (success) {
286 | NSAlert *alert = [NSAlert alertWithMessageText:@"Script Installed" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"The Automation script was installed succcessfully."];
287 | [alert runModal];
288 |
289 | // NOTE: This is a bit of a hack to get the Application Scripts path out of the next open or save panel that appears.
290 | [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"NSNavLastRootDirectory"];
291 | }
292 | else {
293 | NSLog(@"%s error = %@", __PRETTY_FUNCTION__, error);
294 | if ([error code] == NSFileWriteFileExistsError) {
295 | // the script was already installed Application Scripts folder
296 |
297 | if (! [fileManager removeItemAtURL:destinationURL error:&error]) {
298 | NSLog(@"%s error = %@", __PRETTY_FUNCTION__, error);
299 | }
300 | else {
301 | BOOL success = [fileManager copyItemAtURL:sourceURL toURL:destinationURL error:&error];
302 | if (success) {
303 | NSAlert *alert = [NSAlert alertWithMessageText:@"Script Updated" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"The Automation script was updated."];
304 | [alert runModal];
305 | }
306 | }
307 | }
308 | else {
309 | // the item couldn't be copied, try again
310 | [self performSelector:@selector(installAutomationScript:) withObject:self afterDelay:0.0];
311 | }
312 | }
313 | }
314 | else {
315 | // try again because the user changed the folder path
316 | [self performSelector:@selector(installAutomationScript:) withObject:self afterDelay:0.0];
317 | }
318 | }
319 | }];
320 | }
321 |
322 | - (IBAction)getURL:(id)sender
323 | {
324 | NSUserAppleScriptTask *automationScriptTask = [self automationScriptTask];
325 | if (automationScriptTask) {
326 | NSAppleEventDescriptor *event = [self safariURLEventDescriptor];
327 | [automationScriptTask executeWithAppleEvent:event completionHandler:^(NSAppleEventDescriptor *resultEventDescriptor, NSError *error) {
328 | if (! resultEventDescriptor) {
329 | NSLog(@"%s AppleScript task error = %@", __PRETTY_FUNCTION__, error);
330 | }
331 | else {
332 | NSURL *URL = [self URLForResultEventDescriptor:resultEventDescriptor];
333 | // NOTE: The completion handler for the script is not run on the main thread. Before you update any UI, you'll need to get
334 | // on that thread by using libdispatch or performing a selector.
335 | [self performSelectorOnMainThread:@selector(updateURLTextFieldWithURL:) withObject:URL waitUntilDone:NO];
336 | }
337 | }];
338 | }
339 | else {
340 | // the task couldn't be run, so try to install the script again (it could have been manually deleted by the user)
341 | [self installAutomationScript:self];
342 | }
343 | }
344 |
345 | - (IBAction)setURL:(id)sender
346 | {
347 | NSUserAppleScriptTask *automationScriptTask = [self automationScriptTask];
348 | if (automationScriptTask) {
349 | NSAppleEventDescriptor *event = [self setSafariURLEventDescriptorWithString:[self.URLInputTextField stringValue]];
350 | [automationScriptTask executeWithAppleEvent:event completionHandler:^(NSAppleEventDescriptor *resultEventDescriptor, NSError *error) {
351 | if (! resultEventDescriptor) {
352 | NSLog(@"%s AppleScript task error = %@", __PRETTY_FUNCTION__, error);
353 | }
354 | }];
355 | }
356 | }
357 |
358 | - (IBAction)getHTML:(id)sender
359 | {
360 | NSUserAppleScriptTask *automationScriptTask = [self automationScriptTask];
361 | if (automationScriptTask) {
362 | NSAppleEventDescriptor *event = [self safariHTMLEventDescriptor];
363 | [automationScriptTask executeWithAppleEvent:event completionHandler:^(NSAppleEventDescriptor *resultEventDescriptor, NSError *error) {
364 | if (! resultEventDescriptor) {
365 | NSLog(@"%s AppleScript task error = %@", __PRETTY_FUNCTION__, error);
366 | }
367 | else {
368 | NSString *HTMLString = [self stringForResultEventDescriptor:resultEventDescriptor];
369 | [self performSelectorOnMainThread:@selector(updateHTMLTextFieldWithString:) withObject:HTMLString waitUntilDone:NO];
370 | }
371 | }];
372 | }
373 | }
374 |
375 | - (IBAction)openUserScriptsFolder:(id)sender
376 | {
377 | NSError *error;
378 | NSURL *directoryURL = [[NSFileManager defaultManager] URLForDirectory:NSApplicationScriptsDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:&error];
379 |
380 | [[NSWorkspace sharedWorkspace] openURL:directoryURL];
381 | }
382 |
383 | - (IBAction)openNetworkPreferences:(id)sender
384 | {
385 | NSUserAppleScriptTask *automationScriptTask = [self automationScriptTask];
386 | if (automationScriptTask) {
387 | // wait for any previous tasks to complete before starting a new one — remember that you're blocking the main thread here!
388 | dispatch_semaphore_wait(self.appleScriptTaskSemaphore, DISPATCH_TIME_FOREVER);
389 |
390 | // run the script task
391 | NSAppleEventDescriptor *event = [self openNetworkPreferencesEventDescriptor];
392 | [automationScriptTask executeWithAppleEvent:event completionHandler:^(NSAppleEventDescriptor *resultEventDescriptor, NSError *error) {
393 | if (! resultEventDescriptor) {
394 | NSLog(@"%s AppleScript task error = %@", __PRETTY_FUNCTION__, error);
395 | }
396 | else {
397 | [self performSelectorOnMainThread:@selector(showNetworkAlert) withObject:nil waitUntilDone:NO];
398 | }
399 |
400 | // the task has completed, so let any pending tasks proceed
401 | dispatch_semaphore_signal(self.appleScriptTaskSemaphore);
402 | }];
403 | }
404 | }
405 |
406 | @end
407 |
--------------------------------------------------------------------------------
/Scriptinator.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 446EB0AF1955E93E007C37F7 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 446EB0AE1955E93E007C37F7 /* Cocoa.framework */; };
11 | 446EB0B91955E93E007C37F7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 446EB0B71955E93E007C37F7 /* InfoPlist.strings */; };
12 | 446EB0BB1955E93E007C37F7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 446EB0BA1955E93E007C37F7 /* main.m */; };
13 | 446EB0BF1955E93E007C37F7 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 446EB0BD1955E93E007C37F7 /* Credits.rtf */; };
14 | 446EB0C21955E93E007C37F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 446EB0C11955E93E007C37F7 /* AppDelegate.m */; };
15 | 446EB0C51955E93E007C37F7 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 446EB0C31955E93E007C37F7 /* MainMenu.xib */; };
16 | 446EB0C71955E93E007C37F7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 446EB0C61955E93E007C37F7 /* Images.xcassets */; };
17 | 446EB0CE1955E93E007C37F7 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 446EB0CD1955E93E007C37F7 /* XCTest.framework */; };
18 | 446EB0CF1955E93E007C37F7 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 446EB0AE1955E93E007C37F7 /* Cocoa.framework */; };
19 | 446EB0D71955E93E007C37F7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 446EB0D51955E93E007C37F7 /* InfoPlist.strings */; };
20 | 446EB0D91955E93E007C37F7 /* ScriptinatorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 446EB0D81955E93E007C37F7 /* ScriptinatorTests.m */; };
21 | 446EB0E41955EEFE007C37F7 /* Automation.scpt in Resources */ = {isa = PBXBuildFile; fileRef = 446EB0E31955EEFE007C37F7 /* Automation.scpt */; };
22 | /* End PBXBuildFile section */
23 |
24 | /* Begin PBXContainerItemProxy section */
25 | 446EB0D01955E93E007C37F7 /* PBXContainerItemProxy */ = {
26 | isa = PBXContainerItemProxy;
27 | containerPortal = 446EB0A31955E93E007C37F7 /* Project object */;
28 | proxyType = 1;
29 | remoteGlobalIDString = 446EB0AA1955E93E007C37F7;
30 | remoteInfo = Scriptinator;
31 | };
32 | /* End PBXContainerItemProxy section */
33 |
34 | /* Begin PBXFileReference section */
35 | 446EB0AB1955E93E007C37F7 /* Scriptinator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Scriptinator.app; sourceTree = BUILT_PRODUCTS_DIR; };
36 | 446EB0AE1955E93E007C37F7 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
37 | 446EB0B11955E93E007C37F7 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
38 | 446EB0B21955E93E007C37F7 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
39 | 446EB0B31955E93E007C37F7 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
40 | 446EB0B61955E93E007C37F7 /* Scriptinator-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Scriptinator-Info.plist"; sourceTree = ""; };
41 | 446EB0B81955E93E007C37F7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
42 | 446EB0BA1955E93E007C37F7 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
43 | 446EB0BC1955E93E007C37F7 /* Scriptinator-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Scriptinator-Prefix.pch"; sourceTree = ""; };
44 | 446EB0BE1955E93E007C37F7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; };
45 | 446EB0C01955E93E007C37F7 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
46 | 446EB0C11955E93E007C37F7 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
47 | 446EB0C41955E93E007C37F7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; };
48 | 446EB0C61955E93E007C37F7 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
49 | 446EB0CC1955E93E007C37F7 /* ScriptinatorTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ScriptinatorTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
50 | 446EB0CD1955E93E007C37F7 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
51 | 446EB0D41955E93E007C37F7 /* ScriptinatorTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ScriptinatorTests-Info.plist"; sourceTree = ""; };
52 | 446EB0D61955E93E007C37F7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
53 | 446EB0D81955E93E007C37F7 /* ScriptinatorTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ScriptinatorTests.m; sourceTree = ""; };
54 | 446EB0E21955E94F007C37F7 /* Scriptinator.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Scriptinator.entitlements; sourceTree = ""; };
55 | 446EB0E31955EEFE007C37F7 /* Automation.scpt */ = {isa = PBXFileReference; lastKnownFileType = file; path = Automation.scpt; sourceTree = ""; };
56 | /* End PBXFileReference section */
57 |
58 | /* Begin PBXFrameworksBuildPhase section */
59 | 446EB0A81955E93E007C37F7 /* Frameworks */ = {
60 | isa = PBXFrameworksBuildPhase;
61 | buildActionMask = 2147483647;
62 | files = (
63 | 446EB0AF1955E93E007C37F7 /* Cocoa.framework in Frameworks */,
64 | );
65 | runOnlyForDeploymentPostprocessing = 0;
66 | };
67 | 446EB0C91955E93E007C37F7 /* Frameworks */ = {
68 | isa = PBXFrameworksBuildPhase;
69 | buildActionMask = 2147483647;
70 | files = (
71 | 446EB0CF1955E93E007C37F7 /* Cocoa.framework in Frameworks */,
72 | 446EB0CE1955E93E007C37F7 /* XCTest.framework in Frameworks */,
73 | );
74 | runOnlyForDeploymentPostprocessing = 0;
75 | };
76 | /* End PBXFrameworksBuildPhase section */
77 |
78 | /* Begin PBXGroup section */
79 | 446EB0A21955E93E007C37F7 = {
80 | isa = PBXGroup;
81 | children = (
82 | 446EB0B41955E93E007C37F7 /* Scriptinator */,
83 | 446EB0D21955E93E007C37F7 /* ScriptinatorTests */,
84 | 446EB0AD1955E93E007C37F7 /* Frameworks */,
85 | 446EB0AC1955E93E007C37F7 /* Products */,
86 | );
87 | sourceTree = "";
88 | };
89 | 446EB0AC1955E93E007C37F7 /* Products */ = {
90 | isa = PBXGroup;
91 | children = (
92 | 446EB0AB1955E93E007C37F7 /* Scriptinator.app */,
93 | 446EB0CC1955E93E007C37F7 /* ScriptinatorTests.xctest */,
94 | );
95 | name = Products;
96 | sourceTree = "";
97 | };
98 | 446EB0AD1955E93E007C37F7 /* Frameworks */ = {
99 | isa = PBXGroup;
100 | children = (
101 | 446EB0AE1955E93E007C37F7 /* Cocoa.framework */,
102 | 446EB0CD1955E93E007C37F7 /* XCTest.framework */,
103 | 446EB0B01955E93E007C37F7 /* Other Frameworks */,
104 | );
105 | name = Frameworks;
106 | sourceTree = "";
107 | };
108 | 446EB0B01955E93E007C37F7 /* Other Frameworks */ = {
109 | isa = PBXGroup;
110 | children = (
111 | 446EB0B11955E93E007C37F7 /* AppKit.framework */,
112 | 446EB0B21955E93E007C37F7 /* CoreData.framework */,
113 | 446EB0B31955E93E007C37F7 /* Foundation.framework */,
114 | );
115 | name = "Other Frameworks";
116 | sourceTree = "";
117 | };
118 | 446EB0B41955E93E007C37F7 /* Scriptinator */ = {
119 | isa = PBXGroup;
120 | children = (
121 | 446EB0E31955EEFE007C37F7 /* Automation.scpt */,
122 | 446EB0E21955E94F007C37F7 /* Scriptinator.entitlements */,
123 | 446EB0C01955E93E007C37F7 /* AppDelegate.h */,
124 | 446EB0C11955E93E007C37F7 /* AppDelegate.m */,
125 | 446EB0C31955E93E007C37F7 /* MainMenu.xib */,
126 | 446EB0C61955E93E007C37F7 /* Images.xcassets */,
127 | 446EB0B51955E93E007C37F7 /* Supporting Files */,
128 | );
129 | path = Scriptinator;
130 | sourceTree = "";
131 | };
132 | 446EB0B51955E93E007C37F7 /* Supporting Files */ = {
133 | isa = PBXGroup;
134 | children = (
135 | 446EB0B61955E93E007C37F7 /* Scriptinator-Info.plist */,
136 | 446EB0B71955E93E007C37F7 /* InfoPlist.strings */,
137 | 446EB0BA1955E93E007C37F7 /* main.m */,
138 | 446EB0BC1955E93E007C37F7 /* Scriptinator-Prefix.pch */,
139 | 446EB0BD1955E93E007C37F7 /* Credits.rtf */,
140 | );
141 | name = "Supporting Files";
142 | sourceTree = "";
143 | };
144 | 446EB0D21955E93E007C37F7 /* ScriptinatorTests */ = {
145 | isa = PBXGroup;
146 | children = (
147 | 446EB0D81955E93E007C37F7 /* ScriptinatorTests.m */,
148 | 446EB0D31955E93E007C37F7 /* Supporting Files */,
149 | );
150 | path = ScriptinatorTests;
151 | sourceTree = "";
152 | };
153 | 446EB0D31955E93E007C37F7 /* Supporting Files */ = {
154 | isa = PBXGroup;
155 | children = (
156 | 446EB0D41955E93E007C37F7 /* ScriptinatorTests-Info.plist */,
157 | 446EB0D51955E93E007C37F7 /* InfoPlist.strings */,
158 | );
159 | name = "Supporting Files";
160 | sourceTree = "";
161 | };
162 | /* End PBXGroup section */
163 |
164 | /* Begin PBXNativeTarget section */
165 | 446EB0AA1955E93E007C37F7 /* Scriptinator */ = {
166 | isa = PBXNativeTarget;
167 | buildConfigurationList = 446EB0DC1955E93E007C37F7 /* Build configuration list for PBXNativeTarget "Scriptinator" */;
168 | buildPhases = (
169 | 446EB0A71955E93E007C37F7 /* Sources */,
170 | 446EB0A81955E93E007C37F7 /* Frameworks */,
171 | 446EB0A91955E93E007C37F7 /* Resources */,
172 | );
173 | buildRules = (
174 | );
175 | dependencies = (
176 | );
177 | name = Scriptinator;
178 | productName = Scriptinator;
179 | productReference = 446EB0AB1955E93E007C37F7 /* Scriptinator.app */;
180 | productType = "com.apple.product-type.application";
181 | };
182 | 446EB0CB1955E93E007C37F7 /* ScriptinatorTests */ = {
183 | isa = PBXNativeTarget;
184 | buildConfigurationList = 446EB0DF1955E93E007C37F7 /* Build configuration list for PBXNativeTarget "ScriptinatorTests" */;
185 | buildPhases = (
186 | 446EB0C81955E93E007C37F7 /* Sources */,
187 | 446EB0C91955E93E007C37F7 /* Frameworks */,
188 | 446EB0CA1955E93E007C37F7 /* Resources */,
189 | );
190 | buildRules = (
191 | );
192 | dependencies = (
193 | 446EB0D11955E93E007C37F7 /* PBXTargetDependency */,
194 | );
195 | name = ScriptinatorTests;
196 | productName = ScriptinatorTests;
197 | productReference = 446EB0CC1955E93E007C37F7 /* ScriptinatorTests.xctest */;
198 | productType = "com.apple.product-type.bundle.unit-test";
199 | };
200 | /* End PBXNativeTarget section */
201 |
202 | /* Begin PBXProject section */
203 | 446EB0A31955E93E007C37F7 /* Project object */ = {
204 | isa = PBXProject;
205 | attributes = {
206 | LastUpgradeCheck = 0510;
207 | ORGANIZATIONNAME = "Craig Hockenberry";
208 | TargetAttributes = {
209 | 446EB0AA1955E93E007C37F7 = {
210 | SystemCapabilities = {
211 | com.apple.Sandbox = {
212 | enabled = 1;
213 | };
214 | };
215 | };
216 | 446EB0CB1955E93E007C37F7 = {
217 | TestTargetID = 446EB0AA1955E93E007C37F7;
218 | };
219 | };
220 | };
221 | buildConfigurationList = 446EB0A61955E93E007C37F7 /* Build configuration list for PBXProject "Scriptinator" */;
222 | compatibilityVersion = "Xcode 3.2";
223 | developmentRegion = English;
224 | hasScannedForEncodings = 0;
225 | knownRegions = (
226 | en,
227 | Base,
228 | );
229 | mainGroup = 446EB0A21955E93E007C37F7;
230 | productRefGroup = 446EB0AC1955E93E007C37F7 /* Products */;
231 | projectDirPath = "";
232 | projectRoot = "";
233 | targets = (
234 | 446EB0AA1955E93E007C37F7 /* Scriptinator */,
235 | 446EB0CB1955E93E007C37F7 /* ScriptinatorTests */,
236 | );
237 | };
238 | /* End PBXProject section */
239 |
240 | /* Begin PBXResourcesBuildPhase section */
241 | 446EB0A91955E93E007C37F7 /* Resources */ = {
242 | isa = PBXResourcesBuildPhase;
243 | buildActionMask = 2147483647;
244 | files = (
245 | 446EB0B91955E93E007C37F7 /* InfoPlist.strings in Resources */,
246 | 446EB0C71955E93E007C37F7 /* Images.xcassets in Resources */,
247 | 446EB0BF1955E93E007C37F7 /* Credits.rtf in Resources */,
248 | 446EB0C51955E93E007C37F7 /* MainMenu.xib in Resources */,
249 | 446EB0E41955EEFE007C37F7 /* Automation.scpt in Resources */,
250 | );
251 | runOnlyForDeploymentPostprocessing = 0;
252 | };
253 | 446EB0CA1955E93E007C37F7 /* Resources */ = {
254 | isa = PBXResourcesBuildPhase;
255 | buildActionMask = 2147483647;
256 | files = (
257 | 446EB0D71955E93E007C37F7 /* InfoPlist.strings in Resources */,
258 | );
259 | runOnlyForDeploymentPostprocessing = 0;
260 | };
261 | /* End PBXResourcesBuildPhase section */
262 |
263 | /* Begin PBXSourcesBuildPhase section */
264 | 446EB0A71955E93E007C37F7 /* Sources */ = {
265 | isa = PBXSourcesBuildPhase;
266 | buildActionMask = 2147483647;
267 | files = (
268 | 446EB0C21955E93E007C37F7 /* AppDelegate.m in Sources */,
269 | 446EB0BB1955E93E007C37F7 /* main.m in Sources */,
270 | );
271 | runOnlyForDeploymentPostprocessing = 0;
272 | };
273 | 446EB0C81955E93E007C37F7 /* Sources */ = {
274 | isa = PBXSourcesBuildPhase;
275 | buildActionMask = 2147483647;
276 | files = (
277 | 446EB0D91955E93E007C37F7 /* ScriptinatorTests.m in Sources */,
278 | );
279 | runOnlyForDeploymentPostprocessing = 0;
280 | };
281 | /* End PBXSourcesBuildPhase section */
282 |
283 | /* Begin PBXTargetDependency section */
284 | 446EB0D11955E93E007C37F7 /* PBXTargetDependency */ = {
285 | isa = PBXTargetDependency;
286 | target = 446EB0AA1955E93E007C37F7 /* Scriptinator */;
287 | targetProxy = 446EB0D01955E93E007C37F7 /* PBXContainerItemProxy */;
288 | };
289 | /* End PBXTargetDependency section */
290 |
291 | /* Begin PBXVariantGroup section */
292 | 446EB0B71955E93E007C37F7 /* InfoPlist.strings */ = {
293 | isa = PBXVariantGroup;
294 | children = (
295 | 446EB0B81955E93E007C37F7 /* en */,
296 | );
297 | name = InfoPlist.strings;
298 | sourceTree = "";
299 | };
300 | 446EB0BD1955E93E007C37F7 /* Credits.rtf */ = {
301 | isa = PBXVariantGroup;
302 | children = (
303 | 446EB0BE1955E93E007C37F7 /* en */,
304 | );
305 | name = Credits.rtf;
306 | sourceTree = "";
307 | };
308 | 446EB0C31955E93E007C37F7 /* MainMenu.xib */ = {
309 | isa = PBXVariantGroup;
310 | children = (
311 | 446EB0C41955E93E007C37F7 /* Base */,
312 | );
313 | name = MainMenu.xib;
314 | sourceTree = "";
315 | };
316 | 446EB0D51955E93E007C37F7 /* InfoPlist.strings */ = {
317 | isa = PBXVariantGroup;
318 | children = (
319 | 446EB0D61955E93E007C37F7 /* en */,
320 | );
321 | name = InfoPlist.strings;
322 | sourceTree = "";
323 | };
324 | /* End PBXVariantGroup section */
325 |
326 | /* Begin XCBuildConfiguration section */
327 | 446EB0DA1955E93E007C37F7 /* Debug */ = {
328 | isa = XCBuildConfiguration;
329 | buildSettings = {
330 | ALWAYS_SEARCH_USER_PATHS = NO;
331 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
332 | CLANG_CXX_LIBRARY = "libc++";
333 | CLANG_ENABLE_MODULES = YES;
334 | CLANG_ENABLE_OBJC_ARC = YES;
335 | CLANG_WARN_BOOL_CONVERSION = YES;
336 | CLANG_WARN_CONSTANT_CONVERSION = YES;
337 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
338 | CLANG_WARN_EMPTY_BODY = YES;
339 | CLANG_WARN_ENUM_CONVERSION = YES;
340 | CLANG_WARN_INT_CONVERSION = YES;
341 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
342 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
343 | COPY_PHASE_STRIP = NO;
344 | GCC_C_LANGUAGE_STANDARD = gnu99;
345 | GCC_DYNAMIC_NO_PIC = NO;
346 | GCC_ENABLE_OBJC_EXCEPTIONS = YES;
347 | GCC_OPTIMIZATION_LEVEL = 0;
348 | GCC_PREPROCESSOR_DEFINITIONS = (
349 | "DEBUG=1",
350 | "$(inherited)",
351 | );
352 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
353 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
354 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
355 | GCC_WARN_UNDECLARED_SELECTOR = YES;
356 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
357 | GCC_WARN_UNUSED_FUNCTION = YES;
358 | GCC_WARN_UNUSED_VARIABLE = YES;
359 | MACOSX_DEPLOYMENT_TARGET = 10.8;
360 | ONLY_ACTIVE_ARCH = YES;
361 | SDKROOT = macosx;
362 | };
363 | name = Debug;
364 | };
365 | 446EB0DB1955E93E007C37F7 /* Release */ = {
366 | isa = XCBuildConfiguration;
367 | buildSettings = {
368 | ALWAYS_SEARCH_USER_PATHS = NO;
369 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
370 | CLANG_CXX_LIBRARY = "libc++";
371 | CLANG_ENABLE_MODULES = YES;
372 | CLANG_ENABLE_OBJC_ARC = YES;
373 | CLANG_WARN_BOOL_CONVERSION = YES;
374 | CLANG_WARN_CONSTANT_CONVERSION = YES;
375 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
376 | CLANG_WARN_EMPTY_BODY = YES;
377 | CLANG_WARN_ENUM_CONVERSION = YES;
378 | CLANG_WARN_INT_CONVERSION = YES;
379 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
380 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
381 | COPY_PHASE_STRIP = YES;
382 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
383 | ENABLE_NS_ASSERTIONS = NO;
384 | GCC_C_LANGUAGE_STANDARD = gnu99;
385 | GCC_ENABLE_OBJC_EXCEPTIONS = YES;
386 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
387 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
388 | GCC_WARN_UNDECLARED_SELECTOR = YES;
389 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
390 | GCC_WARN_UNUSED_FUNCTION = YES;
391 | GCC_WARN_UNUSED_VARIABLE = YES;
392 | MACOSX_DEPLOYMENT_TARGET = 10.8;
393 | SDKROOT = macosx;
394 | };
395 | name = Release;
396 | };
397 | 446EB0DD1955E93E007C37F7 /* Debug */ = {
398 | isa = XCBuildConfiguration;
399 | buildSettings = {
400 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
401 | CODE_SIGN_ENTITLEMENTS = Scriptinator/Scriptinator.entitlements;
402 | CODE_SIGN_IDENTITY = "-";
403 | COMBINE_HIDPI_IMAGES = YES;
404 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
405 | GCC_PREFIX_HEADER = "Scriptinator/Scriptinator-Prefix.pch";
406 | INFOPLIST_FILE = "Scriptinator/Scriptinator-Info.plist";
407 | PRODUCT_NAME = "$(TARGET_NAME)";
408 | WRAPPER_EXTENSION = app;
409 | };
410 | name = Debug;
411 | };
412 | 446EB0DE1955E93E007C37F7 /* Release */ = {
413 | isa = XCBuildConfiguration;
414 | buildSettings = {
415 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
416 | CODE_SIGN_ENTITLEMENTS = Scriptinator/Scriptinator.entitlements;
417 | CODE_SIGN_IDENTITY = "-";
418 | COMBINE_HIDPI_IMAGES = YES;
419 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
420 | GCC_PREFIX_HEADER = "Scriptinator/Scriptinator-Prefix.pch";
421 | INFOPLIST_FILE = "Scriptinator/Scriptinator-Info.plist";
422 | PRODUCT_NAME = "$(TARGET_NAME)";
423 | WRAPPER_EXTENSION = app;
424 | };
425 | name = Release;
426 | };
427 | 446EB0E01955E93E007C37F7 /* Debug */ = {
428 | isa = XCBuildConfiguration;
429 | buildSettings = {
430 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Scriptinator.app/Contents/MacOS/Scriptinator";
431 | COMBINE_HIDPI_IMAGES = YES;
432 | FRAMEWORK_SEARCH_PATHS = (
433 | "$(DEVELOPER_FRAMEWORKS_DIR)",
434 | "$(inherited)",
435 | );
436 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
437 | GCC_PREFIX_HEADER = "Scriptinator/Scriptinator-Prefix.pch";
438 | GCC_PREPROCESSOR_DEFINITIONS = (
439 | "DEBUG=1",
440 | "$(inherited)",
441 | );
442 | INFOPLIST_FILE = "ScriptinatorTests/ScriptinatorTests-Info.plist";
443 | PRODUCT_NAME = "$(TARGET_NAME)";
444 | TEST_HOST = "$(BUNDLE_LOADER)";
445 | WRAPPER_EXTENSION = xctest;
446 | };
447 | name = Debug;
448 | };
449 | 446EB0E11955E93E007C37F7 /* Release */ = {
450 | isa = XCBuildConfiguration;
451 | buildSettings = {
452 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Scriptinator.app/Contents/MacOS/Scriptinator";
453 | COMBINE_HIDPI_IMAGES = YES;
454 | FRAMEWORK_SEARCH_PATHS = (
455 | "$(DEVELOPER_FRAMEWORKS_DIR)",
456 | "$(inherited)",
457 | );
458 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
459 | GCC_PREFIX_HEADER = "Scriptinator/Scriptinator-Prefix.pch";
460 | INFOPLIST_FILE = "ScriptinatorTests/ScriptinatorTests-Info.plist";
461 | PRODUCT_NAME = "$(TARGET_NAME)";
462 | TEST_HOST = "$(BUNDLE_LOADER)";
463 | WRAPPER_EXTENSION = xctest;
464 | };
465 | name = Release;
466 | };
467 | /* End XCBuildConfiguration section */
468 |
469 | /* Begin XCConfigurationList section */
470 | 446EB0A61955E93E007C37F7 /* Build configuration list for PBXProject "Scriptinator" */ = {
471 | isa = XCConfigurationList;
472 | buildConfigurations = (
473 | 446EB0DA1955E93E007C37F7 /* Debug */,
474 | 446EB0DB1955E93E007C37F7 /* Release */,
475 | );
476 | defaultConfigurationIsVisible = 0;
477 | defaultConfigurationName = Release;
478 | };
479 | 446EB0DC1955E93E007C37F7 /* Build configuration list for PBXNativeTarget "Scriptinator" */ = {
480 | isa = XCConfigurationList;
481 | buildConfigurations = (
482 | 446EB0DD1955E93E007C37F7 /* Debug */,
483 | 446EB0DE1955E93E007C37F7 /* Release */,
484 | );
485 | defaultConfigurationIsVisible = 0;
486 | };
487 | 446EB0DF1955E93E007C37F7 /* Build configuration list for PBXNativeTarget "ScriptinatorTests" */ = {
488 | isa = XCConfigurationList;
489 | buildConfigurations = (
490 | 446EB0E01955E93E007C37F7 /* Debug */,
491 | 446EB0E11955E93E007C37F7 /* Release */,
492 | );
493 | defaultConfigurationIsVisible = 0;
494 | };
495 | /* End XCConfigurationList section */
496 | };
497 | rootObject = 446EB0A31955E93E007C37F7 /* Project object */;
498 | }
499 |
--------------------------------------------------------------------------------
/Scriptinator/Base.lproj/MainMenu.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
694 |
705 |
716 |
727 |
738 |
749 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 |
805 |
806 |
807 |
808 |
809 |
810 |
811 |
812 |
813 |
814 |
815 |
816 |
817 |
818 |
819 |
820 |
821 |
822 |
823 |
824 |
825 |
826 |
827 |
828 |
829 |
830 |
831 |
832 |
833 |
834 |
835 |
836 |
837 |
838 |
839 |
840 |
841 |
852 |
853 |
854 |
855 |
856 |
857 |
858 |
859 |
860 |
861 |
862 |
863 |
864 |
865 |
866 |
867 |
868 |
869 |
870 |
871 |
872 |
873 |
874 |
875 |
876 |
877 |
878 |
879 |
880 |
881 |
882 |
883 |
884 |
885 |
886 |
887 |
888 |
889 |
890 |
891 |
892 |
893 |
894 |
895 |
896 |
897 |
898 |
899 |
900 |
901 |
902 |
903 | Click the Get HTML button to get the markup from the document of the frontmost window using JavaScript run from an AppleScript.
904 |
905 | Pretty neat, huh?
906 |
907 |
908 |
909 |
910 |
911 |
912 |
913 |
914 |
915 |
916 |
917 |
918 |
919 |
920 |
921 |
922 |
923 |
924 |
925 |
926 |
927 |
928 |
929 |
930 |
931 |
932 |
933 |
934 |
935 |
936 |
937 |
938 |
939 |
940 |
941 |
942 |
--------------------------------------------------------------------------------