Files
gitx/PBWebHistoryController.m
T
Nathan Kinsinger 2b0c2b200a Retry loadCommit() script when it fails
Fixes a problem when opening a number of repos at once where the commit information does not show up. Get a webKit error "TypeError: Result of expression 'commit' [undefined] is not an object."

For some reason the callWebScriptMethod:withArguments: method returns nil (even after the webView:didFinishLoadForFrame: delegate is called) when the app is busy. Seems like the web view is not really ready yet and so it never actually calls loadCommit().

If we get nil (normally should get WebUndefined) then try changeContentTo: again after a little delay. This stops the loadCommitDetails() script from running before the commit object is created.
2010-03-13 22:16:06 -07:00

164 lines
5.1 KiB
Objective-C

//
// PBWebGitController.m
// GitTest
//
// Created by Pieter de Bie on 14-06-08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "PBWebHistoryController.h"
#import "PBGitDefaults.h"
@implementation PBWebHistoryController
@synthesize diff;
- (void) awakeFromNib
{
startFile = @"history";
repository = historyController.repository;
[super awakeFromNib];
[historyController addObserver:self forKeyPath:@"webCommit" options:0 context:@"ChangedCommit"];
}
- (void) didLoad
{
currentSha = @"";
[self changeContentTo: historyController.webCommit];
}
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([(NSString *)context isEqualToString: @"ChangedCommit"])
[self changeContentTo: historyController.webCommit];
else
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
- (void) changeContentTo: (PBGitCommit *) content
{
if (content == nil || !finishedLoading)
return;
// The sha is the same, but refs may have changed.. reload it lazy
if ([currentSha isEqualToString: [content realSha]])
{
[[self script] callWebScriptMethod:@"reload" withArguments: nil];
return;
}
NSArray *arguments = [NSArray arrayWithObjects:content, [[[historyController repository] headRef] simpleRef], nil];
id scriptResult = [[self script] callWebScriptMethod:@"loadCommit" withArguments: arguments];
if (!scriptResult) {
// the web view is not really ready for scripting???
[self performSelector:_cmd withObject:content afterDelay:0.05];
return;
}
currentSha = [content realSha];
// Now we load the extended details. We used to do this in a separate thread,
// but this caused some funny behaviour because NSTask's and NSThread's don't really
// like each other. Instead, just do it async.
NSMutableArray *taskArguments = [NSMutableArray arrayWithObjects:@"show", @"--pretty=raw", @"-M", @"--no-color", currentSha, nil];
if (![PBGitDefaults showWhitespaceDifferences])
[taskArguments insertObject:@"-w" atIndex:1];
NSFileHandle *handle = [repository handleForArguments:taskArguments];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
// Remove notification, in case we have another one running
[nc removeObserver:self];
[nc addObserver:self selector:@selector(commitDetailsLoaded:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle];
[handle readToEndOfFileInBackgroundAndNotify];
}
- (void)commitDetailsLoaded:(NSNotification *)notification
{
NSData *data = [[notification userInfo] valueForKey:NSFileHandleNotificationDataItem];
if (!data)
return;
NSString *details = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (!details)
details = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding];
if (!details)
return;
[[view windowScriptObject] callWebScriptMethod:@"loadCommitDetails" withArguments:[NSArray arrayWithObject:details]];
}
- (void) selectCommit: (NSString*) sha
{
[historyController selectCommit:sha];
}
- (void) sendKey: (NSString*) key
{
id script = [view windowScriptObject];
[script callWebScriptMethod:@"handleKeyFromCocoa" withArguments: [NSArray arrayWithObject:key]];
}
- (void) copySource
{
NSString *source = [(DOMHTMLElement *)[[[view mainFrame] DOMDocument] documentElement] outerHTML];
NSPasteboard *a =[NSPasteboard generalPasteboard];
[a declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:self];
[a setString:source forType: NSStringPboardType];
}
- (NSArray *) webView:(WebView *)sender
contextMenuItemsForElement:(NSDictionary *)element
defaultMenuItems:(NSArray *)defaultMenuItems
{
DOMNode *node = [element valueForKey:@"WebElementDOMNode"];
while (node) {
// Every ref has a class name of 'refs' and some other class. We check on that to see if we pressed on a ref.
if ([[node className] hasPrefix:@"refs "]) {
NSString *selectedRefString = [[[node childNodes] item:0] textContent];
for (PBGitRef *ref in historyController.webCommit.refs)
{
if ([[ref shortName] isEqualToString:selectedRefString])
return [contextMenuDelegate menuItemsForRef:ref];
}
NSLog(@"Could not find selected ref!");
return defaultMenuItems;
}
if ([node hasAttributes] && [[node attributes] getNamedItem:@"representedFile"])
return [historyController menuItemsForPaths:[NSArray arrayWithObject:[[[node attributes] getNamedItem:@"representedFile"] value]]];
node = [node parentNode];
}
return defaultMenuItems;
}
// Open external links in the default browser
- (void)webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)actionInformation
request:(NSURLRequest *)request
newFrameName:(NSString *)frameName
decisionListener:(id < WebPolicyDecisionListener >)listener
{
[[NSWorkspace sharedWorkspace] openURL:[request URL]];
}
- getConfig:(NSString *)config
{
return [historyController valueForKeyPath:[@"repository.config." stringByAppendingString:config]];
}
- (void) finalize
{
[historyController removeObserver:self forKeyPath:@"webCommit"];
[super finalize];
}
- (void) preferencesChanged
{
[[self script] callWebScriptMethod:@"enableFeatures" withArguments:nil];
}
@end