Merge branch 'jake' of git@github.com:280north/cappuccino into loader

This commit is contained in:
Francisco Ryan Tolmasky I
2010-01-29 17:53:36 -08:00
28 changed files with 366 additions and 326 deletions
+3
View File
@@ -735,6 +735,9 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
var hexCharacters = "0123456789ABCDEF";
// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior
var hexToRGB, integerToBytes, rgbToHex, byteToHex;
/*!
Used for the CPColor \c +colorWithHexString: implementation
@ignore
+10 -10
View File
@@ -30,7 +30,7 @@
*/
@implementation CPFlashMovie : CPObject
{
CPString _fileName;
CPString _filename;
}
/*!
@@ -38,9 +38,9 @@
@param aFilename the swf to load
@return the initialized CPFlashMovie
*/
+ (id)flashMovieWithFile:(CPString)aFileName
+ (id)flashMovieWithFile:(CPString)aFilename
{
return [[self alloc] initWithFile:aFileName];
return [[self alloc] initWithFile:aFilename];
}
/*!
@@ -48,37 +48,37 @@
@param aFilename the swf to load
@return the initialized CPFlashMovie
*/
- (id)initWithFile:(CPString)aFileName
- (id)initWithFile:(CPString)aFilename
{
self = [super init];
if (self)
_fileName = aFileName;
_filename = aFilename;
return self;
}
- (CPString)fileName
- (CPString)filename
{
return _fileName;
return _filename;
}
@end
var CPFlashMovieFileNameKey = "CPFlashMovieFileNameKey";
var CPFlashMovieFilenameKey = "CPFlashMovieFilenameKey";
@implementation CPFlashMovie (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
_fileName = [aCoder decodeObjectForKey:CPFlashMovieFileNameKey];
_filename = [aCoder decodeObjectForKey:CPFlashMovieFilenameKey];
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_fileName forKey:CPFlashMovieFileNameKey];
[aCoder encodeObject:_filename forKey:CPFlashMovieFilenameKey];
}
@end
+78 -59
View File
@@ -24,20 +24,21 @@
@import "CPView.j"
var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
/*!
@ingroup appkit
*/
@implementation CPFlashView : CPView
{
CPFlashMovie _flashMovie;
CPDictionary _flashVars;
CPDictionary _params;
CPDictionary _paramElements;
DOMElement _DOMEmbedElement;
DOMElement _DOMMParamElement;
DOMElement _DOMParamElement;
DOMElement _DOMObjectElement;
DOMElement _DOMInnerObjectElement;
}
- (id)initWithFrame:(CGRect)aFrame
@@ -46,35 +47,30 @@
if (self)
{
_DOMObjectElement = document.createElement("object");
_DOMObjectElement.width = "100%";
_DOMObjectElement.height = "100%";
_DOMObjectElement.style.top = "0px";
_DOMObjectElement.style.left = "0px";
_DOMParamElement = document.createElement("param");
_DOMParamElement.name = "movie";
_DOMObjectElement.appendChild(_DOMParamElement);
var param = document.createElement("param");
param.name = "wmode";
param.value = "transparent";
_DOMObjectElement.appendChild(param);
_DOMEmbedElement = document.createElement("embed");
_DOMEmbedElement.type = "application/x-shockwave-flash";
_DOMEmbedElement.setAttribute("wmode", "transparent");
_DOMEmbedElement.width = "100%";
_DOMEmbedElement.height = "100%";
// IE requires this thing to be in the _DOMElement and not the _DOMObjectElement.
_DOMElement.appendChild(_DOMEmbedElement);
_DOMElement.appendChild(_DOMObjectElement);
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
{
_DOMObjectElement = document.createElement(@"object");
_DOMObjectElement.width = @"100%";
_DOMObjectElement.height = @"100%";
_DOMObjectElement.style.top = @"0px";
_DOMObjectElement.style.left = @"0px";
_DOMObjectElement.type = @"application/x-shockwave-flash";
_DOMObjectElement.setAttribute(@"classid", IEFlashCLSID);
_DOMParamElement = document.createElement(@"param");
_DOMParamElement.name = @"movie";
_DOMInnerObjectElement = document.createElement(@"object");
_DOMInnerObjectElement.width = @"100%";
_DOMInnerObjectElement.height = @"100%";
_DOMObjectElement.appendChild(_DOMParamElement);
_DOMObjectElement.appendChild(_DOMInnerObjectElement);
_DOMElement.appendChild(_DOMObjectElement);
}
else
[self _rebuildIEObjects];
}
return self;
@@ -87,10 +83,13 @@
_flashMovie = aFlashMovie;
_DOMParamElement.value = aFlashMovie._fileName;
if (_DOMEmbedElement)
_DOMEmbedElement.src = aFlashMovie._fileName;
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
{
_DOMParamElement.value = [aFlashMovie filename];
_DOMInnerObjectElement.data = [aFlashMovie filename];
}
else
[self _rebuildIEObjects];
}
- (CPFlashMovie)flashMovie
@@ -100,33 +99,28 @@
- (void)setFlashVars:(CPDictionary)aDictionary
{
_flashVars = aDictionary;
var varString = @"",
enumerator = [_flashVars keyEnumerator];
enumerator = [aDictionary keyEnumerator];
var key;
while (key = [enumerator nextObject])
varString = [varString stringByAppendingFormat:@"&%@=%@", key, [_flashVars objectForKey:key]];
varString = [varString stringByAppendingFormat:@"&%@=%@", key, [aDictionary objectForKey:key]];
var param = document.createElement(@"param");
param.name = @"flashvars";
param.value = varString;
if (!_params)
_params = [CPDictionary dictionary];
_DOMObjectElement.appendChild(param);
if (_DOMEmbedElement)
_DOMEmbedElement.setAttribute(@"flashvars", varString);
[_params setObject:varString forKey:@"flashvars"];
[self setParameters:_params];
}
- (CPDictionary)flashVars
{
return _flashVars;
return [_params objectForKey:@"flashvars"];
}
- (void)setParameters:(CPDictionary)aDictionary
{
if (_paramElements)
if (_paramElements && !CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
{
var elements = [_paramElements allValues],
count = [elements count];
@@ -136,21 +130,27 @@
}
_params = aDictionary;
_paramElements = [CPDictionary dictionary];
var enumerator = [_params keyEnumerator],
key;
while (key = [enumerator nextObject])
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
{
var param = document.createElement(@"param");
param.name = key;
param.value = [_params objectForKey:key];
_paramElements = [CPDictionary dictionary];
_DOMObjectElement.appendChild(param);
var enumerator = [_params keyEnumerator],
key;
[_paramElements setObject:param forKey:key];
while (key = [enumerator nextObject] && _DOMObjectElement)
{
var param = document.createElement(@"param");
param.name = key;
param.value = [_params objectForKey:key];
_DOMObjectElement.appendChild(param);
[_paramElements setObject:param forKey:key];
}
}
else
[self _rebuildIEObjects];
}
- (CPDictionary)parameters
@@ -158,6 +158,25 @@
return _params;
}
- (void)_rebuildIEObjects
{
_DOMElement.innerHTML = @"";
if (![_flashMovie filename])
return;
var paramString = [CPString stringWithFormat:@"<param name='movie' value='%@' />", [_flashMovie filename]],
paramEnumerator = [_params keyEnumerator],
key;
while (key = [paramEnumerator nextObject])
paramString = [paramString stringByAppendingFormat:@"<param name='%@' value='%@' />", key, [_params objectForKey:key]];
_DOMObjectElement = document.createElement(@"object");
_DOMElement.appendChild(_DOMObjectElement);
_DOMObjectElement.outerHTML = [CPString stringWithFormat:@"<object classid=%@ width=%@ height=%@>%@</object>", IEFlashCLSID, CGRectGetWidth([self bounds]), CGRectGetHeight([self bounds]), paramString];
}
- (void)mouseDragged:(CPEvent)anEvent
{
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
+1
View File
@@ -1,5 +1,6 @@
#include "../CoreGraphics/CGGeometry.h"
#include "../Platform/Platform.h"
@import "_CPMenuWindow.j"
+19 -34
View File
@@ -104,17 +104,14 @@ var CPProgressIndicatorSpinningStyleColors = nil,
for (; start <= end; ++start)
{
CPProgressIndicatorBezelBorderViewPool[start] = [];
CPProgressIndicatorBezelBorderViewPool[start][CPMiniControlSize] = [];
CPProgressIndicatorBezelBorderViewPool[start][CPSmallControlSize] = [];
CPProgressIndicatorBezelBorderViewPool[start][CPRegularControlSize] = [];
}
CPProgressIndicatorClassName = [self className];
CPProgressIndicatorStyleIdentifiers = [];
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] = @"Bar";
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorSpinningStyle] = @"Spinny";
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle] = @"HUDBar";
@@ -126,30 +123,20 @@ var CPProgressIndicatorSpinningStyleColors = nil,
CPProgressIndicatorStyleSizes = [];
// Bar Sttyle
var prefix = CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle];
var prefixes = [
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle],
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle]
];
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
prefix = CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle];
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = _CGSizeMake(1.0, 9.0);
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = _CGSizeMake(1.0, 9.0);
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = _CGSizeMake(1.0, 9.0);
// HUD Bar Style
prefix = CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle];
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
prefix = CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle];
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = _CGSizeMake(1.0, 9.0);
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = _CGSizeMake(1.0, 9.0);
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = _CGSizeMake(1.0, 9.0);
for (var i = 0, count = prefixes.length; i<count; i++)
{
var prefix = prefixes[i];
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
}
}
- (id)initWithFrame:(CGRect)aFrame
@@ -428,21 +415,19 @@ var CPProgressIndicatorSpinningStyleColors = nil,
if (!_barView)
{
_barView = [[CPView alloc] initWithFrame:CGRectMake(2.0, 2.0, 0.0, 9.0)];
[_barView setBackgroundColor:[CPColor redColor]];
_barView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 16.0)];
[self addSubview:_barView];
}
[_barView setBackgroundColor:_CPControlColorWithPatternImage(
[_barView setBackgroundColor:_CPControlThreePartImagePattern(
NO,
CPProgressIndicatorStyleSizes,
CPProgressIndicatorClassName,
@"Bar",
CPProgressIndicatorStyleIdentifiers[_style],
_CPControlIdentifierForControlSize(_controlSize))];
[_barView setFrameSize:CGSizeMake(CGRectGetWidth([self bounds]) * (_doubleValue - _minValue) / (_maxValue - _minValue) - 4.0, 9.0)];
[_barView setFrameSize:CGSizeMake(CGRectGetWidth([self bounds]) * (_doubleValue - _minValue) / (_maxValue - _minValue) - 4.0, 16.0)];
}
/* @ignore */
+51 -42
View File
@@ -656,7 +656,7 @@ window.setTimeout(function(){
- (void)selectRowIndexes:(CPIndexSet)rows byExtendingSelection:(BOOL)shouldExtendSelection
{
if (([rows firstIndex] != CPNotFound && [rows firstIndex] < 0) || [rows lastIndex] >= [self numberOfRows])
if ([rows isEqualToIndexSet:_selectedRowIndexes] || (([rows firstIndex] != CPNotFound && [rows firstIndex] < 0) || [rows lastIndex] >= [self numberOfRows]))
return;
// We deselect all columns when selecting rows.
@@ -1445,8 +1445,8 @@ window.setTimeout(function(){
event:(CPEvent)theDragEvent
offset:(CPPoint)dragViewOffset
{
var size = [self bounds].size,
view = [[CPView alloc] initWithFrame:CPMakeRect(dragViewOffset.x, dragViewOffset.y, size.width, size.height)];
var bounds = [self bounds],
view = [[CPView alloc] initWithFrame:bounds];
[view setBackgroundColor:[CPColor clearColor]];
[view setAlphaValue:0.7];
@@ -1455,32 +1455,40 @@ window.setTimeout(function(){
// After that we can copy these add them to a transparent drag view and use that drag view
// to make it appear we are dragging images of those rows (as you would do in regular Cocoa)
var firstExposedColumn = [_exposedColumns firstIndex],
exposedLength = [_exposedColumns lastIndex] - firstExposedColumn + 1,
columns = [];
firstExposedRow = [_exposedRows firstIndex],
exposedColumnsLength = [_exposedColumns lastIndex] - firstExposedColumn + 1,
exposedRowsLength = [_exposedRows lastIndex] - firstExposedRow + 1,
columns = [],
rows = [];
[_exposedColumns getIndexes:columns maxCount:-1 inIndexRange:CPMakeRange(firstExposedColumn, exposedLength)];
var columnIndex = [columns count],
draggedDataViews = [],
dragViewHeight = 0.0;
[_exposedColumns getIndexes:columns maxCount:-1 inIndexRange:CPMakeRange(firstExposedColumn, exposedColumnsLength)];
[theDraggedRows getIndexes:rows maxCount:-1 inIndexRange:CPMakeRange(firstExposedRow, exposedRowsLength)];
var columnIndex = [columns count];
while (columnIndex--) {
var column = [_tableColumns objectAtIndex:columnIndex],
yOffset = 0,
rowIndex = CPNotFound;
while (columnIndex--)
{
var column = columns[columnIndex],
tableColumn = [_tableColumns objectAtIndex:column],
rowIndex = [rows count];
while ((rowIndex = [_selectedRowIndexes indexGreaterThanIndex:rowIndex]) !== CPNotFound)
{
var dataView = [self _newDataViewForRow:rowIndex tableColumn:column];
while (rowIndex--)
{
var row = rows[rowIndex];
var dataView = [self _newDataViewForRow:row tableColumn:tableColumn];
[dataView setBackgroundColor:[CPColor clearColor]];
[dataView setFrame:[self frameOfDataViewAtColumn:columnIndex row:rowIndex]];
[dataView setObjectValue:[self _objectValueForTableColumn:column row:rowIndex]];
[dataView setFrame:[self frameOfDataViewAtColumn:column row:row]];
[dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]];
[view addSubview:dataView];
}
}
var dragPoint = [self convertPoint:[theDragEvent locationInWindow] fromView:nil];
dragViewOffset.x = CGRectGetWidth(bounds)/2 - dragPoint.x;
dragViewOffset.y = CGRectGetHeight(bounds)/2 - dragPoint.y;
return view;
}
@@ -2152,13 +2160,20 @@ window.setTimeout(function(){
return YES;
}
- (void)trackMouse:(CPEvent)anEvent
{
// Prevent CPControl from eating the mouse events when we are in a drag session
if (![_draggedRowIndexes count])
[super trackMouse:anEvent];
else
[CPApp sendEvent:anEvent];
}
/* ignore */
- (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
{
var row = [self rowAtPoint:aPoint];
// begin the drag is the datasource lets us, we've move at least +-3px vertical or horizontal, or we're dragging from selected rows and we haven't begun a drag session
if
(
@@ -2170,7 +2185,7 @@ window.setTimeout(function(){
)
)
{
if([_selectedRowIndexes containsIndex:row])
if ([_selectedRowIndexes containsIndex:row])
_draggedRowIndexes = [[CPIndexSet alloc] initWithIndexSet:_selectedRowIndexes];
else
_draggedRowIndexes = [CPIndexSet indexSetWithIndex:row];
@@ -2179,32 +2194,34 @@ window.setTimeout(function(){
//ask the datasource for the data
var pboard = [CPPasteboard pasteboardWithName:CPDragPboard];
if([self canDragRowsWithIndexes:_draggedRowIndexes atPoint:aPoint] && [_dataSource tableView:self writeRowsWithIndexes:_draggedRowIndexes toPasteboard:pboard])
if ([self canDragRowsWithIndexes:_draggedRowIndexes atPoint:aPoint] && [_dataSource tableView:self writeRowsWithIndexes:_draggedRowIndexes toPasteboard:pboard])
{
var currentEvent = [CPApp currentEvent],
offset = CPPointMakeZero();
offset = CPPointMakeZero(),
tableColumns = [_tableColumns objectsAtIndexes:_exposedColumns];
// We deviate from the default Cocoa implementation here by asking for a view in stead of an image
// We support both, but the view prefered over the image because we can mimic the rows we are dragging
// by re-creating the data views for the dragged rows
var view = [self dragViewForRowsWithIndexes:_draggedRowIndexes
tableColumns:_exposedColumns
tableColumns:tableColumns
event:currentEvent
offset:CPPointMakeZero()];
offset:offset];
if (!view) {
if (!view)
{
var image = [self dragImageForRowsWithIndexes:_draggedRowIndexes
tableColumns:_exposedColumns
tableColumns:tableColumns
event:currentEvent
offset:CPPointMakeZero()];
view = [[CPImageView alloc] initWithFrame:CPMakeRect(aPoint.x, aPoint.y, [image size].width, [image size].height)];
offset:offset];
view = [[CPImageView alloc] initWithFrame:CPMakeRect(0, 0, [image size].width, [image size].height)];
[view setImage:image];
offset = aPoint;
}
[self dragView:view at:offset offset:CPPointMakeZero() event:[CPApp currentEvent] pasteboard:pboard source:self slideBack:YES];
var bounds = [view bounds];
var viewLocation = CPPointMake(aPoint.x - CGRectGetWidth(bounds)/2 + offset.x, aPoint.y - CGRectGetHeight(bounds)/2 + offset.y);
[self dragView:view at:viewLocation offset:CPPointMakeZero() event:[CPApp currentEvent] pasteboard:pboard source:self slideBack:YES];
return NO;
}
}
@@ -2253,10 +2270,6 @@ window.setTimeout(function(){
}
}
if (![_previouslySelectedRowIndexes isEqualToIndexSet:_selectedRowIndexes])
[self _noteSelectionDidChange];
if (mouseIsUp
&& (_implementedDataSourceMethods & CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_)
&& !_trackingPointMovedOutOfClickSlop
@@ -2571,8 +2584,6 @@ window.setTimeout(function(){
[self selectRowIndexes:newSelection byExtendingSelection:NO];
[self _noteSelectionIsChanging];
}
- (void)_noteSelectionIsChanging
@@ -2652,7 +2663,6 @@ window.setTimeout(function(){
if(i)
{
[self scrollRowToVisible:i];
[self _noteSelectionDidChange];
}
}
@@ -2702,7 +2712,6 @@ window.setTimeout(function(){
if(i)
{
[self scrollRowToVisible:i];
[self _noteSelectionDidChange];
}
}
+30 -21
View File
@@ -799,41 +799,50 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)copy:(id)sender
{
var selectedRange = [self selectedRange];
if (![CPPlatform isBrowser])
{
var selectedRange = [self selectedRange];
if (selectedRange.length < 1)
return;
if (selectedRange.length < 1)
return;
var pasteboard = [CPPasteboard generalPasteboard],
stringValue = [self stringValue],
stringForPasting = [stringValue substringWithRange:selectedRange];
var pasteboard = [CPPasteboard generalPasteboard],
stringValue = [self stringValue],
stringForPasting = [stringValue substringWithRange:selectedRange];
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
[pasteboard setString:stringForPasting forType:CPStringPboardType];
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
[pasteboard setString:stringForPasting forType:CPStringPboardType];
}
}
- (void)cut:(id)sender
{
[self copy:sender];
[self deleteBackwards:sender];
if (![CPPlatform isBrowser])
{
[self copy:sender];
[self deleteBackwards:sender];
}
}
- (void)paste:(id)sender
{
var pasteboard = [CPPasteboard generalPasteboard];
if (![[pasteboard types] containsObject:CPStringPboardType])
return;
if (![CPPlatform isBrowser])
{
var pasteboard = [CPPasteboard generalPasteboard];
[self deleteBackwards:sender];
if (![[pasteboard types] containsObject:CPStringPboardType])
return;
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
pasteString = [pasteboard stringForType:CPStringPboardType],
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
[self deleteBackwards:sender];
[self setStringValue:newValue];
[self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)];
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
pasteString = [pasteboard stringForType:CPStringPboardType],
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
[self setStringValue:newValue];
[self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)];
}
}
- (CPRange)selectedRange
+1 -1
View File
@@ -44,7 +44,7 @@ var screenNeedsInitialization = NO,
+ (BOOL)supportsDragAndDrop
{
return CPFeatureIsCompatible(CPHTMLDragAndDropFeature);
return CPFeatureIsCompatible(CPHTMLDragAndDropFeature) && ![self isBrowser];
}
+ (BOOL)supportsNativeMainMenu
Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 B

After

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 B

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 B

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 B

+3
View File
@@ -403,6 +403,9 @@
var kvoOperators = [];
// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior
var avgOperator, maxOperator, minOperator, countOperator, sumOperator;
kvoOperators["avg"] = function avgOperator(self, _cmd, param)
{
var objects = [self valueForKeyPath:param],
+7
View File
@@ -68,6 +68,13 @@ exports.run = function(args)
{
if (args && args.length > 1)
{
// we expect args to be in the format:
// 1) "objj" path
// 2) optional "-I" args
// 3) real or "virtual" main.j
// 4) optional program arguments
// copy the args since we're going to modify them
var argv = args.slice(1);
while (argv.length && argv[0].indexOf('-I') === 0)
+4 -12
View File
@@ -1,15 +1,7 @@
#!/usr/bin/env narwhal
var FILE = require("file");
var execPath = require("file").path(module.path);
var mainPath = execPath.dirname().dirname().join("lib", execPath.basename(), "main.j");
var cappuccinoPackage = FILE.path(module.path).dirname().dirname();
var mainPath = cappuccinoPackage.join("lib", FILE.basename(module.path), "main.j");
var frameworksPath = cappuccinoPackage.join("Frameworks");
// TODO: is specifying the Frameworks necessary?
system.args.splice(1, 0, "-I"+frameworksPath, String(mainPath));
// HACK: remove use of SELF_HOME from capp gen
system.env["SELF_HOME"] = cappuccinoPackage;
require("objective-j").run(system.args);
var args = ["objj", String(mainPath)].concat(system.args.slice(1));
require("objective-j").run(args);
+3 -1
View File
@@ -6,6 +6,8 @@ var OS = require("os"),
FILE = require("file"),
OBJJ = require("objective-j");
// FIXME: better way to do this:
var CAPP_HOME = require("packages").catalog["cappuccino"].directory;
function gen(/*va_args*/)
{
@@ -56,7 +58,7 @@ function gen(/*va_args*/)
if (FILE.isAbsolute(template))
sourceTemplate = FILE.join(template);
else
sourceTemplate = FILE.join(SYSTEM.env["SELF_HOME"], "lib", "capp", "Resources", "Templates", template);
sourceTemplate = FILE.join(CAPP_HOME, "lib", "capp", "Resources", "Templates", template);
var configFile = FILE.join(sourceTemplate, "template.config"),
config = {};
+11 -11
View File
@@ -3,20 +3,20 @@
function findCibClassDependencies(cibPath) {
var cib = [[CPCib alloc] initWithContentsOfURL:cibPath];
var dependencies = {};
var CPClassFromStringOriginal = CPClassFromString;
CPClassFromString = function(aClassName) {
var result = CPClassFromStringOriginal(aClassName);
// print("CPClassFromString: " + Array.prototype.slice.call(arguments) + " => " + result);
dependencies[aClassName] = true;
return result;
}
// make sure CPApp is init'd
// make sure CPApp is init'd
[CPApplication sharedApplication]
try {
@@ -26,7 +26,7 @@ function findCibClassDependencies(cibPath) {
} finally {
CPClassFromString = CPClassFromStringOriginal;
}
return Object.keys(dependencies);
}
// this is copied from CPCib's "instantiateCibWithExternalNameTable:"
@@ -55,16 +55,16 @@ function findCibClassDependencies(cibPath) {
[unarchiver setExternalObjectsForProxyIdentifiers:nil/*[anExternalNameTable objectForKey:CPCibExternalObjects]*/];
var objectData = [unarchiver decodeObjectForKey:"CPCibObjectDataKey"];
if (!objectData || ![objectData isKindOfClass:[_CPCibObjectData class]])
return NO;
var topLevelObjects = nil;//[anExternalNameTable objectForKey:CPCibTopLevelObjects];
[objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects]
// [objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects];
// [objectData awakeWithOwner:owner topLevelObjects:topLevelObjects];
// Display Visible Windows.
// [objectData displayVisibleWindows];
+79 -74
View File
@@ -1,18 +1,16 @@
var OS = require("os");
if (system.engine !== "rhino") {
system.args.splice(1,2); // remove library path and main.j
var cmd = "NARWHAL_ENGINE_HOME='' NARWHAL_ENGINE='rhino' " + system.args.map(OS.enquote).join(" ");
OS.exit(OS.system(cmd));
}
require("narwhal").ensureEngine("rhino");
@import <Foundation/Foundation.j>
@import <AppKit/AppKit.j>
@import "objj-analysis-tools.j"
@import "cib-analysis-tools.j"
var ARGS = require("args");
var FILE = require("file");
var OS = require("os");
var DOM = require("browser/dom");
var UTIL = require("util");
var INTERPRETER = require("interpreter");
var serializer = new DOM.XMLSerializer();
@@ -52,7 +50,7 @@ parser.option("-n", "--nostrip", "strip")
.set(false)
.help("Do not strip any files");
parser.option("-p", "--pngcrush", "png")
parser.option("-p", "--pngcrush", "png")
.def(false)
.set(true)
.help("Run pngcrush on all PNGs (pngcrush must be installed!)");
@@ -67,12 +65,12 @@ parser.helpful();
function main(args)
{
var options = parser.parse(args);
if (options.args.length < 2) {
parser.printUsage(options);
return;
}
//if (options.verbose)
CPLogRegister(CPLogPrint);
//else
@@ -98,63 +96,67 @@ function press(rootPath, outputPath, options) {
CPLog.info("===========================================");
CPLog.info("Application root: " + rootPath);
CPLog.info("Output directory: " + outputPath);
var outputFiles = {};
// analyze and gather files for each environment:
options.environments.forEach(function(environment) {
pressEnvironment(rootPath, outputFiles, environment, options);
});
// phase 4: copy everything and write out the new files
CPLog.error("PHASE 4: copy to output ("+rootPath+" to "+outputPath+")");
FILE.copyTree(rootPath, outputPath);
for (var path in outputFiles) {
var file = outputPath.join(rootPath.relative(path));
var parent = file.dirname();
if (!parent.exists()) {
CPLog.warn(parent + " doesn't exist, creating directories.");
parent.mkdirs();
}
if (typeof outputFiles[path] !== "string")
outputFiles[path] = outputFiles[path].join("");
CPLog.info((file.exists() ? "Overwriting: " : "Writing: ") + file);
FILE.write(file, outputFiles[path], { charset : "UTF-8" });
}
// strip known unnecessary files
// outputPath.glob("**/Frameworks/Debug").forEach(function(debugFramework) {
// outputPath.join(debugFramework).rmtree();
// });
// outputPath.join("index-debug.html").remove();
if (options.png) {
pngcrushDirectory(outputPath);
}
}
function pressEnvironment(rootPath, outputFiles, environment, options) {
var mainPath = String(rootPath.join(options.main));
var frameworks = options.frameworks.map(function(framework) { return rootPath.join(framework); });
CPLog.info("===========================================");
CPLog.info("Main file: " + mainPath)
CPLog.info("Frameworks: " + frameworks);
CPLog.info("Environment: " + environment);
// get a Rhino context
var context = new INTERPRETER.Context();
var scope = setupObjectiveJ(context);
scope.OBJJ_INCLUDE_PATHS = frameworks;
scope.OBJJ_ENVIRONMENTS = [environment, "ObjJ"];
// build list of cibs to inspect for dependent classes
// FIXME: what's the best way to determine which cibs to look in?
var cibs = FILE.glob(rootPath.join("**", "*.cib")).filter(function(path) { return !(/Frameworks/).test(path); });
// flattening bookkeeping. keep track of the bundles and evaled code (in the correct order!)
var bundleArchiveResponses = [];
var exectuableResponses = [];
@@ -166,42 +168,42 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
success : aResponse.success,
filePath : rootPath.relative(aResponse.filePath).toString()
};
if (aResponse.success) {
var xmlString = serializer.serializeToString(aResponse.xml);
response.text = CPPropertyListCreate280NorthData(CPPropertyListCreateFromXMLData({ string: xmlString })).string;
}
bundleArchiveResponses.push(response);
});
functionHookBefore(scope.objj_search.prototype, "didReceiveExecutableResponse", function(aResponse) {
exectuableResponses.push(aResponse);
});
// lets just use the Context object as our con
context.rootPath = rootPath;
context.scope = scope;
// phase 1: get global defines
CPLog.error("PHASE 1: Loading application...");
var globals = findGlobalDefines(context, mainPath, evaledFragments);
// coalesce the results
var dependencies = coalesceGlobalDefines(globals);
// Log
// log identifer => files defining
CPLog.trace("Global defines:");
Object.keys(dependencies).sort().forEach(function(identifier) {
CPLog.trace(" " + identifier + " => " + rootPath.relative(dependencies[identifier]));
});
// phase 2: walk the dependency tree (both imports and references) to determine exactly which files need to be included
CPLog.error("PHASE 2: Walk dependency tree...");
var requiredFiles = {};
if (options.nostrip)
{
// all files are required. no need for analysis
@@ -214,18 +216,31 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
CPLog.error("Root file not loaded!");
return;
}
CPLog.warn("Analyzing dependencies...");
context.dependencies = dependencies;
context.ignoreFrameworkImports = true; // ignores "XXX/XXX.j" imports
context.importCallback = function(importing, imported) { requiredFiles[imported] = true; };
context.referenceCallback = function(referencing, referenced) { requiredFiles[referenced] = true; }
requiredFiles[mainPath] = true;
// check the code
traverseDependencies(context, scope.objj_files[mainPath]);
// check the cibs
cibs.forEach(function(cibPath) {
var cibClasses = findCibClassDependencies(cibPath);
CPLog.debug(cibPath + " => " + cibClasses);
var referencedFiles = {};
markFilesReferencedByTokens(cibClasses, context.dependencies, referencedFiles);
checkReferenced(context, null, referencedFiles);
print(UTIL.repr(referencedFiles));
});
var count = 0,
total = 0;
for (var path in scope.objj_files)
@@ -233,7 +248,7 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
// mark all ".keytheme"s as required
if (/\.keyedtheme$/.test(path))
requiredFiles[path] = true;
if (requiredFiles[path])
{
CPLog.debug("Included: " + rootPath.relative(path));
@@ -242,30 +257,20 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
else
{
CPLog.info("Excluded: " + rootPath.relative(path));
}
}
total++;
}
CPLog.warn("Total required files: " + count + " out of " + total);
// FIXME: sprite images
//for (var i in context.bundleImages)
//{
// var images = context.bundleImages[i];
//
// CPLog.debug("Bundle images for " + i);
// for (var j in images)
// CPLog.trace(j + " = " + images[j]);
//}
}
if (options.flatten)
{
// phase 3a: build single Application.js file (and modified index.html)
CPLog.error("PHASE 3a: Flattening...");
var applicationScriptName = "Application-"+environment+".js";
var indexHTMLName = "index-"+environment+".html";
// Shim for faking bundle responses.
// We're just defining it here so we can serialize the function. It's not used within press.
// **************************************************
@@ -303,9 +308,9 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
}
}
// **************************************************
var applicationScript = [];
var URIMaps = {};
Object.keys(scope.objj_bundles).forEach(function(bundleName) {
var bundle = scope.objj_bundles[bundleName];
@@ -332,7 +337,7 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
applicationScript.push(" var URIMaps = " + JSON.stringify(URIMaps) + ";");
applicationScript.push(" setupURIMaps(URIMaps);");
applicationScript.push("})();");
// add each fragment, wrapped in a function, along with OBJJ_CURRENT_BUNDLE bookkeeping
evaledFragments.forEach(function(fragment) {
if (requiredFiles[fragment.file.path])
@@ -346,13 +351,13 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
CPLog.info("Stripping " + rootPath.relative(fragment.file.path));
}
});
// call main once the page has loaded. FIXME: assumes synchronous script loading?
applicationScript.push("if (window.addEventListener)");
applicationScript.push(" window.addEventListener('load', main, false);")
applicationScript.push("else if (window.attachEvent)")
applicationScript.push(" window.attachEvent('onload', main);");
// MHTML
// TODO: combine multiple MHTMLs
exectuableResponses.forEach(function(aResponse) {
@@ -362,15 +367,15 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
applicationScript.push(aResponse.text.slice(mhtmlStart, mhtmlEnd+2));
}
});
var indexHTML = FILE.read(FILE.join(rootPath, "index.html"), { charset : "UTF-8" });
// comment out any OBJJ_MAIN_FILE defintions or objj_import() calls
indexHTML = indexHTML.replace(/(\bOBJJ_MAIN_FILE\s*=|\bobjj_import\s*\()/g, '//$&');
// add a script tag for Application.js at the very end of the <head> block
indexHTML = indexHTML.replace(/([ \t]*)(<\/head>)/, '$1 <script src = "'+applicationScriptName+'" type = "text/javascript"></script>\n$1$2');
// output Application.js and index.html
outputFiles[rootPath.join(applicationScriptName)] = applicationScript.join("\n");
outputFiles[rootPath.join(indexHTMLName)] = indexHTML;
@@ -423,7 +428,7 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
outputFiles[staticPath].push("p;");
outputFiles[staticPath].push(filename.length+";");
outputFiles[staticPath].push(filename);
for (var i = 0; i < file.fragments.length; i++)
{
if (file.fragments[i].type & FRAGMENT_CODE)
@@ -443,13 +448,13 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
ignoreFragment = true;
}
}
if (!ignoreFragment)
{
if (file.fragments[i].type & FRAGMENT_LOCAL)
{
var relativePath = pathRelativeTo(file.fragments[i].info, directory)
outputFiles[staticPath].push("i;");
outputFiles[staticPath].push(relativePath.length+";");
outputFiles[staticPath].push(relativePath);
@@ -480,20 +485,20 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
// phase 3.5: fix bundle plists
CPLog.error("PHASE 3.5: fix bundle plists");
for (var path in bundles)
{
var directory = FILE.dirname(path),
dict = bundles[path].info,
replacedFiles = [dict objectForKey:"CPBundleReplacedFiles"];
CPLog.info("Modifying .sj: " + rootPath.relative(path));
if (replacedFiles)
{
var newReplacedFiles = [];
[dict setObject:newReplacedFiles forKey:"CPBundleReplacedFiles"];
for (var i = 0; i < replacedFiles.length; i++)
{
var replacedFilePath = directory + "/" + replacedFiles[i]
@@ -516,12 +521,12 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
function pngcrushDirectory(directory) {
var directoryPath = FILE.path(directory);
var pngs = directoryPath.glob("**/*.png");
system.stderr.print("Running pngcrush on " + pngs.length + " pngs:");
pngs.forEach(function(dst) {
var dstPath = directoryPath.join(dst);
var tmpPath = FILE.path(dstPath+".tmp");
var p = OS.popen(["pngcrush", "-rem", "alla", "-reduce", /*"-brute",*/ dstPath, tmpPath]);
if (p.wait()) {
CPLog.warn("pngcrush failed. Ensure it's installed and on your PATH.");
+64 -60
View File
@@ -48,28 +48,6 @@ function traverseDependencies(context, file)
file.fragments = objj_preprocess(file.contents, file.bundle, file);
}
// sprite: look for pngs in the Resources directory
if (!context.bundleImages)
context.bundleImages = {};
if (!context.bundleImages[file.bundle.path])
{
var resourcesPath = FILE.path(file.bundle.path).dirname().join("/Resources");
if (resourcesPath.exists())
{
context.bundleImages[file.bundle.path] = {};
resourcesPath.glob("**/*.png").forEach(function(png) {
var pngPath = resourcesPath.join(png);
var relativePath = pathRelativeTo(pngPath.absolute(), resourcesPath.absolute());
// this is used as a bit mask, not a boolean
context.bundleImages[file.bundle.path][relativePath] = 1;
});
}
}
var images = context.bundleImages[file.bundle.path];
var referencedFiles = {},
importedFiles = {};
@@ -80,31 +58,9 @@ function traverseDependencies(context, file)
if (fragment.type & FRAGMENT_CODE)
{
var lexer = new objj_lexer(fragment.info, NULL);
var token;
while (token = lexer.skip_whitespace())
{
if (context.dependencies.hasOwnProperty(token))
{
var files = context.dependencies[token];
for (var j = 0; j < files.length; j++)
{
// don't record references to self
if (files[j] != file.path)
{
if (!referencedFiles[files[j]])
referencedFiles[files[j]] = {};
referencedFiles[files[j]][token] = true;
}
}
}
var matches = token.match(new RegExp("^['\"](.*)['\"]$"));
if (matches && images && images[matches[1]])
images[matches[1]] = (images[matches[1]] | 2);
}
var referencedTokens = uniqueTokens(fragment.info);
markFilesReferencedByTokens(referencedTokens, context.dependencies, referencedFiles);
}
else if (fragment.type & FRAGMENT_FILE)
{
@@ -130,12 +86,25 @@ function traverseDependencies(context, file)
}
// check each imported file
checkImported(context, file.path, importedFiles);
if (context.importedFiles)
context.importedFiles[file.path] = importedFiles;
// check each referenced file
checkReferenced(context, file.path, referencedFiles);
if (context.referencedFiles)
context.referencedFiles[file.path] = referencedFiles;
}
function checkImported(context, path, importedFiles) {
for (var importedFile in importedFiles)
{
if (importedFile != file.path)
if (importedFile != path)
{
if (context.importCallback)
context.importCallback(file.path, importedFile);
context.importCallback(path, importedFile);
if (context.scope.objj_files[importedFile])
traverseDependencies(context, context.scope.objj_files[importedFile]);
@@ -143,17 +112,15 @@ function traverseDependencies(context, file)
CPLog.error("Missing imported file: " + importedFile);
}
}
}
if (context.importedFiles)
context.importedFiles[file.path] = importedFiles;
// check each referenced file
function checkReferenced(context, path, referencedFiles) {
for (var referencedFile in referencedFiles)
{
if (referencedFile != file.path)
if (referencedFile != path)
{
if (context.referenceCallback)
context.referenceCallback(file.path, referencedFile, referencedFiles[referencedFile]);
context.referenceCallback(path, referencedFile, referencedFiles[referencedFile]);
if (context.scope.objj_files.hasOwnProperty(referencedFile))
traverseDependencies(context, context.scope.objj_files[referencedFile]);
@@ -161,9 +128,46 @@ function traverseDependencies(context, file)
CPLog.error("Missing referenced file: " + referencedFile);
}
}
}
if (context.referencedFiles)
context.referencedFiles[file.path] = referencedFiles;
// returns a unique list of tokens for a piece of code.
// ideally this should return identifiers only
function uniqueTokens(code) {
// FIXME: this breaks for indentifiers containing "$" since it's considered a distinct token by the parser
var lexer = new objj_lexer(code, null);
var token, tokens = {};
while (token = lexer.skip_whitespace()) {
tokens[token] = true;
}
return Object.keys(tokens);
}
/*
params:
tokens (in): list of tokens to mark as required
tokenDependenciesMap (in): map from tokens to files which define those tokens
referencedFiles (out): map of required files (to map of tokens defined in that file)
*/
function markFilesReferencedByTokens(tokens, tokenDependenciesMap, referencedFiles) {
tokens.forEach(function(token) {
if (tokenDependenciesMap.hasOwnProperty(token))
{
var files = tokenDependenciesMap[token];
for (var j = 0; j < files.length; j++)
{
// don't record references to self
if (files[j] != file.path)
{
if (!referencedFiles[files[j]])
referencedFiles[files[j]] = {};
referencedFiles[files[j]][token] = true;
}
}
}
});
}
function findImportInObjjFiles(scope, fragment)
@@ -272,9 +276,9 @@ function findGlobalDefines(context, mainPath, evaledFragments, bundleCallback)
bundlePaths = bundlePaths || [];
// load default theme bundle
var themePath = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName]];
var themeBundle = [[CPBundle alloc] initWithPath:themePath + "/Info.plist"];
[themeBundle loadWithDelegate:bundleDelegate];
// var themePath = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName]];
// var themeBundle = [[CPBundle alloc] initWithPath:themePath + "/Info.plist"];
// [themeBundle loadWithDelegate:bundleDelegate];
// load additional bundles
bundlePaths.forEach(function(bundlePath) {
+2 -1
View File
@@ -24,7 +24,8 @@ function ask_remove_dir () {
if [ -d "$dir" ]; then
echo "================================================================================"
echo "Found an existing Narwhal/Cappuccino installation, $dir. Remove it automatically now?"
echo "WARNING: custom modifications and installed packages in this installation WILL BE DELETED."
echo "WARNING: the ENTIRE directory, $dir, will be removed (i.e. 'rm -rf $dir')."
echo "Be sure this is correct. Custom modifications and installed packages WILL BE DELETED."
if prompt; then
rm -rf "$dir"
fi