macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

BYOB: Build Your Own Browser, Part 2
Pages: 1, 2, 3

Changing the Code

There are five pieces of code that need to be added: first, code to make it so the MyDocument class can access the UI elements that we connected to it; second, code the "connectURL" method to handle processing connections entered in the URL text field; third, code to handle JavaScript pop-up windows; fourth, code to handle setting a default home page to load when a new browser window is loaded; and finally, code to handle updating the URL line when pages get forwarded automatically by the WebView object. This sounds like a lot of code to be adding and updating, but it's really not. And the code that will be added is simple and straightforward to understand.

Connecting the UI Elements

The first step is to edit MyDocuments class header file, MyDocument.h, located in the "Classes" subdirectory of the project in Xcode.

If you look at the file now it is pretty empty and should look something like:


#import <Cocoa/Cocoa.h>

@interface MyDocument : NSDocument
{
}
@end

The first line to add is:


#import <WebKit/WebView.h>

after the line "#import <Cocoa/Cocoa.h>". This file gives the Objective-C compiler the information it needs to access the fields and methods of the WebView object.

Next add:


IBOutlet id urlString;
IBOutlet WebView *webView;

between the { and } brackets after the "@interface" statement. These statements are for the outlets that were set up in the NIB file.

The last line to add is:


- (IBAction)connectURL:(id)sender;

after the closing bracket (that is, / }) of the "@interface" declaration and before the "@end" statement. This statement is for the action that was set up in the NIB file.

In the end, the file should look like:


#import <Cocoa/Cocoa.h>

#import <WebKit/WebView.h>

@interface MyDocument : NSDocument
{
    IBOutlet id urlString;
    IBOutlet WebView *webView;
}
- (IBAction)connectURL:(id)sender;
@end

Adding "connectURL"

The next step is to add the connectURL method to MyDocument's implementation file, MyDocument.m. When you open this file, you'll notice that it contains a number of predefined method prototypes. (These methods will be useful to use later in the article, but for the time being ignore these methods.) Add the "connectURL" method:


- (IBAction)connectURL:(id)sender{
    [urlString setStringValue:[sender stringValue]];
    [[webView mainFrame] loadRequest:
	[NSURLRequest requestWithURL:
	    [NSURL URLWithString:
		[sender stringValue]]]];
}

after these methods and before the "@end" statement.

This method is pretty simple; the first line gets the string value from urlString; the second sends that value to the WebView instance to load the site with that string.

You may wonder why we changed this method if for all intents and purposes it does the same that it did before we disconnected the urlString field from the webView object in the NIB. In the old version, the developer maintained no control over how the connection was made, so whatever was entered on the URL line was sent directly to the WebView object.

This creates a problem because when a user enters "www.macdevcenter.com" in the URL line nothing happens, because it lacked a protocol statement ("http://"). We will not implement it here, but "connectURL" can be used to check for a protocol (by doing a string search for ":"), and if one is not present then connectURL can add a default protocol. It is interesting to check out what Safari does when a protocol and a sub-domain are left out on the URL line.

Once "connectURL" is added, the browser now supports basic multi-window operations. If you test it out at this point, you can create new browser windows from the "File/New" menu, but you will not be able to create new windows using JavaScript requests.

JavaScript Windows

Now that we have a basic multi-window browser working, it's time to open up Pandora's box and add support for JavaScript window requests. These requests will be handled using Objective-C's delegation mechanism. The delegation mechanism allows Objective-C classes to be modified without having to subclass them. A class implements a delegate for another class by first altering the delegating class that it will implement its delegation methods and then implementing those methods. This is the extent of our explanation of delegation methods but if you want more information, check out this article at developer.apple.com.

JavaScript window requests are handled by WebKit's UIDelegate. We need to alter the WebView instance, webView, so that the MyDocument object will be the UIDelegate by adding two lines of code:


[webView setUIDelegate:self]; 
[webView setGroupName:@"MyDocument"];

somewhere within MyDocument. One of the methods that Xcode predefined for us in MyDocument is windowControllerDidLoadNib. This method is called after an individual instance of MyDocument is created and the NIB file for it is loaded. Since this method is called at the creation of the MyDocument object, and after the WebView was created by loading the NIB file, the windowControllerDidLoadNib method is an appropriate place to set up our UIDelegate (as well as other delegates later).

The next step is to add an accessor method to MyDocument so we can access the private webView object. First, add the prototype for the method:


- (id)webView;

after the prototype for the "connectURL" method. Then at the end of the implementation file add the actual method:


 - (id)webView
{
    return webView;
}

Once that is done, it is time to implement the two methods that WebView's UIDelegates uses when JavaScript makes new window requests: createWebViewWithRequest and showWebView methods.


- (WebView *)webView:(WebView *)sender 
	    createWebViewWithRequest:
	    (NSURLRequest *)request
{
    id myDocument = [
	    [NSDocumentController 
		sharedDocumentController] 
	    openUntitledDocumentOfType:
		@"DocumentType" 
	    display:YES];

    [[[myDocument webView] mainFrame] 
		loadRequest:request];
    
    return [myDocument webView];
}

- (void)webViewShow:(WebView *)sender
{
    id myDocument = [[NSDocumentController 
			sharedDocumentController] 
			documentForWindow:
			    [sender window]];
    [myDocument showWindows];
}

The first method is called when a new window request is made and it creates a new MyDocument and returns its WebView object so the WebView object can process the URL request. The second method looks up the window for the MyDocument object and displays it on the screen.

Pages: 1, 2, 3

Next Pagearrow