Skip to content

Instantly share code, notes, and snippets.

@chandlerkent
Created July 9, 2011 04:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chandlerkent/1073316 to your computer and use it in GitHub Desktop.
Save chandlerkent/1073316 to your computer and use it in GitHub Desktop.
@import <Foundation/CPObject.j>
@import <Foundation/CPNotificationCenter.j>
@import <Foundation/CPURL.j>
@import <AppKit/CPToolbar.j>
@import <AppKit/CPCursor.j>
@import "CKToolbarDelegate.j"
@import "CKGitHubController.j"
@import "CKGistController.j"
@import "CKMainView.j"
@import "CKPreviewView.j"
@implementation AppController : CPObject
{
CPString gistId;
CPToolbar toolbar;
CPWindow mainWindow;
CPWindow previewWindow;
CKMainView mainView;
CKPreviewView previewView;
CKGistController gistController;
}
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
gistController = [[CKGistController alloc] init];
[[gistController fileController] setDelegate:self];
gistId = [[[CPApplication sharedApplication] namedArguments] objectForKey:@"g"];
if (gistId)
{
[CKGitHubController getGistById:gistId withCallback:function(data)
{
[gistController setCurrentGist:data];
}];
}
else
{
}
alert("HERE");
[self setupUserInterface];
[self registerForNotifications];
}
- (void)setupUserInterface
{
mainWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask];
var contentView = [mainWindow contentView];
toolbar = [[CPToolbar alloc] initWithIdentifier:@"MainToolbar"];
[toolbar setDelegate:[[CKToolbarDelegate alloc] init]];
[mainWindow setToolbar:toolbar];
mainView = [[CKMainView alloc] initWithFrame:[contentView bounds]];
[mainView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[[mainView outlineView] setDataSource:[gistController fileController]];
[[mainView outlineView] setDelegate:[gistController fileController]];
[contentView addSubview:mainView];
[mainWindow orderFront:self];
}
- (void)registerForNotifications
{
[[CPNotificationCenter defaultCenter]
addObserver:self
selector:@selector(frameworkVersionsDidLoad:)
name:CKToolbarDelegateDidLoadFrameworksVersionsNotification
object:nil];
[[CPNotificationCenter defaultCenter]
addObserver:self
selector:@selector(didClickPreview:)
name:CKToolbarDelegateDidClickPreviewNotification
object:nil];
}
@end
@implementation AppController(CKFileControllerDelegate)
- (void)outlineView:(CPOutlineView)outlineView didSelectItem:(CKFile)file
{
[[mainView textView] setStringValue:(file ? [file content] : @"")];
[[mainView textView] setEditable:(file ? YES : NO)];
[[mainView textView] setEnabled:(file ? YES : NO)];
}
- (void)didRefreshFiles
{
[[mainView outlineView] reloadData];
}
@end
@implementation AppController (CKPreviewViewDelegate)
- (void)didCancelPreview:(CKPreviewView)aPreviewView
{
[previewWindow orderOut:self];
}
- (void)previewDidFinishLoadingWithWindow:(DOMWindow)win
{
var cached = win.ObjectiveJ.StaticResource.prototype.resolve;
win.ObjectiveJ.StaticResource.prototype.resolve = function()
{
if (this.isDirectory())
{
cached.apply(this, arguments);
return;
}
var filename = this.URL().absoluteString().replace(win.location.href, "");
var file = [[gistController fileController] fileWithName:filename];
if (file)
{
this._contents = [file content];
resolveStaticResource(this);
}
else
{
cached.apply(this, arguments);
}
};
}
@end
@implementation AppController (Notifications)
- (void)frameworkVersionsDidLoad:(CPNotification)notification
{
// FIXME: relies on private method
[toolbar _reloadToolbarItems];
}
- (void)didClickPreview:(CPNotification)notification
{
if (!previewWindow)
{
previewWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask];
}
if (!previewView)
{
previewView = [[CKPreviewView alloc] initWithFrame:[mainView bounds]];
[previewView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[previewView setDelegate:self];
[previewWindow setContentView:previewView];
}
var version = [[notification object] selectedFrameworkVersion];
[previewView previewURL:[CPURL URLWithString:[CPString stringWithFormat:@"/view/%s/%s/", version, gistId]]];
[previewWindow orderFront:self];
}
@end
function resolveStaticResource(aResource)
{
aResource._isResolved = YES;
aResource._eventDispatcher.dispatchEvent(
{
type:"resolve",
staticResource:aResource
});
}
@import <Foundation/CPObject.j>
@import "CKURLConnection.j"
var API_BASE_URL = "api";
@implementation CKAPIController : CPObject
+ (void)getFrameworkVersionsWithCallback:(Function)cb
{
var request = [CPURLRequest requestWithURL:[CPURL URLWithString:[CPString stringWithFormat:@"/%s/%s", API_BASE_URL, @"frameworks"]]];
[request setHTTPMethod:@"GET"];
var connection = [CKURLConnection connectionWithRequest:request callback:cb];
[connection start];
}
@end
@import <Foundation/CPObject.j>
@import "CKURLConnection.j"
var API_BASE_URL = "api";
@implementation CKAPIController : CPObject
+ (void)getFrameworkVersionsWithCallback:(Function)cb
{
var request = [CPURLRequest requestWithURL:[CPURL URLWithString:[CPString stringWithFormat:@"/%s/%s", API_BASE_URL, @"frameworks"]]];
[request setHTTPMethod:@"GET"];
var connection = [CKURLConnection connectionWithRequest:request callback:cb];
[connection start];
}
@end
@import <Foundation/CPObject.j>
@import <Foundation/CPURL.j>
@implementation CKFile : CPObject
{
CPString name @accessors;
CPString content @accessors;
CPURL rawUrl @accessors;
int size @accessors;
}
+ (CKFile)fileFromGistFile:(JSObject)gistFile
{
var file = [[CKFile alloc] initWithName:gistFile.filename content:gistFile.content];
[file setRawUrl:[CPURL URLWithString:gistFile.raw_url]];
[file setSize:gistFile.size];
return file;
}
- (id)initWithName:(CPString)aName content:(CPString)someContent
{
self = [super init];
if(self)
{
name = aName;
content = someContent;
}
return self;
}
@end
@import <Foundation/CPObject.j>
@import <Foundation/CPURL.j>
@implementation CKFile : CPObject
{
CPString name @accessors;
CPString content @accessors;
CPURL rawUrl @accessors;
int size @accessors;
}
+ (CKFile)fileFromGistFile:(JSObject)gistFile
{
var file = [[CKFile alloc] initWithName:gistFile.filename content:gistFile.content];
[file setRawUrl:[CPURL URLWithString:gistFile.raw_url]];
[file setSize:gistFile.size];
return file;
}
- (id)initWithName:(CPString)aName content:(CPString)someContent
{
self = [super init];
if(self)
{
name = aName;
content = someContent;
}
return self;
}
@end
@import <Foundation/CPObject.j>
@import <Foundation/CPNotificationCenter.j>
@import "CKFile.j"
@import "CKGitHubController.j"
@implementation CKFileController : CPObject
{
CPArray files;
CKFile selectedFile;
id delegate @accessors;
}
- (id)init
{
self = [super init];
if(self)
{
files = [];
[self registerForNotifications];
}
return self;
}
- (void)registerForNotifications
{
[[CPNotificationCenter defaultCenter]
addObserver:self
selector:@selector(fileDidChange:)
name:CPControlTextDidChangeNotification
object:nil];
}
- (void)setFiles:(CPArray)someFiles
{
files = someFiles;
if ([[self delegate] respondsToSelector:@selector(didRefreshFiles)])
{
[[self delegate] didRefreshFiles];
}
}
- (CKFile)fileWithName:(CPString)aName
{
for (var i = 0; i < files.length; i++)
{
var file = files[i];
if ([file name] === aName)
{
return file;
}
}
return nil;
}
- (JSObject)jsonForFiles
{
var json = { files: {} };
for (var i = 0; i < files.length; i++)
{
var file = files[i];
json.files[[file name]] = {
"content": [file content]
};
}
return json;
}
@end
@implementation CKFileController(CPOutlineViewDataSource)
- (id)outlineView:(CPOutlineView)outlineView child:(int)index ofItem:(id)item
{
if (item === nil)
{
return [files objectAtIndex:index];
}
else
{
return nil;
}
}
- (BOOL)outlineView:(CPOutlineView)outlineView isItemExpandable:(id)item
{
return false;
}
- (int)outlineView:(CPOutlineView)outlineView numberOfChildrenOfItem:(id)item
{
if (item === nil)
{
return [files count];
}
else
{
return 0;
}
}
- (id)outlineView:(CPOutlineView)outlineView objectValueForTableColumn:(CPTableColumn)tableColumn byItem:(id)item
{
return [item name];
}
@end
@implementation CKFileController(CPOutlineViewDelegate)
- (void)outlineViewSelectionDidChange:(CPNotification)notification
{
if ([[self delegate] respondsToSelector:@selector(outlineView:didSelectItem:)])
{
var outlineView = [notification object];
var selectedIndex = [outlineView selectedRow];
selectedFile = (selectedIndex < 0 ? nil : [files objectAtIndex:selectedIndex]);
[[self delegate] outlineView:outlineView didSelectItem:selectedFile];
}
}
@end
@implementation CKFileController (LPMultilineTextFieldTarget)
- (void)fileDidChange:(CPNotification)note
{
if (![[note object] isKindOfClass:CPClassFromString(@"LPMultiLineTextField")])
return;
[selectedFile setContent:[[note object] stringValue]];
}
@end
@import <Foundation/CPObject.j>
@import <Foundation/CPNotificationCenter.j>
@import "CKFile.j"
@import "CKGitHubController.j"
@implementation CKFileController : CPObject
{
CPArray files;
CKFile selectedFile;
id delegate @accessors;
}
- (id)init
{
self = [super init];
if(self)
{
files = [];
[self registerForNotifications];
}
return self;
}
- (void)registerForNotifications
{
[[CPNotificationCenter defaultCenter]
addObserver:self
selector:@selector(fileDidChange:)
name:CPControlTextDidChangeNotification
object:nil];
}
- (void)setFiles:(CPArray)someFiles
{
files = someFiles;
if ([[self delegate] respondsToSelector:@selector(didRefreshFiles)])
{
[[self delegate] didRefreshFiles];
}
}
- (CKFile)fileWithName:(CPString)aName
{
for (var i = 0; i < files.length; i++)
{
var file = files[i];
if ([file name] === aName)
{
return file;
}
}
return nil;
}
- (JSObject)jsonForFiles
{
var json = { files: {} };
for (var i = 0; i < files.length; i++)
{
var file = files[i];
json.files[[file name]] = {
"content": [file content]
};
}
return json;
}
@end
@implementation CKFileController(CPOutlineViewDataSource)
- (id)outlineView:(CPOutlineView)outlineView child:(int)index ofItem:(id)item
{
if (item === nil)
{
return [files objectAtIndex:index];
}
else
{
return nil;
}
}
- (BOOL)outlineView:(CPOutlineView)outlineView isItemExpandable:(id)item
{
return false;
}
- (int)outlineView:(CPOutlineView)outlineView numberOfChildrenOfItem:(id)item
{
if (item === nil)
{
return [files count];
}
else
{
return 0;
}
}
- (id)outlineView:(CPOutlineView)outlineView objectValueForTableColumn:(CPTableColumn)tableColumn byItem:(id)item
{
return [item name];
}
@end
@implementation CKFileController(CPOutlineViewDelegate)
- (void)outlineViewSelectionDidChange:(CPNotification)notification
{
if ([[self delegate] respondsToSelector:@selector(outlineView:didSelectItem:)])
{
var outlineView = [notification object];
var selectedIndex = [outlineView selectedRow];
selectedFile = (selectedIndex < 0 ? nil : [files objectAtIndex:selectedIndex]);
[[self delegate] outlineView:outlineView didSelectItem:selectedFile];
}
}
@end
@implementation CKFileController (LPMultilineTextFieldTarget)
- (void)fileDidChange:(CPNotification)note
{
if (![[note object] isKindOfClass:CPClassFromString(@"LPMultiLineTextField")])
return;
[selectedFile setContent:[[note object] stringValue]];
}
@end
@import <Foundation/CPObject.j>
@import "CKFileController.j"
@implementation CKGistController : CPObject
{
CPString currentGistId @accessors;
CKFileController fileController @accessors;
}
- (id)init
{
self = [super init];
if (self)
{
fileController = [[CKFileController alloc] init];
[self registerForNotifications];
}
return self;
}
- (void)registerForNotifications
{
[[CPNotificationCenter defaultCenter]
addObserver:self
selector:@selector(saveFiles:)
name:CKToolbarDelegateDidClickSaveNotification
object:nil];
}
- (void)setCurrentGist:(JSObject)gist
{
[self setCurrentGistId:gist.id];
var files = [];
for (var file in gist.files)
{
[files addObject:[CKFile fileFromGistFile:gist.files[file]]];
}
[fileController setFiles:files];
}
- (void)saveFiles:(CPNotification)note
{
[CKGitHubController updateGistById:[self currentGistId] data:[fileController jsonForFiles] callback:function()
{
console.log("SAVED!?");
}];
}
@end
@import <Foundation/CPObject.j>
@import "CKFileController.j"
@implementation CKGistController : CPObject
{
CPString currentGistId @accessors;
CKFileController fileController @accessors;
}
- (id)init
{
self = [super init];
if (self)
{
fileController = [[CKFileController alloc] init];
[self registerForNotifications];
}
return self;
}
- (void)registerForNotifications
{
[[CPNotificationCenter defaultCenter]
addObserver:self
selector:@selector(saveFiles:)
name:CKToolbarDelegateDidClickSaveNotification
object:nil];
}
- (void)setCurrentGist:(JSObject)gist
{
[self setCurrentGistId:gist.id];
var files = [];
for (var file in gist.files)
{
[files addObject:[CKFile fileFromGistFile:gist.files[file]]];
}
[fileController setFiles:files];
}
- (void)saveFiles:(CPNotification)note
{
[CKGitHubController updateGistById:[self currentGistId] data:[fileController jsonForFiles] callback:function()
{
console.log("SAVED!?");
}];
}
@end
@import <Foundation/CPObject.j>
@import "CKURLConnection.j"
var GITHUB_BASE_URL = "github";
@implementation CKGitHubController : CPObject
+ (void)getGistById:(CPString)gistId withCallback:(Function)callback
{
var request = [CPURLRequest requestWithURL:[CPURL URLWithString:[CPString stringWithFormat:@"/%s/gists/%s", GITHUB_BASE_URL, gistId]]];
[request setHTTPMethod:@"GET"];
var connection = [CKURLConnection connectionWithRequest:request callback:callback];
[connection start];
}
+ (void)updateGistById:(CPString)gistId data:(JSObject)gist callback:(Function)cb
{
var request = [CPURLRequest requestWithURL:[CPURL URLWithString:[CPString stringWithFormat:@"/%s/gists/%s", GITHUB_BASE_URL, gistId]]];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:JSON.stringify(gist)];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"content-type"];
var connection = [CKURLConnection connectionWithRequest:request callback:cb];
[connection start];
}
@end
@import <Foundation/CPObject.j>
@import "CKURLConnection.j"
var GITHUB_BASE_URL = "github";
@implementation CKGitHubController : CPObject
+ (void)getGistById:(CPString)gistId withCallback:(Function)callback
{
var request = [CPURLRequest requestWithURL:[CPURL URLWithString:[CPString stringWithFormat:@"/%s/gists/%s", GITHUB_BASE_URL, gistId]]];
[request setHTTPMethod:@"GET"];
var connection = [CKURLConnection connectionWithRequest:request callback:callback];
[connection start];
}
+ (void)updateGistById:(CPString)gistId data:(JSObject)gist callback:(Function)cb
{
var request = [CPURLRequest requestWithURL:[CPURL URLWithString:[CPString stringWithFormat:@"/%s/gists/%s", GITHUB_BASE_URL, gistId]]];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:JSON.stringify(gist)];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"content-type"];
var connection = [CKURLConnection connectionWithRequest:request callback:cb];
[connection start];
}
@end
@import <AppKit/CPView.j>
@import <AppKit/CPSplitView.j>
@import <AppKit/CPColor.j>
@import <AppKit/CPScrollView.j>
@import <AppKit/CPOutlineView.j>
@import "LPMultiLineTextField.j"
@implementation CKMainView : CPView
{
CPSplitView splitView @accessors;
CPOutlineView outlineView @accessors;
LPMultiLineTextField textView @accessors;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
splitView = [[CPSplitView alloc] initWithFrame:aFrame];
[splitView setIsPaneSplitter:NO];
[splitView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
var leftScrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(0, 0, 200, CGRectGetHeight(aFrame))];
[leftScrollView setAutohidesScrollers:YES];
[leftScrollView setHasHorizontalScroller:NO];
var onlyColumn = [[CPTableColumn alloc] initWithIdentifier:@"Only Column"];
[onlyColumn setWidth:200];
outlineView = [[CPOutlineView alloc] initWithFrame:[leftScrollView bounds]];
[outlineView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[outlineView addTableColumn:onlyColumn];
[outlineView setOutlineTableColumn:onlyColumn];
[outlineView setColumnAutoresizingStyle:CPTableViewLastColumnOnlyAutoresizingStyle];
[outlineView setHeaderView:nil];
[outlineView setCornerView:nil];
[outlineView setBackgroundColor:[CPColor colorWithHexString:@"e0ecfa"]];
[leftScrollView setDocumentView:outlineView];
[splitView addSubview:leftScrollView];
textView = [[LPMultiLineTextField alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(aFrame) - CGRectGetWidth([leftScrollView bounds]), CGRectGetHeight(aFrame))];
[textView setEditable:NO];
[splitView addSubview:textView];
[self addSubview:splitView];
}
return self;
}
@end
@import <AppKit/CPView.j>
@import <AppKit/CPSplitView.j>
@import <AppKit/CPColor.j>
@import <AppKit/CPScrollView.j>
@import <AppKit/CPOutlineView.j>
@import "LPMultiLineTextField.j"
@implementation CKMainView : CPView
{
CPSplitView splitView @accessors;
CPOutlineView outlineView @accessors;
LPMultiLineTextField textView @accessors;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
splitView = [[CPSplitView alloc] initWithFrame:aFrame];
[splitView setIsPaneSplitter:NO];
[splitView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
var leftScrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(0, 0, 200, CGRectGetHeight(aFrame))];
[leftScrollView setAutohidesScrollers:YES];
[leftScrollView setHasHorizontalScroller:NO];
var onlyColumn = [[CPTableColumn alloc] initWithIdentifier:@"Only Column"];
[onlyColumn setWidth:200];
outlineView = [[CPOutlineView alloc] initWithFrame:[leftScrollView bounds]];
[outlineView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[outlineView addTableColumn:onlyColumn];
[outlineView setOutlineTableColumn:onlyColumn];
[outlineView setColumnAutoresizingStyle:CPTableViewLastColumnOnlyAutoresizingStyle];
[outlineView setHeaderView:nil];
[outlineView setCornerView:nil];
[outlineView setBackgroundColor:[CPColor colorWithHexString:@"e0ecfa"]];
[leftScrollView setDocumentView:outlineView];
[splitView addSubview:leftScrollView];
textView = [[LPMultiLineTextField alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(aFrame) - CGRectGetWidth([leftScrollView bounds]), CGRectGetHeight(aFrame))];
[textView setEditable:NO];
[splitView addSubview:textView];
[self addSubview:splitView];
}
return self;
}
@end
@import <Foundation/CPObject.j>
@import <Foundation/CPNotificationCenter.j>
@implementation CKPreviewController : CPObject
{
id delegate @accessors;
}
- (id)init
{
self = [super init];
if (self)
{
[self registerForNotifications];
}
return self;
}
- (void)registerForNotifications
{
[[CPNotificationCenter defaultCenter]
registerObserver:self
selector:@selector(didClickPreview:)
name:CKToolbarDelegateDidClickPreviewNotification
object:nil];
}
@end
@implementation CKPreviewController (Notifications)
- (void)didClickPreview:(CPNotification)notification
{
// Send someSelector: to [self delegate], if [self delegate] supports it
if ([[self delegate] respondsToSelector:@selector(someSelector:)])
{
[[self delegate] someSelector:<>];
}
}
@end
@import <Foundation/CPObject.j>
@import <Foundation/CPNotificationCenter.j>
@implementation CKPreviewController : CPObject
{
id delegate @accessors;
}
- (id)init
{
self = [super init];
if (self)
{
[self registerForNotifications];
}
return self;
}
- (void)registerForNotifications
{
[[CPNotificationCenter defaultCenter]
registerObserver:self
selector:@selector(didClickPreview:)
name:CKToolbarDelegateDidClickPreviewNotification
object:nil];
}
@end
@implementation CKPreviewController (Notifications)
- (void)didClickPreview:(CPNotification)notification
{
// Send someSelector: to [self delegate], if [self delegate] supports it
if ([[self delegate] respondsToSelector:@selector(someSelector:)])
{
[[self delegate] someSelector:<>];
}
}
@end
@import <AppKit/CPView.j>
@import <AppKit/CPWebView.j>
@import <AppKit/CPColor.j>
@implementation CKPreviewView : CPView
{
CPWebView webView;
id delegate @accessors;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
webView = [[CPWebView alloc] initWithFrame:CGRectInset(aFrame, 30, 30)];
[webView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[webView setFrameLoadDelegate:self];
[self addSubview:webView];
[self setBackgroundColor:[CPColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8]];
}
return self;
}
- (void)previewURL:(CPURL)aURL
{
[webView setMainFrameURL:[aURL absoluteString]];
}
- (void)mouseDown:(CPEvent)anEvent
{
[super mouseDown:anEvent];
if ([[self delegate] respondsToSelector:@selector(didCancelPreview:)])
{
[[self delegate] didCancelPreview:self];
}
}
@end
@implementation CKPreviewView (CPWebViewFrameLoadDelegate)
- (void)webView:(CPWebView)aWebView didFinishLoadForFrame:()aFrame
{
// Send previewDidFinishLoadingWithWindow: to [self delegate], if [self delegate] supports it
if ([[self delegate] respondsToSelector:@selector(previewDidFinishLoadingWithWindow:)])
{
[[self delegate] previewDidFinishLoadingWithWindow:[webView DOMWindow]];
}
}
@end
@import <AppKit/CPView.j>
@import <AppKit/CPWebView.j>
@import <AppKit/CPColor.j>
@implementation CKPreviewView : CPView
{
CPWebView webView;
id delegate @accessors;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
webView = [[CPWebView alloc] initWithFrame:CGRectInset(aFrame, 30, 30)];
[webView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[webView setFrameLoadDelegate:self];
[self addSubview:webView];
[self setBackgroundColor:[CPColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8]];
}
return self;
}
- (void)previewURL:(CPURL)aURL
{
[webView setMainFrameURL:[aURL absoluteString]];
}
- (void)mouseDown:(CPEvent)anEvent
{
[super mouseDown:anEvent];
if ([[self delegate] respondsToSelector:@selector(didCancelPreview:)])
{
[[self delegate] didCancelPreview:self];
}
}
@end
@implementation CKPreviewView (CPWebViewFrameLoadDelegate)
- (void)webView:(CPWebView)aWebView didFinishLoadForFrame:()aFrame
{
// Send previewDidFinishLoadingWithWindow: to [self delegate], if [self delegate] supports it
if ([[self delegate] respondsToSelector:@selector(previewDidFinishLoadingWithWindow:)])
{
[[self delegate] previewDidFinishLoadingWithWindow:[webView DOMWindow]];
}
}
@end
@import <Foundation/CPObject.j>
@import <Foundation/CPNotificationCenter.j>
@import <AppKit/CPPopUpButton.j>
@import "CKAPIController.j"
// Toolbar Items
var CKSelectFrameworkToolbarItemIdentifier = @"Select Framework Version";
var CKPreviewToolbarItemIdentifier = @"Preview";
var CKSaveToolbarItemIdentifier = @"Save";
// Notifications
CKToolbarDelegateDidClickPreviewNotification = @"CKToolbarDelegateDidClickPreviewNotification";
CKToolbarDelegateDidLoadFrameworksVersionsNotification = @"CKToolbarDelegateDidLoadFrameworksVersionsNotification";
CKToolbarDelegateDidClickSaveNotification = @"CKToolbarDelegateDidClickSaveNotification";
@implementation CKToolbarDelegate : CPObject
{
CPPopUpButton frameworkButton;
}
- (CKToolbarDelegate)init
{
if (self = [super init])
{
frameworkButton = [[CPPopUpButton alloc] initWithFrame:CPRectMake(0, 0, 140, 24)];
[self populateFrameworkButton];
}
return self;
}
- (CPArray)toolbarDefaultItemIdentifiers:(CPToolbar)aToolbar
{
return [CKPreviewToolbarItemIdentifier, CKSaveToolbarItemIdentifier, CPToolbarFlexibleSpaceItemIdentifier, CKSelectFrameworkToolbarItemIdentifier];
}
- (CPArray)toolbarAllowedItemIdentifiers:(CPToolbar)aToolbar
{
return [self toolbarDefaultItemIdentifiers:aToolbar];
}
- (CPToolbarItem)toolbar:(CPToolbar)aToolbar itemForItemIdentifier:(CPString)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
{
var toolbarItem = nil;
if (itemIdentifier === CKSelectFrameworkToolbarItemIdentifier)
{
var rect = [frameworkButton frame];
toolbarItem = [[CPToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
[toolbarItem setLabel:@"Framework"];
[toolbarItem setView:frameworkButton];
[toolbarItem setMinSize:rect.size];
[toolbarItem setMaxSize:rect.size];
}
else if (itemIdentifier === CKPreviewToolbarItemIdentifier)
{
toolbarItem = [[CPToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
[toolbarItem setLabel:@"Preview"];
[toolbarItem setMinSize:CGSizeMake(120, 32)];
[toolbarItem setMaxSize:CGSizeMake(120, 32)];
[toolbarItem setTarget:self];
[toolbarItem setAction:@selector(preview:)];
}
else if (itemIdentifier === CKSaveToolbarItemIdentifier)
{
toolbarItem = [[CPToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
[toolbarItem setLabel:@"Save"];
[toolbarItem setMinSize:CGSizeMake(120, 32)];
[toolbarItem setMaxSize:CGSizeMake(120, 32)];
[toolbarItem setTarget:self];
[toolbarItem setAction:@selector(save:)];
}
return toolbarItem;
}
- (CPString)selectedFrameworkVersion
{
return [frameworkButton titleOfSelectedItem];
}
- (void)preview:(id)sender
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CKToolbarDelegateDidClickPreviewNotification
object:self];
}
- (void)save:(id)sender
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CKToolbarDelegateDidClickSaveNotification
object:self];
}
- (void)populateFrameworkButton
{
[CKAPIController getFrameworkVersionsWithCallback:function(data)
{
if (!data.ok)
{
return;
}
[frameworkButton addItemsWithTitles:data.versions];
[[CPNotificationCenter defaultCenter]
postNotificationName:CKToolbarDelegateDidLoadFrameworksVersionsNotification
object:self];
}];
}
@end
@import <Foundation/CPURLConnection.j>
@import <Foundation/CPObject.j>
@import <Foundation/CPURLRequest.j>
@implementation CKURLConnection : CPURLConnection
+ (CKURLConnection)connectionWithRequest:(CPURLRequest)request callback:(Function)cb
{
var connection = [CKURLConnection connectionWithRequest:request delegate:[_CKURLConnectionDelegate sharedConnectionDelegate]];
[[_CKURLConnectionDelegate sharedConnectionDelegate] setCallback:cb forConnection:connection];
return connection;
}
@end
var _CKURLConnectionDelegateObject = nil;
@implementation _CKURLConnectionDelegate : CPObject
{
CPDictionary connections;
}
+ (_CKURLConnectionDelegate)sharedConnectionDelegate
{
if (!_CKURLConnectionDelegateObject)
{
_CKURLConnectionDelegateObject = [[_CKURLConnectionDelegate alloc] _init];
}
return _CKURLConnectionDelegateObject;
}
+ (JSObject)buildConnectionObjectWithCallback:(Function)cb data:(CPString)data
{
return {
"callback": cb,
"data": data || "",
"response": nil
};
}
- (id)_init
{
self = [super init];
if (self)
{
connections = [CPDictionary new];
}
return self;
}
- (void)setCallback:(Function)cb forConnection:(CPURLConnection)connection
{
[connections setObject:[_CKURLConnectionDelegate buildConnectionObjectWithCallback:cb data:nil] forKey:connection];
}
- (void)connection:(CPURLConnection)connection didReceiveResponse:(CPHTTPURLResponse)response
{
var obj = [connections objectForKey:connection];
obj.response = response;
}
-(void)connection:(CPURLConnection)connection didReceiveData:(CPString)data
{
var obj = [connections objectForKey:connection];
obj.data = JSON.parse(data);
}
- (void)connectionDidFinishLoading:(CPURLConnection)connection
{
var obj = [connections objectForKey:connection];
obj.callback(obj.data);
[connections removeObjectForKey:connection];
}
@end
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CPApplicationDelegateClass</key>
<string>AppController</string>
<key>CPBundleName</key>
<string>Test</string>
<key>CPPrincipalClass</key>
<string>CPApplication</string>
</dict>
</plist>
/*
* LPMultiLineTextField.j
*
* Created by Ludwig Pettersson on January 22, 2010.
*
* The MIT License
*
* Copyright (c) 2010 Ludwig Pettersson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
@import <AppKit/CPTextField.j>
var CPTextFieldInputOwner = nil;
@implementation LPMultiLineTextField : CPTextField
{
id _DOMTextareaElement;
CPString _stringValue;
}
- (DOMElement)_DOMTextareaElement
{
if (!_DOMTextareaElement)
{
_DOMTextareaElement = document.createElement("textarea");
_DOMTextareaElement.style.position = @"absolute";
_DOMTextareaElement.style.background = @"none";
_DOMTextareaElement.style.border = @"0";
_DOMTextareaElement.style.outline = @"0";
_DOMTextareaElement.style.zIndex = @"100";
_DOMTextareaElement.style.resize = @"none";
_DOMTextareaElement.style.padding = @"0";
_DOMTextareaElement.style.margin = @"0";
_DOMTextareaElement.onblur = function(){
[[CPTextFieldInputOwner window] makeFirstResponder:nil];
CPTextFieldInputOwner = nil;
};
self._DOMElement.appendChild(_DOMTextareaElement);
}
return _DOMTextareaElement;
}
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
}
return self;
}
- (void)setEditable:(BOOL)shouldBeEditable
{
[self _DOMTextareaElement].style.cursor = shouldBeEditable ? @"cursor" : @"default";
[super setEditable:shouldBeEditable];
}
- (void)selectText:(id)sender
{
[self _DOMTextareaElement].select();
}
- (void)layoutSubviews
{
[super layoutSubviews];
var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"bezel-view"];
[contentView setHidden:YES];
var DOMElement = [self _DOMTextareaElement],
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
bounds = [self bounds];
DOMElement.style.top = contentInset.top + @"px";
DOMElement.style.bottom = contentInset.bottom + @"px";
DOMElement.style.left = contentInset.left + @"px";
DOMElement.style.right = contentInset.right + @"px";
DOMElement.style.width = (CGRectGetWidth(bounds) - contentInset.left - contentInset.right) + @"px";
DOMElement.style.height = (CGRectGetHeight(bounds) - contentInset.top - contentInset.bottom) + @"px";
DOMElement.style.color = [[self currentValueForThemeAttribute:@"text-color"] cssString];
DOMElement.style.font = [[self currentValueForThemeAttribute:@"font"] cssString];
DOMElement.value = _stringValue || @"";
}
- (void)mouseDown:(CPEvent)anEvent
{
if ([self isEditable] && [self isEnabled])
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
else
[super mouseDown:anEvent];
}
- (void)mouseDragged:(CPEvent)anEvent
{
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
}
- (void)keyDown:(CPEvent)anEvent
{
if ([anEvent keyCode] === CPTabKeyCode)
{
if ([anEvent modifierFlags] & CPShiftKeyMask)
[[self window] selectPreviousKeyView:self];
else
[[self window] selectNextKeyView:self];
if ([[[self window] firstResponder] respondsToSelector:@selector(selectText:)])
[[[self window] firstResponder] selectText:self];
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
}
else
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
- (void)keyUp:(CPEvent)anEvent
{
if (_stringValue !== [self stringValue])
{
_stringValue = [self stringValue];
if (!_isEditing)
{
_isEditing = YES;
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
}
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
}
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
}
- (BOOL)becomeFirstResponder
{
_stringValue = [self stringValue];
[self setThemeState:CPThemeStateEditing];
setTimeout(function(){
[self _DOMTextareaElement].focus();
CPTextFieldInputOwner = self;
}, 0.0);
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
return YES;
}
- (BOOL)resignFirstResponder
{
[self unsetThemeState:CPThemeStateEditing];
[self setStringValue:[self stringValue]];
[self _DOMTextareaElement].blur();
//post CPControlTextDidEndEditingNotification
if (_isEditing)
{
_isEditing = NO;
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
if ([self sendsActionOnEndEditing])
[self sendAction:[self action] to:[self target]];
}
[self textDidBlur:[CPNotification notificationWithName:CPTextFieldDidBlurNotification object:self userInfo:nil]];
return YES;
}
- (CPString)stringValue
{
return (!!_DOMTextareaElement) ? _DOMTextareaElement.value : @"";
}
- (void)setStringValue:(CPString)aString
{
_stringValue = aString;
[self setNeedsLayout];
}
@end
/*
* LPMultiLineTextField.j
*
* Created by Ludwig Pettersson on January 22, 2010.
*
* The MIT License
*
* Copyright (c) 2010 Ludwig Pettersson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
@import <AppKit/CPTextField.j>
var CPTextFieldInputOwner = nil;
@implementation LPMultiLineTextField : CPTextField
{
id _DOMTextareaElement;
CPString _stringValue;
}
- (DOMElement)_DOMTextareaElement
{
if (!_DOMTextareaElement)
{
_DOMTextareaElement = document.createElement("textarea");
_DOMTextareaElement.style.position = @"absolute";
_DOMTextareaElement.style.background = @"none";
_DOMTextareaElement.style.border = @"0";
_DOMTextareaElement.style.outline = @"0";
_DOMTextareaElement.style.zIndex = @"100";
_DOMTextareaElement.style.resize = @"none";
_DOMTextareaElement.style.padding = @"0";
_DOMTextareaElement.style.margin = @"0";
_DOMTextareaElement.onblur = function(){
[[CPTextFieldInputOwner window] makeFirstResponder:nil];
CPTextFieldInputOwner = nil;
};
self._DOMElement.appendChild(_DOMTextareaElement);
}
return _DOMTextareaElement;
}
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
}
return self;
}
- (void)setEditable:(BOOL)shouldBeEditable
{
[self _DOMTextareaElement].style.cursor = shouldBeEditable ? @"cursor" : @"default";
[super setEditable:shouldBeEditable];
}
- (void)selectText:(id)sender
{
[self _DOMTextareaElement].select();
}
- (void)layoutSubviews
{
[super layoutSubviews];
var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"bezel-view"];
[contentView setHidden:YES];
var DOMElement = [self _DOMTextareaElement],
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
bounds = [self bounds];
DOMElement.style.top = contentInset.top + @"px";
DOMElement.style.bottom = contentInset.bottom + @"px";
DOMElement.style.left = contentInset.left + @"px";
DOMElement.style.right = contentInset.right + @"px";
DOMElement.style.width = (CGRectGetWidth(bounds) - contentInset.left - contentInset.right) + @"px";
DOMElement.style.height = (CGRectGetHeight(bounds) - contentInset.top - contentInset.bottom) + @"px";
DOMElement.style.color = [[self currentValueForThemeAttribute:@"text-color"] cssString];
DOMElement.style.font = [[self currentValueForThemeAttribute:@"font"] cssString];
DOMElement.value = _stringValue || @"";
}
- (void)mouseDown:(CPEvent)anEvent
{
if ([self isEditable] && [self isEnabled])
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
else
[super mouseDown:anEvent];
}
- (void)mouseDragged:(CPEvent)anEvent
{
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
}
- (void)keyDown:(CPEvent)anEvent
{
if ([anEvent keyCode] === CPTabKeyCode)
{
if ([anEvent modifierFlags] & CPShiftKeyMask)
[[self window] selectPreviousKeyView:self];
else
[[self window] selectNextKeyView:self];
if ([[[self window] firstResponder] respondsToSelector:@selector(selectText:)])
[[[self window] firstResponder] selectText:self];
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
}
else
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
- (void)keyUp:(CPEvent)anEvent
{
if (_stringValue !== [self stringValue])
{
_stringValue = [self stringValue];
if (!_isEditing)
{
_isEditing = YES;
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
}
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
}
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
}
- (BOOL)becomeFirstResponder
{
_stringValue = [self stringValue];
[self setThemeState:CPThemeStateEditing];
setTimeout(function(){
[self _DOMTextareaElement].focus();
CPTextFieldInputOwner = self;
}, 0.0);
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
return YES;
}
- (BOOL)resignFirstResponder
{
[self unsetThemeState:CPThemeStateEditing];
[self setStringValue:[self stringValue]];
[self _DOMTextareaElement].blur();
//post CPControlTextDidEndEditingNotification
if (_isEditing)
{
_isEditing = NO;
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
if ([self sendsActionOnEndEditing])
[self sendAction:[self action] to:[self target]];
}
[self textDidBlur:[CPNotification notificationWithName:CPTextFieldDidBlurNotification object:self userInfo:nil]];
return YES;
}
- (CPString)stringValue
{
return (!!_DOMTextareaElement) ? _DOMTextareaElement.value : @"";
}
- (void)setStringValue:(CPString)aString
{
_stringValue = aString;
[self setNeedsLayout];
}
@end
@import "AppController.j"
function main(args, namedArgs)
{
console.log("HELLO");
CPApplicationMain(args, namedArgs);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment