Merge branch 'loader' into jake

This commit is contained in:
Francisco Ryan Tolmasky I committed 2010-02-17 13:40:22 -08:00
commit 80b252a744
137 files changed
+6916 -8096

No files matched your search

+1
View File
@@ -4,3 +4,4 @@ Build
Demos
./Aristo
WebSite
.push-package
+2 -2
View File
@@ -145,7 +145,7 @@ CPButtonStateMixed = CPThemeState("mixed");
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), nil]
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
}
@@ -460,7 +460,7 @@ CPButtonStateMixed = CPThemeState("mixed");
return bounds;
}
- (CGRect)bezelRectForBounds:(CFRect)bounds
- (CGRect)bezelRectForBounds:(CGRect)bounds
{
if (![self isBordered])
return _CGRectMakeZero();
+1 -1
View File
@@ -25,7 +25,7 @@
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[nil]
return [CPDictionary dictionaryWithObjects:[[CPNull null]]
forKeys:[@"bezel-color"]];
}
+105 -16
View File
@@ -365,29 +365,21 @@
- (void)tile
{
var width = CGRectGetWidth([self bounds]);
if (![_content count] || width == _tileWidth)
return;
// We try to fit as many views per row as possible. Any remaining space is then
// either proportioned out to the views (if their minSize != maxSize) or used as
// margin
var itemSize = CGSizeMakeCopy(_minItemSize);
_numberOfColumns = MAX(1.0, FLOOR(width / itemSize.width));
if (_maxNumberOfColumns > 0)
_numberOfColumns = MIN(_maxNumberOfColumns, _numberOfColumns);
var nbItems = [_items count];
if (_numberOfColumns > nbItems)
_numberOfColumns = nbItems;
var maxItemSize = CGSizeMakeCopy(_maxItemSize);
if (maxItemSize.width==0)
maxItemSize.width = FLOOR(width / _numberOfColumns);
var remaining = width - _numberOfColumns * itemSize.width,
var remaining = width - _numberOfColumns * itemSize.width,
itemsNeedSizeUpdate = NO;
if (remaining > 0 && itemSize.width < _maxItemSize.width)
@@ -420,7 +412,7 @@
{
if (index % _numberOfColumns == 0)
{
x = 0;
x = _horizontalMargin;
y += _verticalMargin + itemSize.height;
}
@@ -431,7 +423,7 @@
if (itemsNeedSizeUpdate)
[view setFrameSize:_itemSize];
x += itemSize.width;
x += itemSize.width + _horizontalMargin;
}
_tileWidth = width;
@@ -686,6 +678,103 @@
@end
@implementation CPCollectionView (KeyboardInteraction)
- (CGRect)rectForItemAtIndex:(int)index
{
// Don't re-compute anything just grab the current frame
// This allows subclasses to override tile without messing this up.
return [[_items[index] view] frame];
}
- (CGRect)rectForItemsAtIndexes:(CPIndexSet)indexSet
{
var indexArray = [],
rect = nil;
[indexSet getIndexes:indexArray maxCount:-1 inIndexRange:nil];
for (var i = 0, count = indexArray.length; i < count; ++i)
{
var index = indexArray[i];
if (rect == nil)
rect = [self rectForItemAtIndex:index];
else
rect = CGRectUnion(rect, [self rectForItemAtIndex:index]);
}
return rect;
}
- (void)_scrollToSelection
{
var rect = [self rectForItemsAtIndexes:[self selectionIndexes]];
if (rect)
[self scrollRectToVisible:rect];
}
- (void)moveLeft:(id)sender
{
var index = [[self selectionIndexes] firstIndex];
if (index === CPNotFound)
index = [[self items] count];
index = MAX(index - 1, 0);
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
}
- (void)moveRight:(id)sender
{
var index = MIN([[self selectionIndexes] firstIndex] + 1, [[self items] count]-1);
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
}
- (void)moveDown:(id)sender
{
var index = MIN([[self selectionIndexes] firstIndex] + [self numberOfColumns], [[self items] count]-1);
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
}
- (void)moveUp:(id)sender
{
var index = [[self selectionIndexes] firstIndex];
if (index == CPNotFound)
index = [[self items] count];
index = MAX(0, index - [self numberOfColumns]);
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
}
- (void)deleteBackwards:(id)sender
{
if ([[self delegate] respondsToSelector:@selector(collectionView:shouldDeleteItemsAtIndexes:)])
{
[[self delegate] collectionView:self shouldDeleteItemsAtIndexes:[self selectionIndexes]];
var index = [[self selectionIndexes] firstIndex];
if (index > [[self content] count]-1)
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count]-1]];
[self _scrollToSelection];
[self setNeedsDisplay:YES];
}
}
- (void)keyDown:(CPEvent)anEvent
{
[self interpretKeyEvents:[anEvent]];
}
@end
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
+16 -41
View File
@@ -27,47 +27,22 @@
#include "CoreGraphics/CGGeometry.h"
#include "Platform/Platform.h"
/*
@global
@group CPTextAlignment
*/
CPLeftTextAlignment = 0;
/*
@global
@group CPTextAlignment
*/
CPRightTextAlignment = 1;
/*
@global
@group CPTextAlignment
*/
CPCenterTextAlignment = 2;
/*
@global
@group CPTextAlignment
*/
CPJustifiedTextAlignment = 3;
/*
@global
@group CPTextAlignment
*/
CPNaturalTextAlignment = 4;
CPLeftTextAlignment = 0;
CPRightTextAlignment = 1;
CPCenterTextAlignment = 2;
CPJustifiedTextAlignment = 3;
CPNaturalTextAlignment = 4;
/*
@global
@group CPControlSize
*/
CPRegularControlSize = 0;
/*
@global
@group CPControlSize
*/
CPSmallControlSize = 1;
/*
@global
@group CPControlSize
*/
CPMiniControlSize = 2;
CPRegularControlSize = 0;
CPSmallControlSize = 1;
CPMiniControlSize = 2;
CPLineBreakByWordWrapping = 0;
CPLineBreakByCharWrapping = 1;
CPLineBreakByClipping = 2;
CPLineBreakByTruncatingHead = 3;
CPLineBreakByTruncatingTail = 4;
CPLineBreakByTruncatingMiddle = 5;
CPControlNormalBackgroundColor = "CPControlNormalBackgroundColor";
CPControlSelectedBackgroundColor = "CPControlSelectedBackgroundColor";
@@ -112,7 +87,7 @@ var CPControlBlackColor = [CPColor blackColor];
CPLineBreakByClipping,
[CPColor blackColor],
[CPFont systemFontOfSize:12.0],
nil,
[CPNull null],
_CGSizeMakeZero(),
CPImageLeft,
CPScaleToFit,
+2 -2
View File
@@ -484,7 +484,7 @@ var CPDocumentUntitledCount = 0;
else
[_writeRequest setHTTPMethod:@"PUT"];
[_writeRequest setHTTPBody:[data string]];
[_writeRequest setHTTPBody:[data encodedString]];
[_writeRequest setValue:@"close" forHTTPHeaderField:@"Connection"];
@@ -567,7 +567,7 @@ var CPDocumentUntitledCount = 0;
// READ
if (aConnection == _readConnection)
{
[self readFromData:[CPData dataWithString:aData] ofType:session.fileType error:nil];
[self readFromData:[CPData dataWithEncodedString:aData] ofType:session.fileType error:nil];
objj_msgSend(session.delegate, session.didReadSelector, self, YES, session.contextInfo);
}
+5
View File
@@ -189,6 +189,11 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
return self;
}
- (id)draggingDestination
{
return _draggingDestination;
}
- (CGPoint)draggingLocation
{
return _draggingLocation
+5
View File
@@ -28,6 +28,9 @@
@import "CPGeometry.j"
#include "Platform/DOM.h"
CPImageLoadStatusInitialized = 0;
CPImageLoadStatusLoading = 1;
CPImageLoadStatusCompleted = 2;
@@ -258,6 +261,7 @@ function CPAppKitImage(aFilename, aSize)
_loadStatus = CPImageLoadStatusLoading;
#if PLATFORM(DOM)
_image = new Image();
var isSynchronous = YES;
@@ -304,6 +308,7 @@ function CPAppKitImage(aFilename, aSize)
// onload and friends may fire after this point but BEFORE the end of the run loop,
// crazy, I know. So don't set isSynchronous here, rather wait a bit longer.
window.setTimeout(function() { isSynchronous = NO; }, 0);
#endif
}
- (BOOL)isThreePartImage
+6 -6
View File
@@ -233,7 +233,7 @@ var CPPasteboards = nil,
*/
- (BOOL)setPropertyList:(id)aPropertyList forType:(CPString)aType
{
return [self setData:[CPPropertyListSerialization dataFromPropertyList:aPropertyList format:CPPropertyListXMLFormat_v1_0 errorDescription:nil] forType:aType];
return [self setData:[CPPropertyListSerialization dataFromPropertyList:aPropertyList format:CPPropertyList280NorthFormat_v1_0] forType:aType];
}
/*!
@@ -343,7 +343,7 @@ var CPPasteboards = nil,
var data = [self dataForType:aType];
if (data)
return [CPPropertyListSerialization propertyListFromData:data format:CPPropertyListXMLFormat_v1_0 errorDescription:nil];
return [CPPropertyListSerialization propertyListFromData:data format:CPPropertyList280NorthFormat_v1_0];
return nil;
}
@@ -415,7 +415,7 @@ var DOMDataTransferPasteboard = nil;
if (type === CPStringPboardType)
_dataTransfer.setData(type, [aPasteboard stringForType:type]);
else
_dataTransfer.setData(type, [[aPasteboard dataForType:type] string]);
_dataTransfer.setData(type, [[aPasteboard dataForType:type] encodedString]);
}
}
@@ -429,9 +429,9 @@ var DOMDataTransferPasteboard = nil;
var dataString = _dataTransfer.getData(aType);
if (aType === CPStringPboardType)
return [CPData dataFromPropertyList:dataString format:kCFPropertyList280NorthFormat_v1_0 errorDescription:0];
return [CPData dataFromPropertyList:dataString format:kCFPropertyList280NorthFormat_v1_0];
return [CPData dataWithString:dataString];
return [CPData dataWithEncodedString:dataString];
}
- (id)propertyListForType:(CPString)aType
@@ -439,7 +439,7 @@ var DOMDataTransferPasteboard = nil;
if (aType === CPStringPboardType)
return _dataTransfer.getData(aType);
return [CPPropertyListSerialization propertyListFromData:[self dataForType:aType] format:CPPropertyListUnknownFormat errorDescription:nil];
return [CPPropertyListSerialization propertyListFromData:[self dataForType:aType] format:CPPropertyListUnknownFormat];
}
@end
+15 -4
View File
@@ -315,7 +315,10 @@
_hasHorizontalScroller = shouldHaveHorizontalScroller;
if (_hasHorizontalScroller && !_horizontalScroller)
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, _CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])]];
{
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth]+1), [CPScroller scrollerWidth])]];
[[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])];
}
[self reflectScrolledClipView:_contentView];
}
@@ -373,7 +376,10 @@
_hasVerticalScroller = shouldHaveVerticalScroller;
if (_hasVerticalScroller && !_verticalScroller)
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))]];
{
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight([self bounds]), [CPScroller scrollerWidth]+1))]];
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))];
}
[self reflectScrolledClipView:_contentView];
}
@@ -726,7 +732,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller",
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller";
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller",
CPScrollViewCornerViewKey = "CPScrollViewCornerViewKey";
@implementation CPScrollView (CPCoding)
@@ -749,7 +756,9 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
_hasVerticalScroller = [aCoder decodeBoolForKey:CPScrollViewHasVScrollerKey];
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
// Do to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state.
[[CPRunLoop currentRunLoop] performSelector:@selector(reflectScrolledClipView:) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
}
@@ -775,6 +784,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
[aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey];
[aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey];
[aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
[aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey];
}
@end
+30 -10
View File
@@ -79,7 +79,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[ nil, nil, nil, nil,
return [CPDictionary dictionaryWithObjects:[ [CPNull null], [CPNull null], [CPNull null], [CPNull null],
_CGSizeMakeZero(), _CGSizeMakeZero(), _CGInsetMakeZero(), _CGInsetMakeZero(), _CGSizeMakeZero()]
forKeys:[ @"knob-slot-color",
@"decrement-line-color",
@@ -235,21 +235,21 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/
- (void)checkSpaceForParts
{
var bounds = [self bounds];
var bounds = [self bounds];
// Assume we won't be needing the arrows.
if (_knobProportion === 1.0)
{
_usableParts = CPNoScrollerParts;
_partRects[CPScrollerDecrementPage] = _CGRectMakeZero();
_partRects[CPScrollerKnob] = _CGRectMakeZero();
_partRects[CPScrollerIncrementPage] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementPage] = CGRectMakeZero();
_partRects[CPScrollerKnob] = CGRectMakeZero();
_partRects[CPScrollerIncrementPage] = CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = CGRectMakeZero();
_partRects[CPScrollerIncrementLine] = CGRectMakeZero();
// In this case, the slot is the entirety of the scroller.
_partRects[CPScrollerKnobSlot] = _CGRectMakeCopy(bounds);
_partRects[CPScrollerKnobSlot] = CGRectMakeCopy(bounds);
return;
}
@@ -279,8 +279,18 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
_partRects[CPScrollerIncrementPage] = _CGRectMake(0.0, knobLocation + knobHeight, width, height - (knobLocation + knobHeight) - effectiveIncrementLineHeight);
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotHeight);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
}
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
if(height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
_partRects[CPScrollerKnob] = _CGRectMakeZero();
if(height < decrementLineSize.height + incrementLineSize.height - 2)
{
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, 0, width - trackInset.left - trackInset.right, height);
}
}
else
{
@@ -300,6 +310,16 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
if(width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
_partRects[CPScrollerKnob] = _CGRectMakeZero();
if(width < decrementLineSize.width + incrementLineSize.width - 2)
{
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
_partRects[CPScrollerKnobSlot] = _CGRectMake(0.0, 0.0, width, slotHeight);
}
}
}
+43 -35
View File
@@ -26,20 +26,8 @@
#include "CoreGraphics/CGGeometry.h"
/*
@global
@group CPSegmentSwitchTracking
*/
CPSegmentSwitchTrackingSelectOne = 0;
/*
@global
@group CPSegmentSwitchTracking
*/
CPSegmentSwitchTrackingSelectAny = 1;
/*
@global
@group CPSegmentSwitchTracking
*/
CPSegmentSwitchTrackingMomentary = 2;
/*!
@@ -68,7 +56,7 @@ CPSegmentSwitchTrackingMomentary = 2;
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[CPCenterTextAlignment, CPCenterVerticalTextAlignment, CPImageLeft, CPScaleNone, _CGInsetMakeZero(), _CGInsetMakeZero(), nil, nil, nil, nil, 1.0, 24.0]
return [CPDictionary dictionaryWithObjects:[CPCenterTextAlignment, CPCenterVerticalTextAlignment, CPImageLeft, CPScaleNone, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], [CPNull null], 1.0, 24.0]
forKeys:[@"alignment", @"vertical-alignment", @"image-position", @"image-scaling", @"bezel-inset", @"content-inset", @"left-segment-bezel-color", @"right-segment-bezel-color", @"center-segment-bezel-color", @"divider-bezel-color", @"divider-thickness", @"default-height"]];
}
@@ -375,7 +363,10 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
{
_segments[aSegment].enabled = isEnabled;
if (isEnabled)
_themeStates[aSegment] &= ~CPThemeStateDisabled;
else
_themeStates[aSegment] |= CPThemeStateDisabled;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
@@ -388,7 +379,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (BOOL)isEnabledForSegment:(unsigned)aSegment
{
return _segments[aSegment].enabled;
return !(_themeStates[aSegment] & CPThemeStateDisabled)
}
/*!
@@ -462,30 +453,28 @@ CPSegmentSwitchTrackingMomentary = 2;
}
else if (aName === "right-segment-bezel")
{
var lastSegmentLeftOffset = [self _leftOffsetForSegment:[self _indexOfLastSegment]];
return CPRectMake(lastSegmentLeftOffset + [self widthForSegment:[self _indexOfLastSegment]] - contentInset.right,
return CPRectMake(CGRectGetWidth([self bounds]) - contentInset.right,
bezelInset.top,
contentInset.right,
height);
}
else if (aName.substring(0, "segment-bezel".length) == "segment-bezel")
else if (aName.indexOf("segment-bezel") === 0)
{
var segment = parseInt(aName.substring("segment-bezel-".length), 10),
frame = CGRectCreateCopy(_segments[segment].frame);
if (segment == 0)
if (segment === 0)
{
frame.origin.x += contentInset.left;
frame.size.width -= contentInset.left;
}
if (segment == _segments.length - 1)
frame.size.width -= contentInset.right;
if (segment === _segments.length - 1)
frame.size.width = CGRectGetWidth([self bounds]) - contentInset.right - frame.origin.x;
return frame;
}
else if (aName.substring(0, "divider-bezel".length) == "divider-bezel")
else if (aName.indexOf("divider-bezel") === 0)
{
var segment = parseInt(aName.substring("divider-bezel-".length), 10),
width = [self widthForSegment:segment],
@@ -494,7 +483,7 @@ CPSegmentSwitchTrackingMomentary = 2;
return CGRectMake(left + width, bezelInset.top, thickness, height);
}
else if (aName.substring(0, "segment-content".length) == "segment-content")
else if (aName.indexOf("segment-content") === 0)
{
var segment = parseInt(aName.substring("segment-content-".length), 10);
@@ -517,8 +506,12 @@ CPSegmentSwitchTrackingMomentary = 2;
if (_segments.length <= 0)
return;
var themeState = _themeStates[0];
themeState |= _themeState & CPThemeStateDisabled;
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
inState:_themeStates[0]];
inState:themeState];
var leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
positioned:CPWindowBelow
@@ -526,8 +519,12 @@ CPSegmentSwitchTrackingMomentary = 2;
[leftBezelView setBackgroundColor:leftCapColor];
var themeState = _themeStates[_themeStates.length - 1];
themeState |= _themeState & CPThemeStateDisabled;
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
inState:_themeStates[_themeStates.length - 1]];
inState:themeState];
var rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
positioned:CPWindowBelow
@@ -703,7 +700,16 @@ CPSegmentSwitchTrackingMomentary = 2;
while (count--)
if (CGRectContainsPoint(_segments[count].frame, aPoint))
return count;
if (_segments.length)
{
var adjustedLastFrame = CGRectCreateCopy(_segments[_segments.length - 1].frame);
adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
if (CGRectContainsPoint(adjustedLastFrame, aPoint))
return _segments.length - 1;
}
return -1;
}
@@ -734,7 +740,7 @@ CPSegmentSwitchTrackingMomentary = 2;
if (_trackingSegment == -1)
return;
if (CGRectContainsPoint(_segments[_trackingSegment].frame, location))
if (_trackingSegment === [self testSegment:location])
{
if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
{
@@ -765,10 +771,13 @@ CPSegmentSwitchTrackingMomentary = 2;
if (type == CPLeftMouseDown)
{
_trackingHighlighted = YES;
_trackingSegment = [self testSegment:location];
[self drawSegmentBezel:_trackingSegment highlight:YES];
var trackingSegment = [self testSegment:location];
if (trackingSegment > -1 && [self isEnabledForSegment:trackingSegment])
{
_trackingHighlighted = YES;
_trackingSegment = trackingSegment;
[self drawSegmentBezel:_trackingSegment highlight:YES];
}
}
else if (type == CPLeftMouseDragged)
@@ -776,12 +785,11 @@ CPSegmentSwitchTrackingMomentary = 2;
if (_trackingSegment == -1)
return;
var highlighted = CGRectContainsPoint(_segments[_trackingSegment].frame, location);
var highlighted = [self testSegment:location] === _trackingSegment;
if (highlighted != _trackingHighlighted)
{
_trackingHighlighted = highlighted;
[self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
}
}
+1 -1
View File
@@ -49,7 +49,7 @@ CPCircularSlider = 1;
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[nil, _CGSizeMakeZero(), 0.0, nil]
return [CPDictionary dictionaryWithObjects:[[CPNull null], _CGSizeMakeZero(), 0.0, [CPNull null]]
forKeys:[@"knob-color", @"knob-size", @"track-width", @"track-color"]];
}
+25 -11
View File
@@ -79,6 +79,7 @@ CPTableColumnUserResizingMask = 1 << 1;
[self setHeaderView:header];
var textDataView = [CPTextField new];
[textDataView setLineBreakMode:CPLineBreakByTruncatingTail];
[textDataView setValue:[CPColor colorWithHexString:@"333333"] forThemeAttribute:@"text-color"];
[textDataView setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateHighlighted];
[textDataView setValue:[CPFont boldSystemFontOfSize:12] forThemeAttribute:@"font" inState:CPThemeStateHighlighted];
@@ -176,7 +177,7 @@ CPTableColumnUserResizingMask = 1 << 1;
_maxWidth = aMaxWidth;
var width = [self width],
newWidth = MAX(width, [self maxWidth]);
newWidth = MIN(width, [self maxWidth]);
if (width !== newWidth)
[self setWidth:newWidth];
@@ -229,6 +230,22 @@ CPTableColumnUserResizingMask = 1 << 1;
return _headerView;
}
/*!
This method set's the "prototype" view which will be used to create all table cells in this column.
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
Example:
[tableColumn setDataView:someView]; // snapshot taken
[[tableColumn dataView] setSomething:x]; //won't work
This doesn't work because the snapshot is taken before the new property is applied. Instead, do:
[someView setSomething:x];
[tableColumn setDataView:someView];
*/
- (void)setDataView:(CPView)aView
{
if (_dataView === aView)
@@ -388,14 +405,11 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
_maxWidth = [aCoder decodeFloatForKey:CPTableColumnMaxWidthKey];
[self setIdentifier:[aCoder decodeObjectForKey:CPTableColumnIdentifierKey]];
// [self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
// [self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
[self setHeaderView:[CPTextField new]];
[self setDataView:[CPTextField new]];
// _resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
_resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
}
return self;
@@ -409,10 +423,10 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
[aCoder encodeObject:_minWidth forKey:CPTableColumnMinWidthKey];
[aCoder encodeObject:_maxWidth forKey:CPTableColumnMaxWidthKey];
// [aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
// [aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
[aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
// [aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
}
@end
+156 -110
View File
@@ -28,7 +28,7 @@ var CPThemeStatePressed = CPThemeState("pressed");
@implementation _CPTableColumnHeaderView : CPView
{
CPTextField _textField;
_CPImageAndTextView _textField;
}
- (void)initWithFrame:(CGRect)frame
@@ -36,31 +36,37 @@ var CPThemeStatePressed = CPThemeState("pressed");
self = [super initWithFrame:frame];
if (self)
{
_textField = [[CPTextField alloc] initWithFrame:CGRectMake(5, 1, CGRectGetWidth([self bounds]) - 5, CGRectGetHeight([self bounds]) - 1)];
[_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_textField setTextColor: [CPColor colorWithHexString: @"333333"]];
[_textField setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font"];
[_textField setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
[_textField setVerticalAlignment:CPCenterVerticalTextAlignment];
[_textField setValue:CGSizeMake(0,1) forThemeAttribute:@"text-shadow-offset"];
[_textField setValue:[CPColor whiteColor] forThemeAttribute:@"text-shadow-color"];
[self addSubview:_textField];
[self _init];
}
return self;
}
- (void)_init
{
_textField = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(5, 1, CGRectGetWidth([self bounds]) - 10, CGRectGetHeight([self bounds]) - 1)];
[_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_textField setLineBreakMode:CPLineBreakByTruncatingTail];
[_textField setTextColor: [CPColor colorWithHexString: @"333333"]];
[_textField setFont:[CPFont boldSystemFontOfSize:12.0]];
[_textField setAlignment:CPLeftTextAlignment];
[_textField setVerticalAlignment:CPCenterVerticalTextAlignment];
[_textField setTextShadowColor:[CPColor whiteColor]];
[_textField setTextShadowOffset:CGSizeMake(0,1)];
[self addSubview:_textField];
}
- (void)layoutSubviews
{
var themeState = [self themeState];
if((themeState & CPThemeStateSelected) && (themeState & CPThemeStatePressed))
if(themeState & CPThemeStateHighlighted && themeState & CPThemeStatePressed)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted-pressed.png", CGSizeMake(1.0, 22.0))]];
else if (themeState == CPThemeStateSelected)
else if (themeState & CPThemeStateHighlighted)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted.png", CGSizeMake(1.0, 22.0))]];
else if (themeState == CPThemeStatePressed)
else if (themeState & CPThemeStatePressed)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-pressed.png", CGSizeMake(1.0, 22.0))]];
else
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
@@ -68,12 +74,12 @@ var CPThemeStatePressed = CPThemeState("pressed");
- (void)setStringValue:(CPString)string
{
[_textField setStringValue:string];
[_textField setText:string];
}
- (CPString)stringValue
{
return [_textField stringValue];
return [_textField text];
}
- (void)textField
@@ -86,10 +92,59 @@ var CPThemeStatePressed = CPThemeState("pressed");
[_textField sizeToFit];
}
- (void)setFont:(CPFont)aFont
{
[_textField setFont:aFont];
}
- (void)setValue:(id)aValue forThemeAttribute:(id)aKey
{
[_textField setValue:aValue forThemeAttribute:aKey];
}
- (void)_setIndicatorImage:(CPImage)anImage
{
if (anImage)
{
[_textField setImage:anImage];
[_textField setImagePosition:CPImageRight];
}
else
{
[_textField setImagePosition:CPNoImage];
}
}
@end
var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringValueKey",
_CPTableColumnHeaderViewFontKey = @"_CPTableColumnHeaderViewFontKey",
_CPTableColumnHeaderViewImageKey = @"_CPTableColumnHeaderViewImageKey";
@implementation _CPTableColumnHeaderView (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
[self _init];
[self _setIndicatorImage:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewImageKey]];
[self setStringValue:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewStringValueKey]];
[self setFont:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewFontKey]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:[_textField text] forKey:_CPTableColumnHeaderViewStringValueKey];
[aCoder encodeObject:[_textField image] forKey:_CPTableColumnHeaderViewImageKey];
[aCoder encodeObject:[_textField font] forKey:_CPTableColumnHeaderViewFontKey];
}
@end
@implementation CPTableHeaderView : CPView
@@ -111,9 +166,9 @@ var CPThemeStatePressed = CPThemeState("pressed");
if (self)
{
_resizedColumn = CPNotFound;
_draggedColumn = CPNotFound;
_pressedColumn = CPNotFound;
_resizedColumn = -1;
_draggedColumn = -1;
_pressedColumn = -1;
_draggedDistance = 0.0;
_lastLocation = nil;
_columnOldWidth = nil;
@@ -126,74 +181,49 @@ var CPThemeStatePressed = CPThemeState("pressed");
- (int)columnAtPoint:(CGPoint)aPoint
{
if (!CGRectContainsPoint([self bounds], aPoint))
return CPNotFound;
// at this point, we can essentially ignore height, because all columns have equal heights
// and that height is equal to the height of our own bounds, which we know we are inside of
var index = 0,
count = [[_tableView tableColumns] count],
tableSpacing = [_tableView intercellSpacing],
tableColumns = [_tableView tableColumns],
leftOffset = 0,
pointX = aPoint.x;
for (; index < count; index++)
{
var width = [tableColumns[index] width] + tableSpacing.width;
if (pointX >= leftOffset && pointX < leftOffset + width)
return index;
leftOffset += width;
}
return CPNotFound;
return [_tableView columnAtPoint:CGPointMake(aPoint.x, 0)];
}
- (CGRect)headerRectOfColumn:(int)aColumnIndex
{
var tableColumns = [_tableView tableColumns],
tableSpacing = [_tableView intercellSpacing],
bounds = [self bounds];
var tableColumns = [_tableView tableColumns];
if (aColumnIndex < 0 || aColumnIndex > [tableColumns count])
[CPException raise:"invalid" reason:"tried to get headerRectOfColumn: on invalid column"];
// UPDATE COLUMN RANGES ?
if (_tableView._dirtyTableColumnRangeIndex !== CPNotFound)
[_tableView _recalculateTableColumnRanges];
var tableRange = _tableView._tableColumnRanges[aColumnIndex];
var tableRange = _tableView._tableColumnRanges[aColumnIndex],
bounds = [self bounds];
bounds.origin.x = tableRange.location;
bounds.size.width = tableRange.length;
return bounds;
}
- (CPRect)_resizeRectBeforeColumn:(CPInteger)column
- (CGRect)_cursorRectForColumn:(int)column
{
if (!([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask))
if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask))
return CGRectMakeZero();
var rect = [self headerRectOfColumn:column];
rect.origin.x -= 10;
rect.origin.x = CGRectGetMaxX(rect) - 5;
rect.size.width = 20;
return rect;
return rect;
}
- (void)_setPressedColumn:(CPInteger)column
{
if (_pressedColumn != CPNotFound)
if (_pressedColumn != -1)
{
var headerView = [_tableView._tableColumns[_pressedColumn] headerView];
[headerView unsetThemeState:CPThemeStatePressed];
}
if (column != CPNotFound)
if (column != -1)
{
var headerView = [_tableView._tableColumns[column] headerView];
[headerView setThemeState:CPThemeStatePressed];
@@ -207,21 +237,22 @@ var CPThemeStatePressed = CPThemeState("pressed");
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
clickedColumn = [self columnAtPoint:mouseLocation];
if (clickedColumn == -1)
return;
// should we send column -1 ?
[_tableView _sendDelegateDidMouseDownInHeader:clickedColumn];
var resizeLocation = CGPointMake(mouseLocation.x + 10, mouseLocation.y),
resizedColumn = [self columnAtPoint:resizeLocation] - 1;
var resizeLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
resizedColumn = [self columnAtPoint:resizeLocation];
if (resizedColumn == -1)
return;
// 2 different tracking methods: one for resizing/stop-resizing, another one for selection/reordering
if ([_tableView allowsColumnResizing]
&& resizedColumn >= 0
&& CGRectContainsPoint([self _resizeRectBeforeColumn:(resizedColumn + 1)], mouseLocation))
if ([_tableView allowsColumnResizing] && [_tableView columnAutoresizingStyle] & CPTableViewUniformColumnAutoresizingStyle
&& CGRectContainsPoint([self _cursorRectForColumn:resizedColumn], mouseLocation))
{
_resizedColumn = resizedColumn;
[_tableView._tableColumns[_resizedColumn] setDisableResizingPosting:YES];
[_tableView setDisableAutomaticResizing:YES];
[self trackResizeWithEvent:theEvent];
}
else
@@ -240,34 +271,11 @@ var CPThemeStatePressed = CPThemeState("pressed");
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
clickedColumn = [self columnAtPoint:location];
[self _setPressedColumn:CPNotFound];
[self _setPressedColumn:-1];
if (clickedColumn == -1)
return;
if (clickedColumn != -1)
[_tableView _didClickTableColumn:clickedColumn modifierFlags:[theEvent modifierFlags]];
[_tableView _sendDelegateDidClickColumn:clickedColumn];
if ([_tableView allowsColumnSelection])
{
if ([theEvent modifierFlags] & CPCommandKeyMask)
{
if ([_tableView isColumnSelected:clickedColumn])
[_tableView deselectColumn:clickedColumn];
else if ([_tableView allowsMultipleSelection] == YES)
[_tableView selectColumnIndexes:[CPIndexSet indexSetWithIndex:clickedColumn] byExtendingSelection:YES];
}
else if ([theEvent modifierFlags] & CPShiftKeyMask)
{
// should be from clickedColumn to lastClickedColum with extending:(direction == previous selection)
var selectedIndexes = [_tableView selectedColumnIndexes],
startColumn = MIN(clickedColumn, [selectedIndexes lastIndex]),
endColumn = MAX(clickedColumn, [selectedIndexes firstIndex]);
[_tableView selectColumnIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(startColumn, endColumn - startColumn + 1)] byExtendingSelection:YES];
}
else
[_tableView selectColumnIndexes:[CPIndexSet indexSetWithIndex:clickedColumn] byExtendingSelection:NO];
}
return;
}
/*
@@ -287,26 +295,35 @@ var CPThemeStatePressed = CPThemeState("pressed");
tableColumn = [[_tableView tableColumns] objectAtIndex:_resizedColumn],
type = [anEvent type];
if (_lastLocation == nil) _lastLocation = location;
if (_columnOldWidth == nil) _columnOldWidth = [tableColumn width];
if (_lastLocation == nil)
_lastLocation = location;
if (_columnOldWidth == nil)
_columnOldWidth = [tableColumn width];
if (type === CPLeftMouseUp)
{
[self _updateResizeCursor:anEvent];
[tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
[tableColumn setDisableResizingPosting:NO];
_resizedColumn = CPNotFound;
[tableColumn setDisableResizingPosting:NO];
[_tableView setDisableAutomaticResizing:NO];
_resizedColumn = -1;
_lastLocation = nil;
_columnOldWidth = nil;
_columnOldWidth = nil;
return;
}
else if (type === CPLeftMouseDragged)
{
var newWidth = [tableColumn width] + location.x - _lastLocation.x;
if (newWidth >= [tableColumn minWidth])
if (newWidth < [tableColumn minWidth])
[[CPCursor resizeRightCursor] set];
else if (newWidth > [tableColumn maxWidth])
[[CPCursor resizeLeftCursor] set];
else
{
[tableColumn setWidth:newWidth];
// FIXME: there has to be a better way to do this...
@@ -314,31 +331,31 @@ var CPThemeStatePressed = CPThemeState("pressed");
// We need to figure out the exact cocoa behavior here though.
[_tableView resizeWithOldSuperviewSize:[_tableView bounds]];
_lastLocation = location;
[[CPCursor resizeLeftRightCursor] set];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
else
[[CPCursor resizeRightCursor] set];
}
[CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
- (void)_updateResizeCursor:(CPEvent)theEvent
{
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil];
var mouseOverLocation = CGPointMake(mouseLocation.x + 10, mouseLocation.y),
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
overColumn = [self columnAtPoint:mouseOverLocation];
var isInside = (overColumn > 0 && CGRectContainsPoint([self _resizeRectBeforeColumn:overColumn], mouseLocation));
if (isInside)
if (overColumn >= 0 && CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation))
{
var column = [[_tableView tableColumns] objectAtIndex:overColumn - 1];
if ([column width] == [column minWidth])
var tableColumn = [[_tableView tableColumns] objectAtIndex:overColumn],
width = [tableColumn width];
if (width == [tableColumn minWidth])
[[CPCursor resizeRightCursor] set];
else if (width == [tableColumn maxWidth])
[[CPCursor resizeLeftCursor] set];
else
[[CPCursor resizeLeftRightCursor] set];
}
@@ -451,3 +468,32 @@ var CPThemeStatePressed = CPThemeState("pressed");
}
@end
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
@implementation CPTableHeaderView (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_resizedColumn = -1;
_draggedColumn = -1;
_pressedColumn = -1;
_draggedDistance = 0.0;
_lastLocation = nil;
_columnOldWidth = nil;
_tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey];
}
@end
+325 -131
View File
@@ -126,8 +126,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
@ingroup appkit
@class CPTableView
CPTableView object displays record-oriented data in a table and allows the user to edit values and resize and rearrange columns.
A CPTableView requires you to set a dataSource which implements numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:
CPTableView object displays record-oriented data in a table and
allows the user to edit values and resize and rearrange columns.
A CPTableView requires you to set a dataSource which implements numberOfRowsInTableView:
and tableView:objectValueForTableColumn:row:
*/
@implementation CPTableView : CPControl
{
@@ -156,7 +158,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
BOOL _allowsColumnSelection;
BOOL _allowsMultipleSelection;
BOOL _allowsEmptySelection;
CPArray _sortDescriptors;
//Setting Display Attributes
CGSize _intercellSpacing;
float _rowHeight;
@@ -166,7 +169,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
unsigned _selectionHighlightMask;
CPColor _selectionHightlightColor;
unsigned _currentHighlightedTableColumn;
CPTableColumn _currentHighlightedTableColumn;
unsigned _gridStyleMask;
CPColor _gridColor;
@@ -199,6 +202,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
CPDragOperation _dragOperationDefaultMask;
int _retargetedDropRow;
CPDragOperation _retargetedDropOperation;
BOOL _disableAutomaticResizing @accessors(property=disableAutomaticResizing);
}
- (id)initWithFrame:(CGRect)aFrame
@@ -213,14 +218,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
_allowsMultipleSelection = NO;
_allowsEmptySelection = YES;
_allowsColumnSelection = NO;
_disableAutomaticResizing = NO;
_tableViewFlags = 0;
//Setting Display Attributes
_selectionHighlightMask = CPTableViewSelectionHighlightStyleRegular;
[self setUsesAlternatingRowBackgroundColors:NO];
[self setAlternatingRowBackgroundColors:[[CPColor whiteColor], /*[CPColor colorWithHexString:@"e4e7ff"]*/ [CPColor colorWithHexString:@"f5f9fc"]]];
[self setAlternatingRowBackgroundColors:[[CPColor whiteColor], [CPColor colorWithHexString:@"f5f9fc"]]];
_tableColumns = [];
_tableColumnRanges = [];
@@ -249,7 +254,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
_selectedColumnIndexes = [CPIndexSet indexSet];
_selectedRowIndexes = [CPIndexSet indexSet];
_currentHighlightedTableColumn = nil;
_sortDescriptors = [CPArray array];
_draggedRowIndexes = [CPIndexSet indexSet];
_verticalMotionCanDrag = YES;
_isSelectingSession = NO;
@@ -310,6 +318,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
if ([_dataSource respondsToSelector:@selector(tableView:writeRowsWithIndexes:toPasteboard:)])
_implementedDataSourceMethods |= CPTableViewDataSource_tableView_writeRowsWithIndexes_toPasteboard_;
if ([_dataSource respondsToSelector:@selector(tableView:sortDescriptorsDidChange:)])
_implementedDataSourceMethods |= CPTableViewDataSource_tableView_sortDescriptorsDidChange_;
[self reloadData];
}
@@ -356,8 +367,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
//Target-action Behavior
/*!
Sets the message sent to the target when the user double-clicks an uneditable cell or a column header to a given selector.
@param aSelector The message the receiver sends to its target when the user double-clicks an uneditable cell or a column header.
Sets the message sent to the target when the user double-clicks an
uneditable cell or a column header to a given selector.
@param aSelector The message the receiver sends to its target when the user
double-clicks an uneditable cell or a column header.
*/
- (void)setDoubleAction:(SEL)anAction
{
@@ -738,7 +751,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
*/
- (void)selectRowIndexes:(CPIndexSet)rows byExtendingSelection:(BOOL)shouldExtendSelection
{
if ([rows isEqualToIndexSet:_selectedRowIndexes] || (([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.
@@ -804,23 +818,31 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
deselectColumns = [],
selectColumns = [],
deselectColumnIndexes = [oldColumns copy],
selectColumnIndexes = [newColumns copy];
selectColumnIndexes = [newColumns copy],
selectRows = [];
[deselectColumnIndexes removeMatches:selectColumnIndexes];
[deselectColumnIndexes getIndexes:deselectColumns maxCount:-1 inIndexRange:CPMakeRange(firstExposedColumn, exposedLength)];
[selectColumnIndexes getIndexes:selectColumns maxCount:-1 inIndexRange:CPMakeRange(firstExposedColumn, exposedLength)];
var count = deselectColumns.length;
[_exposedRows getIndexes:selectRows maxCount:-1 inIndexRange:nil];
var rowsCount = selectRows.length,
count = deselectColumns.length;
while (count--)
{
var columnIndex = deselectColumns[count],
identifier = [_tableColumns[columnIndex] UID],
dataViewsInTableColumn = _dataViewsForTableColumns[identifier];
for (var i = 0; i < rowsCount; i++)
{
var rowIndex = selectRows[i],
dataView = dataViewsInTableColumn[rowIndex];
[dataView unsetThemeState:CPThemeStateHighlighted];
}
[dataViewsInTableColumn makeObjectsPerformSelector:@selector(unsetThemeState:) withObject:CPThemeStateHighlighted];
var headerView = [_tableColumns[columnIndex] headerView];
[headerView unsetThemeState:CPThemeStateSelected];
[headerView unsetThemeState:CPThemeStateHighlighted];
}
count = selectColumns.length;
@@ -829,10 +851,16 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
var columnIndex = selectColumns[count],
identifier = [_tableColumns[columnIndex] UID],
dataViewsInTableColumn = _dataViewsForTableColumns[identifier];
[dataViewsInTableColumn makeObjectsPerformSelector:@selector(setThemeState:) withObject:CPThemeStateHighlighted];
for (var i = 0; i < rowsCount; i++)
{
var rowIndex = selectRows[i],
dataView = dataViewsInTableColumn[rowIndex];
[dataView setThemeState:CPThemeStateHighlighted];
}
var headerView = [_tableColumns[columnIndex] headerView];
[headerView setThemeState:CPThemeStateSelected];
[headerView setThemeState:CPThemeStateHighlighted];
}
}
@@ -858,7 +886,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
{
var selectedRowIndexes = [_selectedRowIndexes copy];
[selectedRowIndexes removeIndex:aRow];
[self selectColumnIndexes:selectedRowIndexes byExtendingSelection:NO];
[self selectRowIndexes:selectedRowIndexes byExtendingSelection:NO];
[self _noteSelectionDidChange];
}
@@ -1179,15 +1207,19 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
- (void)resizeWithOldSuperviewSize:(CGSize)aSize
{
[super resizeWithOldSuperviewSize:aSize];
if (_disableAutomaticResizing)
return;
var mask = _columnAutoResizingStyle;
if(mask === CPTableViewUniformColumnAutoresizingStyle)
{
// FIX ME: needs to respect proportion of the the columns set width...
// this can also get slow when there are many rows
// do this by getting the width of the new size and subtracting it from the width of the old size dividing the difference by the number of visible rows.
// loop trough the rows one by one adding the quotient to each row be sure to check for min/max widths when doing it.
// this can also get slow when there are many rows do this by getting
// the width of the new size and subtracting it from the width of the old size dividing the
// difference by the number of visible rows. loop trough the rows one by one adding the quotient
// to each row be sure to check for min/max widths when doing it.
var superview = [self superview];
@@ -1195,16 +1227,18 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
return;
var superviewSize = [superview bounds].size;
UPDATE_COLUMN_RANGES_IF_NECESSARY();
var count = NUMBER_OF_COLUMNS();
var visColumns = [[CPArray alloc] init];
// Fixme: cache resizable columns because they won't changes betwwen two calls to this method.
for(var i=0; i < count; i++)
{
if(![_tableColumns[i] isHidden])
var tableColumn = _tableColumns[i];
if(![tableColumn isHidden] && ([tableColumn resizingMask] & CPTableColumnAutoresizingMask))
[visColumns addObject:i];
}
@@ -1213,17 +1247,25 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
//if there are rows
if (count > 0)
{
//get total width // don't let it be smaller than 15
var newWidth = MAX(15.0, superviewSize.width / count);
var g = superviewSize.width / aSize.width;
// g = (resizableWidth + superviewSize.width - aSize.width) / resizableWidth
buffer = 0.0;
//loop through all the rows again
for(var i = 0; i < count; i++)
// FIXME: do something smart about min/maxWidth and non-resizable columns
for (var i = 0; i < count; i++)
{
var columnToResize = _tableColumns[visColumns[i]];
var newWidth = MAX([columnToResize minWidth], superviewSize.width / count);
newWidth = (newWidth > [columnToResize maxWidth]) ? [columnToResize maxWidth] : newWidth;
[columnToResize setWidth:FLOOR(newWidth)];
var column = visColumns[i];
columnToResize = _tableColumns[column],
newWidth = g * [columnToResize width];
var fbuffer = FLOOR(buffer);
newWidth += fbuffer;
buffer -= fbuffer;
var fwidth = MAX([columnToResize minWidth], MIN(FLOOR(newWidth),[columnToResize maxWidth]));
buffer += newWidth - fwidth;
[columnToResize setWidth:fwidth];
}
}
@@ -1281,7 +1323,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
/*!
Sets the column autoresizing style of the receiver to a given style.
@param aStyle The column autoresizing style for the receiver. CPTableViewNoColumnAutoresizing, CPTableViewUniformColumnAutoresizingStyle, CPTableViewLastColumnOnlyAutoresizingStyle, CPTableViewFirstColumnOnlyAutoresizingStyle
@param aStyle The column autoresizing style for the receiver.
CPTableViewNoColumnAutoresizing, CPTableViewUniformColumnAutoresizingStyle,
CPTableViewLastColumnOnlyAutoresizingStyle, CPTableViewFirstColumnOnlyAutoresizingStyle
*/
- (void)setColumnAutoresizingStyle:(unsigned)style
{
@@ -1321,8 +1365,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
if (newSize > 0)
{
newSize = (newSize < [columnToResize minWidth]) ? [columnToResize minWidth] : newSize;
newSize = (newSize > [columnToResize maxWidth]) ? [columnToResize maxWidth] : newSize;
newSize = MAX([columnToResize minWidth], newSize);
newSize = MIN([columnToResize maxWidth], newSize);
[columnToResize setWidth:newSize];
}
}
@@ -1543,15 +1587,126 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
[_delegate tableView:self mouseDownInHeaderOfTableColumn:_tableColumns[column]];
}
//Highlightable Column Headers
/*
- (CPTableColumn)highlightedTableColumn
- (void)_sendDataSourceSortDescriptorsDidChange:(CPArray)oldDescriptors
{
if (_implementedDataSourceMethods & CPTableViewDataSource_tableView_sortDescriptorsDidChange_)
[_dataSource tableView:self sortDescriptorsDidChange:oldDescriptors];
}
- (void)_didClickTableColumn:(int)clickedColumn modifierFlags:(unsigned)modifierFlags
{
[self _sendDelegateDidClickColumn:clickedColumn];
if (_allowsColumnSelection)
{
if (modifierFlags & CPCommandKeyMask)
{
if ([self isColumnSelected:clickedColumn])
[self deselectColumn:clickedColumn];
else if ([self allowsMultipleSelection] == YES)
[self selectColumnIndexes:[CPIndexSet indexSetWithIndex:clickedColumn] byExtendingSelection:YES];
return;
}
else if (modifierFlags & CPShiftKeyMask)
{
// should be from clickedColumn to lastClickedColum with extending:(direction == previous selection)
var startColumn = MIN(clickedColumn, [_selectedColumnIndexes lastIndex]),
endColumn = MAX(clickedColumn, [_selectedColumnIndexes firstIndex]);
[self selectColumnIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(startColumn, endColumn - startColumn + 1)]
byExtendingSelection:YES];
return;
}
else
[self selectColumnIndexes:[CPIndexSet indexSetWithIndex:clickedColumn] byExtendingSelection:NO];
}
[self _changeSortDescriptorsForClickOnColumn:clickedColumn];
}
// From GNUSTEP
- (void)_changeSortDescriptorsForClickOnColumn:(int)column
{
var tableColumn = [_tableColumns objectAtIndex:column],
newMainSortDescriptor = [tableColumn sortDescriptorPrototype];
if (!newMainSortDescriptor)
return;
var oldMainSortDescriptor = nil,
oldSortDescriptors = [self sortDescriptors],
newSortDescriptors = [CPArray arrayWithArray:oldSortDescriptors],
e = [newSortDescriptors objectEnumerator],
descriptor = nil,
outdatedDescriptors = [CPArray array];
if ([_sortDescriptors count] > 0)
oldMainSortDescriptor = [[self sortDescriptors] objectAtIndex: 0];
// Remove every main descriptor equivalents (normally only one)
while ((descriptor = [e nextObject]) != nil)
{
if ([[descriptor key] isEqual: [newMainSortDescriptor key]])
[outdatedDescriptors addObject:descriptor];
}
// Invert the sort direction when the same column header is clicked twice
if ([[newMainSortDescriptor key] isEqual:[oldMainSortDescriptor key]])
newMainSortDescriptor = [oldMainSortDescriptor reversedSortDescriptor];
[newSortDescriptors removeObjectsInArray:outdatedDescriptors];
[newSortDescriptors insertObject:newMainSortDescriptor atIndex:0];
// Update indicator image & highlighted column before
var image = [newMainSortDescriptor ascending] ? [CPTableView _defaultTableHeaderSortImage] : [CPTableView _defaultTableHeaderReverseSortImage];
[self setIndicatorImage:nil inTableColumn:_currentHighlightedTableColumn];
[self setIndicatorImage:image inTableColumn:tableColumn];
[self setHighlightedTableColumn:tableColumn];
[self setSortDescriptors:newSortDescriptors];
}
- (void)setIndicatorImage:(CPImage)anImage inTableColumn:(CPTableColumn)aTableColumn
{
if (aTableColumn)
[[aTableColumn headerView] _setIndicatorImage:anImage];
}
+ (CPImage)_defaultTableHeaderSortImage
{
return CPAppKitImage("tableview-headerview-ascending.png", CGSizeMake(9.0, 8.0));
}
+ (CPImage)_defaultTableHeaderReverseSortImage
{
return CPAppKitImage("tableview-headerview-descending.png", CGSizeMake(9.0, 8.0));
}
//Highlightable Column Headers
- (CPTableColumn)highlightedTableColumn
{
return _currentHighlightedTableColumn;
}
- (void)setHighlightedTableColumn:(CPTableColumn)aTableColumn
{
if (_currentHighlightedTableColumn == aTableColumn)
return;
if (_currentHighlightedTableColumn != nil)
[[_currentHighlightedTableColumn headerView] unsetThemeState:CPThemeStateHighlighted];
if (aTableColumn != nil)
[[aTableColumn headerView] setThemeState:CPThemeStateHighlighted];
_currentHighlightedTableColumn = aTableColumn;
}
* - setHighlightedTableColumn:
*/
//Dragging
/*
* - dragImageForRowsWithIndexes:tableColumns:event:offset:
@@ -1648,7 +1803,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
row = 0;
if(row >= [self numberOfRows] && operation === CPTableViewDropOn)
[[CPException exceptionWithName:@"Error" reason:@"Attempt to set dropRow="+ row +", dropOperation=CPTableViewDropOn when [0 - "+ [self numberOfRows] +"] is valid range of rows." userInfo:nil] raise];
[CPException raise:CPInvalidArgumentException
reason:@"Attempt to set dropRow="+ row +", dropOperation=CPTableViewDropOn when [0 - "+
[self numberOfRows] +"] is valid range of rows."];
_retargetedDropRow = row;
_retargetedDropOperation = operation;
@@ -1687,12 +1844,28 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
- (void)setSortDescriptors:(CPArray)sortDescriptors
{
var oldSortDescriptors = [self sortDescriptors],
newSortDescriptors = nil;
//Sorting
/*
* - setSortDescriptors:
* - sortDescriptors
*/
if (sortDescriptors == nil)
newSortDescriptors = [CPArray array];
else
newSortDescriptors = [CPArray arrayWithArray:sortDescriptors];
if ([newSortDescriptors isEqual:oldSortDescriptors])
return;
_sortDescriptors = newSortDescriptors;
[self _sendDataSourceSortDescriptorsDidChange:oldSortDescriptors];
}
- (CPArray)sortDescriptors
{
return _sortDescriptors;
}
//Text Delegate Methods
/*
@@ -1920,15 +2093,12 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
- (void)_layoutDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
{
var rowArray = [],
rowRects = [],
var rowArray = [],
columnArray = [];
[rows getIndexes:rowArray maxCount:-1 inIndexRange:nil];
[columns getIndexes:columnArray maxCount:-1 inIndexRange:nil];
UPDATE_COLUMN_RANGES_IF_NECESSARY();
var columnIndex = 0,
columnsCount = columnArray.length;
@@ -1946,13 +2116,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
for (; rowIndex < rowsCount; ++rowIndex)
{
var row = rowArray[rowIndex],
dataView = dataViewsForTableColumn[row],
frame = [dataView frame];
dataView = dataViewsForTableColumn[row];
frame.origin.x = columnRange.location;
frame.size.width = columnRange.length;
[dataView setFrame:frame];
[dataView setFrame:[self frameOfDataViewAtColumn:column row:row]];
}
}
}
@@ -2157,7 +2323,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
if ([self selectionHighlightStyle] === CPTableViewSelectionHighlightStyleSourceList)
[[CPColor selectionColorSourceView] setFill];
else
[[CPColor selectionColor] setFill];
[[CPColor alternateSelectedControlColor] setFill];
var context = [[CPGraphicsContext currentContext] graphicsPort],
indexes = [],
@@ -2369,54 +2535,63 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
- (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
// 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(!_isSelectingSession && _implementedDataSourceMethods & CPTableViewDataSource_tableView_writeRowsWithIndexes_toPasteboard_)
{
if (
(ABS(_startTrackingPoint.x - aPoint.x) > 4 || (_verticalMotionCanDrag && ABS(_startTrackingPoint.y - aPoint.y) > 4)) ||
([_selectedRowIndexes containsIndex:row])
)
if ((ABS(_startTrackingPoint.x - aPoint.x) > 3 || (_verticalMotionCanDrag && ABS(_startTrackingPoint.y - aPoint.y) > 3)) ||
([_selectedRowIndexes containsIndex:row]))
{
if ([_selectedRowIndexes containsIndex:row])
_draggedRowIndexes = [[CPIndexSet alloc] initWithIndexSet:_selectedRowIndexes];
else
_draggedRowIndexes = [CPIndexSet indexSetWithIndex:row];
//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 ([_selectedRowIndexes containsIndex:row])
_draggedRowIndexes = [[CPIndexSet alloc] initWithIndexSet:_selectedRowIndexes];
else
_draggedRowIndexes = [CPIndexSet indexSetWithIndex:row];
//ask the datasource for the data
var pboard = [CPPasteboard pasteboardWithName:CPDragPboard];
if ([self canDragRowsWithIndexes:_draggedRowIndexes atPoint:aPoint] &&
[_dataSource tableView:self writeRowsWithIndexes:_draggedRowIndexes toPasteboard:pboard])
{
var currentEvent = [CPApp currentEvent],
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:tableColumns
event:currentEvent
offset:offset];
if (!view)
{
var currentEvent = [CPApp currentEvent],
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:tableColumns
event:currentEvent
offset:offset];
if (!view)
{
var image = [self dragImageForRowsWithIndexes:_draggedRowIndexes
tableColumns:tableColumns
event:currentEvent
offset:offset];
view = [[CPImageView alloc] initWithFrame:CPMakeRect(0, 0, [image size].width, [image size].height)];
[view setImage:image];
}
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];
_startTrackingPoint = nil;
return NO;
var image = [self dragImageForRowsWithIndexes:_draggedRowIndexes
tableColumns:tableColumns
event:currentEvent
offset:offset];
view = [[CPImageView alloc] initWithFrame:CPMakeRect(0, 0, [image size].width, [image size].height)];
[view setImage:image];
}
var bounds = [view bounds],
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];
_startTrackingPoint = nil;
return NO;
}
}
else if (ABS(_startTrackingPoint.x - aPoint.x) < 5 && ABS(_startTrackingPoint.y - aPoint.y) < 5)
return YES;
@@ -2643,7 +2818,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
[_dropOperationFeedbackView setCurrentRow:row];
[self addSubview:_dropOperationFeedbackView];
// FIXME : Maybe we should do this in a timer outside this method. Problem: we don't know when the scroll ends and neighter when the next -draggingUpdated is called. Which one will come first ?
// FIXME : Maybe we should do this in a timer outside this method.
// Problem: we don't know when the scroll ends or when the next -draggingUpdated is called.
if (row > 0 && location.y - CGRectGetMinY(exposedClipRect) < _rowHeight)
[self scrollRowToVisible:row - 1];
else if (row < numberOfRows && CGRectGetMaxY(exposedClipRect) - location.y < _rowHeight)
@@ -2711,11 +2887,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
- (void)_updateSelectionWithMouseAtRow:(CPInteger)aRow
{
//check to make sure the row exists
if(aRow < 0)
return;
var newSelection;
// If cmd/ctrl was held down XOR the old selection with the proposed selection
if ([self mouseDownFlags] & (CPCommandKeyMask | CPControlKeyMask | CPAlternateKeyMask))
{
@@ -2780,9 +2956,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
if ([newSelection isEqualToIndexSet:_selectedRowIndexes])
return;
[self selectRowIndexes:newSelection byExtendingSelection:NO];
}
- (void)_noteSelectionIsChanging
@@ -2918,14 +3092,22 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
@end
var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
CPTableViewDelegateKey = @"CPTableViewDelegateKey",
CPTableViewHeaderViewKey = @"CPTableViewHeaderViewKey",
CPTableViewTableColumnsKey = @"CPTableViewTableColumnsKey",
CPTableViewRowHeightKey = @"CPTableViewRowHeightKey",
CPTableViewIntercellSpacingKey = @"CPTableViewIntercellSpacingKey",
CPTableViewMultipleSelectionKey = @"CPTableViewMultipleSelectionKey",
CPTableViewEmptySelectionKey = @"CPTableViewEmptySelectionKey";
var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
CPTableViewDelegateKey = @"CPTableViewDelegateKey",
CPTableViewHeaderViewKey = @"CPTableViewHeaderViewKey",
CPTableViewTableColumnsKey = @"CPTableViewTableColumnsKey",
CPTableViewRowHeightKey = @"CPTableViewRowHeightKey",
CPTableViewIntercellSpacingKey = @"CPTableViewIntercellSpacingKey",
CPTableViewMultipleSelectionKey = @"CPTableViewMultipleSelectionKey",
CPTableViewEmptySelectionKey = @"CPTableViewEmptySelectionKey",
CPTableViewColumnReorderingKey = @"CPTableViewColumnReorderingKey",
CPTableViewColumnResizingKey = @"CPTableViewColumnResizingKey",
CPTableViewColumnSelectionKey = @"CPTableViewColumnSelectionKey",
CPTableViewGridColorKey = @"CPTableViewGridColorKey",
CPTableViewGridStyleMaskKey = @"CPTableViewGridStyleMaskKey",
CPTableViewUsesAlternatingBackgroundKey = @"CPTableViewUsesAlternatingBackgroundKey",
CPTableViewHeaderViewKey = @"CPTableViewHeaderViewKey",
CPTableViewCornerViewKey = @"CPTableViewCornerViewKey";
@implementation CPTableView (CPCoding)
@@ -2936,18 +3118,18 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
if (self)
{
//Configuring Behavior
_allowsColumnReordering = YES;
_allowsColumnResizing = YES;
_allowsColumnReordering = [aCoder decodeBoolForKey:CPTableViewColumnReorderingKey];
_allowsColumnResizing = [aCoder decodeBoolForKey:CPTableViewColumnResizingKey];
_allowsMultipleSelection = [aCoder decodeBoolForKey:CPTableViewMultipleSelectionKey];
_allowsEmptySelection = [aCoder decodeBoolForKey:CPTableViewEmptySelectionKey];
_allowsColumnSelection = NO;
_allowsColumnSelection = [aCoder decodeBoolForKey:CPTableViewColumnSelectionKey];
_tableViewFlags = 0;
//Setting Display Attributes
_selectionHighlightMask = CPTableViewSelectionHighlightStyleRegular;
[self setUsesAlternatingRowBackgroundColors:NO];
_usesAlternatingRowBackgroundColors = [aCoder decodeBoolForKey:CPTableViewUsesAlternatingBackgroundKey];
[self setAlternatingRowBackgroundColors:[[CPColor whiteColor], [CPColor colorWithHexString:@"e4e7ff"]]];
_tableColumns = [aCoder decodeObjectForKey:CPTableViewTableColumnsKey];
@@ -2965,18 +3147,19 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
_exposedColumns = [CPIndexSet indexSet];
_cachedDataViews = { };
_rowHeight = [aCoder decodeFloatForKey:CPTableViewRowHeightKey];
_intercellSpacing = [aCoder decodeSizeForKey:CPTableViewIntercellSpacingKey];
if ([aCoder containsValueForKey:CPTableViewIntercellSpacingKey])
_intercellSpacing = [aCoder decodeSizeForKey:CPTableViewIntercellSpacingKey];
else
_intercellSpacing = _CGSizeMake(0.0, 0.0);
_selectionHightlightColor = [CPColor selectionColor];
[self setGridColor:[CPColor grayColor]];
[self setGridStyleMask:CPTableViewGridNone];
_headerView = [[CPTableHeaderView alloc] initWithFrame:CGRectMake(0, 0, [self bounds].size.width, _rowHeight)];
[_headerView setTableView:self];
_cornerView = [[_CPCornerView alloc] initWithFrame:CGRectMake(0, 0, [CPScroller scrollerWidth], CGRectGetHeight([_headerView frame]))];
_gridColor = [aCoder decodeObjectForKey:CPTableViewGridColorKey] || [CPColor grayColor];
_gridStyleMask = [aCoder decodeIntForKey:CPTableViewGridStyleMaskKey] || CPTableViewGridNone;
_headerView = [aCoder decodeObjectForKey:CPTableViewHeaderViewKey];
_cornerView = [aCoder decodeObjectForKey:CPTableViewCornerViewKey];
_selectedColumnIndexes = [CPIndexSet indexSet];
_selectedRowIndexes = [CPIndexSet indexSet];
@@ -3003,11 +3186,22 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
[aCoder encodeFloat:_rowHeight forKey:CPTableViewRowHeightKey];
[aCoder encodeSize:_intercellSpacing forKey:CPTableViewIntercellSpacingKey];
[aCoder encodeBool:_allowsMultipleSelection forKey:CPTableViewMultipleSelectionKey];
[aCoder encodeBool:_allowsEmptySelection forKey:CPTableViewEmptySelectionKey];
[aCoder encodeBool:_allowsColumnReordering forKey:CPTableViewColumnReorderingKey];
[aCoder encodeBool:_allowsColumnResizing forKey:CPTableViewColumnResizingKey];
[aCoder encodeBool:_allowsColumnSelection forKey:CPTableViewColumnSelectionKey];
[aCoder encodeObject:_tableColumns forKey:CPTableViewTableColumnsKey];
[aCoder encodeObject:_gridColor forKey:CPTableViewGridColorKey];
[aCoder encodeInt:_gridStyleMask forKey:CPTableViewGridStyleMaskKey];
[aCoder encodeBool:_usesAlternatingRowBackgroundColors forKey:CPTableViewUsesAlternatingBackgroundKey];
[aCoder encodeObject:_cornerView forKey:CPTableViewCornerViewKey];
[aCoder encodeObject:_headerView forKey:CPTableViewHeaderViewKey];
}
@end
+1 -9
View File
@@ -29,14 +29,6 @@
#include "Platform/Platform.h"
#include "Platform/DOM/CPDOMDisplayServer.h"
CPLineBreakByWordWrapping = 0;
CPLineBreakByCharWrapping = 1;
CPLineBreakByClipping = 2;
CPLineBreakByTruncatingHead = 3;
CPLineBreakByTruncatingTail = 4;
CPLineBreakByTruncatingMiddle = 5;
CPTextFieldSquareBezel = 0; /*! A textfield bezel with a squared corners. */
CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */
@@ -169,7 +161,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), nil]
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), [CPNull null]]
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
}
+2 -2
View File
@@ -43,7 +43,7 @@
if (self)
{
_bundle = [[CPBundle alloc] initWithPath:aURL + "/Info.plist"];
_bundle = [[CPBundle alloc] initWithPath:aURL];
}
return self;
@@ -65,7 +65,7 @@
{
var path = [aBundle pathForResource:themes[count]],
unarchiver = [[_CPThemeKeyedUnarchiver alloc]
initForReadingWithData:[CPData dataWithString:objj_files[path].contents]
initForReadingWithData:[[CPURL URLWithString:path] staticResourceData]
bundle:_bundle];
[unarchiver decodeObjectForKey:@"root"];
+58 -56
View File
@@ -58,7 +58,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
/*!
@ingroup appkit
@class CPToolbar
A CPToolbar is displayed at the top of a window with multiple
buttons (tools) that offer the user quick access to features.
@@ -73,7 +73,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
Called to obtain the toolbar's default item identifiers. Required.
@param toolbar the toolbar to obtain identifiers for
@return an array of default item identifiers in the order on the toolbar
@delegate - (CPToolbarItem)toolbar:(CPToolbar)toolbar itemForItemIdentifier:(CPString)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag;
Called to obtain a toolbar item. Required.
@param toolbar the toolbar the item belongs to
@@ -89,19 +89,19 @@ var CPToolbarConfigurationsByIdentifier = nil;
BOOL _showsBaselineSeparator;
BOOL _allowsUserCustomization;
BOOL _isVisible;
id _delegate;
CPArray _itemIdentifiers;
CPDictionary _identifiedItems;
CPArray _defaultItems;
CPArray _allowedItems;
CPArray _selectableItems;
CPArray _items;
CPArray _itemsSortedByVisibilityPriority;
CPView _toolbarView;
CPWindow _window;
}
@@ -111,7 +111,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
{
if (self != [CPToolbar class])
return;
CPToolbarsByIdentifier = [CPDictionary dictionary];
CPToolbarConfigurationsByIdentifier = [CPDictionary dictionary];
}
@@ -120,13 +120,13 @@ var CPToolbarConfigurationsByIdentifier = nil;
+ (void)_addToolbar:(CPToolbar)toolbar forIdentifier:(CPString)identifier
{
var toolbarsSharingIdentifier = [CPToolbarsByIdentifier objectForKey:identifier];
if (!toolbarsSharingIdentifier)
{
toolbarsSharingIdentifier = []
[CPToolbarsByIdentifier setObject:toolbarsSharingIdentifier forKey:identifier];
}
[toolbarsSharingIdentifier addObject:toolbar];
}
@@ -143,17 +143,17 @@ var CPToolbarConfigurationsByIdentifier = nil;
- (id)initWithIdentifier:(CPString)anIdentifier
{
self = [super init];
if (self)
{
_items = [];
_identifier = anIdentifier;
_isVisible = YES;
[CPToolbar _addToolbar:self forIdentifier:_identifier];
}
return self;
}
@@ -163,7 +163,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
*/
- (void)setDisplayMode:(CPToolbarDisplayMode)aDisplayMode
{
}
/*!
@@ -198,7 +198,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
{
if (_isVisible === aFlag)
return;
_isVisible = aFlag;
[_window _noteToolbarChanged];
@@ -222,9 +222,9 @@ var CPToolbarConfigurationsByIdentifier = nil;
{
if (_delegate === aDelegate)
return;
_delegate = aDelegate;
[self _reloadToolbarItems];
}
@@ -240,12 +240,12 @@ var CPToolbarConfigurationsByIdentifier = nil;
if (!_toolbarView)
{
_toolbarView = [[_CPToolbarView alloc] initWithFrame:CPRectMake(0.0, 0.0, 1200.0, 59.0)];
[_toolbarView setToolbar:self];
[_toolbarView setAutoresizingMask:CPViewWidthSizable];
[_toolbarView reloadToolbarItems];
}
return _toolbarView;
}
@@ -289,14 +289,14 @@ var CPToolbarConfigurationsByIdentifier = nil;
if (item === nil)
[CPException raise:CPInvalidArgumentException
reason:@"Toolbar delegate " + _delegate + " returned nil toolbar item for identifier \"" + identifier + "\""];
item._toolbar = self;
[_items addObject:item];
}
// _items = [[self _defaultToolbarItems] mutableCopy];
// Store items sorted by priority. We want items to be removed first at the end of the array,
// items to be removed last at the front.
@@ -352,7 +352,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
[CPException raise:CPInvalidArgumentException
reason:sprintf(@"_delegate %s returned nil toolbar item returned for identifier %s", _delegate, identifier)];
}
[_identifiedItems setObject:item forKey:identifier];
}
@@ -361,7 +361,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
/* @ignore */
- (id)_itemsWithIdentifiers:(CPArray)identifiers
{
{
var items = [];
for (var i = 0; i < identifiers.length; i++)
[items addObject:[self _itemForItemIdentifier:identifiers[i] willBeInsertedIntoToolbar:NO]];
@@ -436,7 +436,7 @@ var CPToolbarIdentifierKey = @"CPToolbarIdentifierKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_identifier = [aCoder decodeObjectForKey:CPToolbarIdentifierKey];
@@ -512,10 +512,10 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
@implementation _CPToolbarView : CPView
{
CPToolbar _toolbar;
CPIndexSet _flexibleWidthIndexes;
CPIndexSet _visibleFlexibleWidthIndexes;
CPDictionary _itemInfos;
JSObject _viewsForToolbarItems;
@@ -525,7 +525,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
CPPopUpButton _additionalItemsButton;
CPColor _labelColor;
CPColor _labelShadowColor;
float _minWidth;
BOOL _FIXME_isHUD;
@@ -535,9 +535,9 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
{
if (self !== [_CPToolbarView class])
return;
var bundle = [CPBundle bundleForClass:self];
_CPToolbarViewExtraItemsImage = [[CPImage alloc] initWithContentsOfFile: [bundle pathForResource:"_CPToolbarView/_CPToolbarViewExtraItemsImage.png"] size: CPSizeMake(10.0, 15.0)];
_CPToolbarViewExtraItemsAlternateImage = [[CPImage alloc] initWithContentsOfFile: [bundle pathForResource:"_CPToolbarView/_CPToolbarViewExtraItemsAlternateImage.png"] size:CGSizeMake(10.0, 15.0)];
@@ -546,23 +546,23 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_minWidth = 0;
_labelColor = [CPColor blackColor];
_labelShadowColor = [CPColor colorWithWhite:1.0 alpha:0.75];
_additionalItemsButton = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 15.0) pullsDown:YES];
[_additionalItemsButton setBordered:NO];
[_additionalItemsButton setImagePosition:CPImageOnly];
[[_additionalItemsButton menu] setShowsStateColumn:NO];
[_additionalItemsButton setAlternateImage:_CPToolbarViewExtraItemsAlternateImage];
}
return self;
}
@@ -612,14 +612,14 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
_visibleItems = items;
// We only have hidden items if our actual width is smaller than our
// We only have hidden items if our actual width is smaller than our
// minimum width for hiding items.
if (itemsWidth < minWidth)
{
itemsWidth -= TOOLBAR_EXTRA_ITEMS_WIDTH;
_visibleItems = [_visibleItems copy];
var itemsSortedByVisibilityPriority = [_toolbar itemsSortedByVisibilityPriority],
count = itemsSortedByVisibilityPriority.length;
@@ -678,18 +678,18 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
[view setHidden:NO];
}
var remainingSpace = itemsWidth - minWidth,
proportionate = 0.0;
// Continue to distribute space proportionately while we have it,
// and there are flexible items left that want it. (Those with max
// Continue to distribute space proportionately while we have it,
// and there are flexible items left that want it. (Those with max
// widths may eventually not want it anymore).
while (remainingSpace && [flexibleItemIndexes count])
{
// Divy out the space.
proportionate += remainingSpace / [flexibleItemIndexes count];
// Reset the remaining space to 0
remainingSpace = 0.0;
@@ -712,7 +712,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
[view setFrameSize:CGSizeMake(constrainedWidth, height)];
}
}
// Now that all the visible items are the correct width, give them their final frames.
var index = 0,
count = _visibleItems.length,
@@ -734,9 +734,9 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
{
var index = 0,
count = [items count];
_invisibleItems = [];
for (; index < count; ++index)
{
var item = items[index];
@@ -790,11 +790,11 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
hasNonSeparatorItem = YES;
[_additionalItemsButton addItemWithTitle:[item label]];
var menuItem = [_additionalItemsButton itemArray][index + 1];
[menuItem setImage:[item image]];
[menuItem setTarget:[item target]];
[menuItem setAction:[item action]];
}
@@ -808,14 +808,14 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
// Get rid of all our current subviews.
var subviews = [self subviews],
count = subviews.length;
while (count--)
[subviews[count] removeFromSuperview];
// Populate with new subviews.
var items = [_toolbar items],
index = 0;
count = items.length;
_minWidth = TOOLBAR_ITEM_MARGIN;
@@ -842,13 +842,13 @@ var _CPToolbarItemVisibilityPriorityCompare = function(lhs, rhs)
{
var lhsVisibilityPriority = [lhs visibilityPriority],
rhsVisibilityPriority = [rhs visibilityPriority];
if (lhsVisibilityPriority == rhsVisibilityPriority)
return CPOrderedSame;
if (lhsVisibilityPriority > rhsVisibilityPriority)
return CPOrderedAscending;
return CPOrderedDescending;
}
@@ -984,6 +984,8 @@ var TOP_MARGIN = 5.0,
[_labelField setStringValue:[_toolbarItem label]];
[_labelField sizeToFit]; // FIXME
[self setEnabled:[_toolbarItem isEnabled]];
_labelSize = [_labelField frame].size;
_minSize = CGSizeMake(MAX(_labelSize.width, minSize.width), _labelSize.height + minSize.height + LABEL_MARGIN + TOP_MARGIN);
+1 -18
View File
@@ -26,26 +26,9 @@
@import <AppKit/CPImage.j>
@import <AppKit/CPView.j>
/*
@global
@class CPToolbarItem
*/
CPToolbarItemVisibilityPriorityStandard = 0;
/*
@global
@class CPToolbarItem
*/
CPToolbarItemVisibilityPriorityLow = -1000;
/*
@global
@class CPToolbarItem
*/
CPToolbarItemVisibilityPriorityHigh = 1000;
/*
@global
@class CPToolbarItem
*/
CPToolbarItemVisibilityPriorityUser = 2000;
CPToolbarSeparatorItemIdentifier = @"CPToolbarSeparatorItem";
@@ -197,7 +180,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
- (void)setToolTip:(CPString)aToolTip
{
if ([_view respondsToSelector:@selector(setToolTip:)])
[view setToolTip:aToolTip];
[_view setToolTip:aToolTip];
_toolTip = aToolTip;
}
+197
View File
@@ -87,6 +87,40 @@
[_childNodes[count] sortWithSortDescriptors:sortDescriptors recursively:YES];
}
- (CPEnumerator)preOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorPreOrder];
}
- (CPEnumerator)inOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorInOrder];
}
- (CPEnumerator)postOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorPostOrder];
}
- (CPEnumerator)levelOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorLevelOrder];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
if (aState.state !== 0)
return 0;
// FIXME: Change this to inorder when implemented?
var count = [[self preOrder] countByEnumeratingWithState:aState objects:objects count:aCount];
// Dangerous?
aState.state = YES;
return count;
}
@end
var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
@@ -117,3 +151,166 @@ var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
}
@end
var _CPTreeNodeEnumeratorPreOrder = 0,
_CPTreeNodeEnumeratorInOrder = 1,
_CPTreeNodeEnumeratorPostOrder = 2,
_CPTreeNodeEnumeratorLevelOrder = 3;
@implementation _CPTreeNodeEnumerator : CPEnumerator
{
int _order;
Object _state;
CPTreeNode _treeNode;
}
+ (_CPTreeNodeEnumerator)enumeratorWithTreeNode:(CPTreeNode)aTreeNode order:(int)anOrder
{
return [[self alloc] initWithTreeNode:aTreeNode order:anOrder];
}
- (id)initWithTreeNode:(CPTreeNode)aTreeNode order:(int)anOrder
{
self = [super init];
if (self)
{
_order = anOrder
_state = [self _newState];
_treeNode = aTreeNode;
}
return self;
}
- (id)_newState
{
return { stack:[_treeNode], visited:[CPSet set] };
}
- (id)_preOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
var stack = state.stack;
if (stack.length <= 0)
return nil;
if (shouldReturnAllObjects)
var allObjects = [];
while (stack.length)
{
var currentNode = stack.pop(),
childNodes = currentNode._childNodes,
count = childNodes.length;
while (count--)
stack.push(childNodes[count]);
if (shouldReturnAllObjects)
allObjects.push(currentNode);
else
return currentNode;
}
return allObjects;
}
- (id)_inOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
// Implement.
}
- (id)_postOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
var stack = state.stack;
if (stack.length <= 0)
return nil;
var visited = state.visited;
if (shouldReturnAllObjects)
var allObjects = [];
while (stack.length)
{
var currentNode = [stack lastObject],
childNodes = currentNode._childNodes,
originalCount = stack.length,
count = childNodes.length;
while (count--)
{
var treeNode = childNodes[count];
if ([visited containsObject:treeNode])
continue;
else
stack.push(treeNode);
}
if (originalCount === stack.length)
{
[visited addObject:currentNode];
if (shouldReturnAllObjects)
allObjects.push(stack.pop());
else
return stack.pop();
}
}
return allObjects;
}
- (id)_levelOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
// Implement.
}
- (id)nextObject
{
if (_order === _CPTreeNodeEnumeratorPreOrder)
return [self _preOrderFromState:[self _newState] allObjects:NO];
else if (_order === _CPTreeNodeEnumeratorInOrder)
return [self _inOrderFromState:[self _newState] allObjects:NO];
else if (_order === _CPTreeNodeEnumeratorPostOrder)
return [self _postOrderFromState:[self _newState] allObjects:NO];
//else if (_order === _CPTreeNodeEnumeratorLevelOrder)
return [self _levelOrderFromState:[self _newState] allObjects:NO];
}
- (CPArray)allObjects
{
if (_order === _CPTreeNodeEnumeratorPreOrder)
return [self _preOrderFromState:[self _newState] allObjects:YES];
else if (_order === _CPTreeNodeEnumeratorInOrder)
return [self _inOrderFromState:[self _newState] allObjects:YES];
else if (_order === _CPTreeNodeEnumeratorPostOrder)
return [self _postOrderFromState:[self _newState] allObjects:YES];
//else if (_order === _CPTreeNodeEnumeratorLevelOrder)
return [self _levelOrderFromState:[self _newState] allObjects:NO];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
if (aState.state !== 0)
return 0;
var count = [[self allObjects] countByEnumeratingWithState:aState objects:objects count:aCount];
// Dangerous?
aState.state = YES;
return count;
}
@end
+5 -3
View File
@@ -2135,7 +2135,8 @@ setBoundsOrigin:
var theClass = [self class],
CPViewClass = [CPView class],
attributes = [];
attributes = [],
nullValue = [CPNull null];
for (; theClass && theClass !== CPViewClass; theClass = [theClass superclass])
{
@@ -2159,9 +2160,10 @@ setBoundsOrigin:
while (attributeCount--)
{
var attributeName = attributeKeys[attributeCount];
var attributeName = attributeKeys[attributeCount],
attributeValue = [attributeDictionary objectForKey:attributeName];
attributes.push([attributeDictionary objectForKey:attributeName]);
attributes.push(attributeValue === nullValue ? nil : attributeValue);
attributes.push(attributeName);
}
}
+24 -13
View File
@@ -614,6 +614,13 @@ CPTexturedBackgroundWindowMask
@param shouldDisplay whether the window should redraw its views
@param shouldAnimate whether the window resize should be animated
*/
- (void)_setClippedFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
{
aFrame.size.width = MIN(MAX(aFrame.size.width, _minSize.width), _maxSize.width)
aFrame.size.height = MIN(MAX(aFrame.size.height, _minSize.height), _maxSize.height);
[self setFrame:aFrame display:shouldDisplay animate:shouldAnimate];
}
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
{
aFrame = _CGRectMakeCopy(aFrame);
@@ -673,8 +680,8 @@ CPTexturedBackgroundWindowMask
if (!_CGSizeEqualToSize(size, newSize))
{
size.width = MIN(MAX(newSize.width, _minSize.width), _maxSize.width);
size.height = MIN(MAX(newSize.height, _minSize.height), _maxSize.height);
size.width = newSize.width;
size.height = newSize.height;
[_windowView setFrameSize:size];
@@ -692,7 +699,7 @@ CPTexturedBackgroundWindowMask
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay
{
[super setFrame:aFrame display:shouldDisplay animate:NO];
[self _setClippedFrame:aFrame display:shouldDisplay animate:NO];
}
/*!
@@ -700,7 +707,7 @@ CPTexturedBackgroundWindowMask
*/
- (void)setFrame:(CGRect)aFrame
{
[self setFrame:aFrame display:YES animate:NO];
[self _setClippedFrame:aFrame display:YES animate:NO];
}
/*!
@@ -709,7 +716,7 @@ CPTexturedBackgroundWindowMask
*/
- (void)setFrameOrigin:(CGPoint)anOrigin
{
[self setFrame:_CGRectMake(anOrigin.x, anOrigin.y, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame)) display:YES animate:NO];
[self _setClippedFrame:_CGRectMake(anOrigin.x, anOrigin.y, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame)) display:YES animate:NO];
}
/*!
@@ -718,7 +725,7 @@ CPTexturedBackgroundWindowMask
*/
- (void)setFrameSize:(CGSize)aSize
{
[self setFrame:_CGRectMake(_CGRectGetMinX(_frame), _CGRectGetMinY(_frame), aSize.width, aSize.height) display:YES animate:NO];
[self _setClippedFrame:_CGRectMake(_CGRectGetMinX(_frame), _CGRectGetMinY(_frame), aSize.width, aSize.height) display:YES animate:NO];
}
/*!
@@ -1141,7 +1148,7 @@ CPTexturedBackgroundWindowMask
\c aResponder accept first responder, then finally tell it to become first responder.
@return \c YES if the attempt was successful. \c NO otherwise.
*/
- (void)makeFirstResponder:(CPResponder)aResponder
- (BOOL)makeFirstResponder:(CPResponder)aResponder
{
if (_firstResponder == aResponder)
return YES;
@@ -1908,8 +1915,8 @@ CPTexturedBackgroundWindowMask
sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect);
sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0);
[attachedSheet setFrameOrigin:sheetFrame.origin];
[attachedSheet setFrame:sheetFrame display:YES animate:NO];
}
/* @ignore */
@@ -1943,7 +1950,7 @@ CPTexturedBackgroundWindowMask
[CPApp runModalForWindow:aSheet];
[aSheet orderFront:self];
[aSheet setFrame:startFrame];
[aSheet setFrame:startFrame display:YES animate:NO];
_sheetContext["opened"] = YES;
[aSheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseOut];
@@ -2499,9 +2506,13 @@ var interpolate = function(fromValue, toValue, progress)
if (value == 1.0)
_window._isAnimating = NO;
[_window setFrameOrigin:CGPointMake(interpolate(CGRectGetMinX(_startFrame), CGRectGetMinX(_targetFrame), value), interpolate(CGRectGetMinY(_startFrame), CGRectGetMinY(_targetFrame), value))];
[_window setFrameSize:CGSizeMake(interpolate(CGRectGetWidth(_startFrame), CGRectGetWidth(_targetFrame), value), interpolate(CGRectGetHeight(_startFrame), CGRectGetHeight(_targetFrame), value))];
var newFrame = CGRectMake(interpolate(CGRectGetMinX(_startFrame), CGRectGetMinX(_targetFrame), value),
interpolate(CGRectGetMinY(_startFrame), CGRectGetMinY(_targetFrame), value),
interpolate(CGRectGetWidth(_startFrame), CGRectGetWidth(_targetFrame), value),
interpolate(CGRectGetHeight(_startFrame), CGRectGetHeight(_targetFrame), value));
[_window setFrame:newFrame display:YES animate:NO];
}
@end
+1 -1
View File
@@ -171,7 +171,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)data
{
_data = [CPData dataWithString:data];
_data = [CPData dataWithEncodedString:data];
}
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
+1 -1
View File
@@ -32,7 +32,7 @@
var selectorName = _label,
selectorNameLength = [selectorName length];
if (selectorNameLength && selectorName[selectorNameLength - 1] !== ':')
if (selectorNameLength && selectorName.charAt(selectorNameLength - 1) !== ':')
selectorName += ':';
var selector = CPSelectorFromString(selectorName);
+39 -19
View File
@@ -27,8 +27,6 @@
var CPCibOwner = @"CPCibOwner";
var LoadInfoForCib = {};
@implementation CPObject (CPCibLoading)
- (void)awakeFromCib
@@ -63,9 +61,11 @@ var LoadInfoForCib = {};
+ (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable loadDelegate:aDelegate
{
var cib = [[CPCib alloc] initWithContentsOfURL:anAbsolutePath loadDelegate:self];
LoadInfoForCib[[cib UID]] = { loadDelegate:aDelegate, externalNameTable:aNameTable };
[[CPCib alloc]
initWithContentsOfURL:anAbsolutePath
loadDelegate:[[_CPCibLoadDelegate alloc]
initWithLoadDelegate:aDelegate
externalNameTable:aNameTable]];
}
+ (void)loadCibNamed:(CPString)aName owner:(id)anOwner loadDelegate:(id)aDelegate
@@ -82,20 +82,40 @@ var LoadInfoForCib = {};
- (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable loadDelegate:(id)aDelegate
{
var cib = [[CPCib alloc] initWithCibNamed:aFileName bundle:self loadDelegate:[self class]];
LoadInfoForCib[[cib UID]] = { loadDelegate:aDelegate, externalNameTable:aNameTable };
}
+ (void)cibDidFinishLoading:(CPCib)aCib
{
var loadInfo = LoadInfoForCib[[aCib UID]];
delete LoadInfoForCib[[aCib UID]];
[aCib instantiateCibWithExternalNameTable:loadInfo.externalNameTable];
[loadInfo.loadDelegate cibDidFinishLoading:aCib];
[[CPCib alloc]
initWithCibNamed:aFileName
bundle:self
loadDelegate:[[_CPCibLoadDelegate alloc]
initWithLoadDelegate:aDelegate
externalNameTable:aNameTable]];
}
@end
@implementation _CPCibLoadDelegate : CPObject
{
id _loadDelegate;
CPDictionary _externalNameTable;
}
- (id)initWithLoadDelegate:(id)aLoadDelegate externalNameTable:(id)anExternalNameTable
{
self = [self init];
if (self)
{
_loadDelegate = aLoadDelegate;
_externalNameTable = anExternalNameTable;
}
return self;
}
- (void)cibDidFinishLoading:(CPCib)aCib
{
[aCib instantiateCibWithExternalNameTable:_externalNameTable];
[_loadDelegate cibDidFinishLoading:aCib];
}
@end
+4 -1
View File
@@ -20,6 +20,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
if (typeof window["CPPlatformEnableHTMLDragAndDrop"] === "undefined")
CPPlatformEnableHTMLDragAndDrop = NO;
CPPlatformDidClearBodyElementNotification = @"CPPlatformDidClearBodyElementNotification";
CPPlatformWillClearBodyElementNotification = @"CPPlatformWillClearBodyElementNotification";
@@ -46,7 +49,7 @@ var screenNeedsInitialization = NO,
+ (BOOL)supportsDragAndDrop
{
return CPFeatureIsCompatible(CPHTMLDragAndDropFeature) && ![self isBrowser];
return CPFeatureIsCompatible(CPHTMLDragAndDropFeature) && (CPPlatformEnableHTMLDragAndDrop || ![self isBrowser]);
}
+ (BOOL)supportsNativeMainMenu
+3
View File
@@ -85,6 +85,9 @@ var DOMSpanElement = nil,
aFont = DefaultFont;
}
if (!DOMIFrameElement)
[self createDOMElements];
var style = DOMSpanElement.style;
if (!aWidth)
Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

+2 -2
View File
@@ -100,7 +100,7 @@
+ (CPButton)themedStandardButton
{
var button = [self button];
[button setTitle:@"Cancel"];
return button;
@@ -552,7 +552,7 @@
[segmentedControl setWidth:40.0 forSegment:0];
[segmentedControl setLabel:@"foo" forSegment:0];
[segmentedControl setTag:1 forSegment:0];
[segmentedControl setWidth:60.0 forSegment:1];
[segmentedControl setLabel:@"bar" forSegment:1];
[segmentedControl setTag:2 forSegment:1];
+1 -1
View File
@@ -40,7 +40,7 @@ var ItemSizes = { },
// Grab Theme Descriptor Classes.
var themeDescriptorClasses = [];
for (candidate in window)
for (candidate in global)
{
var theClass = objj_getClass(candidate),
theClassName = class_getName(theClass);
+16 -15
View File
@@ -32,7 +32,7 @@ BlendTask.prototype.infoPlist = function()
{
var infoPlist = BundleTask.prototype.infoPlist.apply(this, arguments);
infoPlist.setValue("CPKeyedThemes", require("util").unique(this._keyedThemes));
infoPlist.setValueForKey("CPKeyedThemes", require("util").unique(this._keyedThemes));
return infoPlist;
}
@@ -60,7 +60,7 @@ BlendTask.prototype.defineSourceTasks = function()
BlendTask.prototype.defineThemeDescriptorTasks = function()
{
this.flattenedEnvironments().forEach(function(anEnvironment)
this.environments().forEach(function(anEnvironment)
{
var folder = anEnvironment.name() + ".environment",
themeDescriptors = this.themeDescriptors(),
@@ -72,20 +72,20 @@ BlendTask.prototype.defineThemeDescriptorTasks = function()
this.enhance(themesTaskName);
objj_import(themeDescriptors.toArray(), YES, function()
themeDescriptors.forEach(function(/*CPString*/ themeDescriptorPath)
{
[BKThemeDescriptor allThemeDescriptorClasses].forEach(function(aClass)
{
var keyedThemePath = FILE.join(intermediatesPath, [aClass themeName] + ".keyedtheme");
filedir (keyedThemePath, themesTaskName);
filedir (staticPath, [keyedThemePath]);
keyedThemes.push([aClass themeName] + ".keyedtheme");
});
objj_importFile(FILE.absolute(themeDescriptorPath), YES);
});
require("browser/timeout").serviceTimeouts();
[BKThemeDescriptor allThemeDescriptorClasses].forEach(function(aClass)
{
var keyedThemePath = FILE.join(intermediatesPath, [aClass themeName] + ".keyedtheme");
filedir (keyedThemePath, themesTaskName);
filedir (staticPath, [keyedThemePath]);
keyedThemes.push([aClass themeName] + ".keyedtheme");
});
task (themesTaskName, function()
{
@@ -101,7 +101,8 @@ BlendTask.prototype.defineThemeDescriptorTasks = function()
// No filedir in this case, so we have to make it ourselves.
FILE.mkdirs(intermediatesPath);
FILE.write(FILE.join(intermediatesPath, [aClass themeName] + ".keyedtheme"), MARKER_TEXT + ";" + fileContents.length + ";" + fileContents, { charset:"UTF-8" });
// FIXME: MARKER_TEXT isn't global, so we use "t;".
FILE.write(FILE.join(intermediatesPath, [aClass themeName] + ".keyedtheme"), "t;" + fileContents.length + ";" + fileContents, { charset:"UTF-8" });
});
});
}, this);
@@ -158,7 +159,7 @@ function themeFromCibData(data)
[templates makeObjectsPerformSelector:@selector(blendAddThemedObjectAttributesToTheme:) withObject:theme];
return [[CPKeyedArchiver archivedDataWithRootObject:theme] string];
return [[CPKeyedArchiver archivedDataWithRootObject:theme] encodedString];
}
@implementation CPCib (BlendAdditions)
+17
View File
@@ -15,4 +15,21 @@
return self;
}
- (void)drawRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSetStrokeColor(context, [CPColor colorWithHexString:@"dce0e2"]);
var points = [
CGPointMake(aRect.origin.x, aRect.origin.y),
CGPointMake(aRect.origin.x + aRect.size.width, aRect.origin.y),
CGPointMake(aRect.origin.x, aRect.origin.y + 0.5),
CGPointMake(aRect.origin.x, aRect.origin.y + aRect.size.height)
];
CGContextStrokeLineSegments(context, points, 2);
}
@end
+16 -21
View File
@@ -83,16 +83,17 @@
+ (id)alloc
{
var a = [];
a.isa = self;
var array = [];
array.isa = self;
var ivars = class_copyIvarList(self),
count = ivars.length;
while (count--)
a[ivar_getName(ivars[count])] = nil;
array[ivar_getName(ivars[count])] = nil;
return a;
return array;
}
-(id)initWithKey:(id)aKey forProxyObject:(id)anObject
@@ -293,20 +294,6 @@
[self _setRepresentedObject:target];
}
- (CPArray)objectsAtIndexes:(CPIndexSet)indexes
{
var index = [indexes firstIndex],
objects = [];
while(index != CPNotFound)
{
[objects addObject:[self objectAtIndex:index]];
index = [indexes indexGreaterThanIndex:index];
}
return objects;
}
@end
@@ -352,9 +339,17 @@
if (aKeyPath.indexOf("@") === 0)
{
var dotIndex = aKeyPath.indexOf("."),
operator = aKeyPath.substring(1, dotIndex),
parameter = aKeyPath.substring(dotIndex+1);
operator,
parameter;
if (dotIndex !== -1)
{
operator = aKeyPath.substring(1, dotIndex);
parameter = aKeyPath.substring(dotIndex+1);
}
else
operator = aKeyPath.substring(1);
if (kvoOperators[operator])
return kvoOperators[operator](self, _cmd, parameter);
+33 -3
View File
@@ -55,6 +55,11 @@
return [_array objectAtIndex:_index];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
return [_array countByEnumeratingWithState:aState objects:objects count:aCount];
}
@end
/* @ignore */
@@ -657,7 +662,7 @@
rhs = anArray[index];
// If they're not equal, and either doesn't have an isa, or they're !isEqual (not isEqual)
if (lhs !== rhs && (!lhs.isa || !rhs.isa || ![lhs isEqual:rhs]))
if (lhs !== rhs && (lhs && !lhs.isa || rhs && !rhs.isa || ![lhs isEqual:rhs]))
return NO;
}
@@ -816,8 +821,8 @@
if (index === 0)
description += '\n';
var object = self[index],
objectDescription = object && object.isa ? [object description] : object + "";
var object = [self objectAtIndex:index],
objectDescription = object && object.isa ? [object description] : String(object);
description += "\t" + objectDescription.split('\n').join("\n\t");
@@ -1206,6 +1211,31 @@
@end
@implementation CPArray (CPFastEnumeration)
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
var count = [self count],
index = aState.state;
if (index >= count)
return 0;
var indexIndex = 0,
last = MIN(index + aCount, count);
aCount = last - index;
for (; index < last; ++index, ++indexIndex)
objects[indexIndex] = [self objectAtIndex:index];
aState.state = last;
return aCount;
}
@end
@implementation CPArray (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
+16 -1
View File
@@ -638,7 +638,22 @@
*/
- (void)removeAttribute:(CPString)anAttribute range:(CPRange)aRange
{
[self addAttribute:anAttribute value:nil range:aRange];
[self beginEditing];
var startingEntryIndex = [self _indexOfRangeEntryForIndex:aRange.location splitOnMaxIndex:YES],
endingEntryIndex = [self _indexOfRangeEntryForIndex:CPMaxRange(aRange) splitOnMaxIndex:YES],
current = startingEntryIndex;
if (endingEntryIndex == CPNotFound)
endingEntryIndex = _rangeEntries.length;
while (current < endingEntryIndex)
[_rangeEntries[current++].attributes removeObjectForKey:anAttribute];
//necessary?
[self _coalesceRangeEntriesFromIndex:startingEntryIndex toIndex:endingEntryIndex];
[self endEditing];
}
//Changing Characters and Attributes
+56 -103
View File
@@ -25,51 +25,50 @@
@import "CPURLRequest.j"
/*!
/*!
@class CPBundle
@ingroup foundation
@brief Groups information about an application's code & resources.
*/
var CPBundlesForPaths = { };
@implementation CPBundle : CPObject
{
//properties set up in file.js
//this.path = NULL;
//this.info = NULL;
//this._URIMap = { };
}
+ (id)alloc
{
return new objj_bundle;
CFBundle _bundle;
id _delegate;
}
+ (CPBundle)bundleWithPath:(CPString)aPath
{
return objj_getBundleWithPath(aPath);
return [[self alloc] initWithPath:aPath];
}
+ (CPBundle)bundleForClass:(Class)aClass
{
return objj_bundleForClass(aClass);
return [self bundleWithPath:CFBundle.bundleForClass(aClass).path()];
}
+ (CPBundle)mainBundle
{
return [CPBundle bundleWithPath:"Info.plist"];
return [CPBundle bundleWithPath:CFBundle.mainBundle().path()];
}
- (id)initWithPath:(CPString)aPath
{
var existingBundle = CPBundlesForPaths[aPath];
if (existingBundle)
return existingBundle;
self = [super init];
if (self)
{
path = aPath;
objj_setBundleForPath(path, self);
_bundle = new CFBundle(aPath);
CPBundlesForPaths[aPath] = self;
}
return self;
}
@@ -80,134 +79,88 @@
- (CPString)bundlePath
{
return [path stringByDeletingLastPathComponent];
return _bundle.path();
}
- (CPString)resourcePath
{
var resourcePath = [self bundlePath];
if (resourcePath.length)
resourcePath += '/';
return resourcePath + "Resources";
}
- (Class)principalClass
{
var className = [self objectForInfoDictionaryKey:@"CPPrincipalClass"];
//[self load];
return className ? CPClassFromString(className) : Nil;
}
+ (CPString)mostEligibleEnvironmentFromArray:(CPArray)environments
{
return objj_mostEligibleEnvironmentFromArray(environments);
//[self load];
return className ? CPClassFromString(className) : Nil;
}
- (CPString)pathForResource:(CPString)aFilename
{
var actualPath = [self resourcePath] + '/' + aFilename,
mappedPath = _URIMap["Resources/" + aFilename];
if (mappedPath)
return mappedPath;
return actualPath;
return _bundle.pathForResource(aFilename);
}
- (CPDictionary)infoDictionary
{
return info;
return _bundle.infoDictionary();
}
- (id)objectForInfoDictionaryKey:(CPString)aKey
{
return [info objectForKey:aKey];
return _bundle.valueForInfoDictionary(aKey);
}
//
- (void)loadWithDelegate:(id)aDelegate
{
self._delegate = aDelegate;
self._infoConnection = [CPURLConnection connectionWithRequest:[CPURLRequest requestWithURL:[CPURL URLWithString:[self bundlePath] + "/Info.plist"]] delegate:self];
_delegate = aDelegate;
_bundle.addEventListener("load", function()
{
[_delegate bundleDidFinishLoading:self];
});
_bundle.addEventListener("error", function()
{
CPLog.error("Could not find bundle: " + self);
});
_bundle.load(NO);
}
- (CPArray)supportedEnvironments
- (CPArray)staticResourceURLs
{
return [self objectForInfoDictionaryKey:"CPBundleEnvironments"] || ["ObjJ"];
var staticResourceURLs = [],
staticResources = _bundle.staticResources(),
index = 0,
count = [staticResources count];
for (; index < count; ++index)
[staticResourceURLs addObject:[CPURL URLWithString:staticResources[index].path()]];
return staticResourceURLs;
}
- (CPArray)environments
{
return _bundle.environments();
}
- (CPString)mostEligibleEnvironment
{
return [[self class] mostEligibleEnvironmentFromArray:[self supportedEnvironments]];
}
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)data
{
if (aConnection === self._infoConnection)
{
info = CPPropertyListCreateFromData([CPData dataWithString:data]);
var environment = [self mostEligibleEnvironment];
if (!environment)
throw "Environment not supported for " + [self bundlePath] + ". Supported environments: " + [self objectForInfoDictionaryKey:"CPBundleEnvironments"] + ".";
[CPURLConnection connectionWithRequest:[CPURLRequest requestWithURL:[self bundlePath] + '/' + environment + ".environment/" + [self objectForInfoDictionaryKey:"CPBundleExecutable"]] delegate:self];
}
else
{
objj_decompile([data string], self);
var context = new objj_context();
if ([_delegate respondsToSelector:@selector(bundleDidFinishLoading:)])
context.didCompleteCallback = function() { [_delegate bundleDidFinishLoading:self]; };
var files = [[self objectForInfoDictionaryKey:@"CPBundleReplacedFiles"] objectForKey:[self mostEligibleEnvironment]],
count = files ? files.length : 0, // Perhaps no files? Be liberal in what you accept...
bundlePath = [self bundlePath];
while (count--)
{
var fileName = files[count];
if (fileName.indexOf(".j") === fileName.length - 2)
context.pushFragment(fragment_create_file(bundlePath + '/' + fileName, new objj_bundle(""), YES, NULL));
}
if (context.fragments.length)
context.evaluate();
else
[_delegate bundleDidFinishLoading:self];
}
}
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
{
if ([_delegate respondsToSelector:@selector(bundle:didFailWithError:)])
[_delegate bundle:self didFailWithError:anError];
CPLog.error("Could not find bundle: " + self);
}
- (void)connectionDidFinishLoading:(CPURLConnection)aConnection
{
return _bundle.mostEligibleEnvironment();
}
- (CPString)description
{
return [super description] + "(" + path + ")";
return [super description] + "(" + [self bundlePath] + ")";
}
@end
objj_bundle.prototype.isa = CPBundle;
objj_bundle.prototype.toString = function()
{
return [this description];
}
+46 -35
View File
@@ -23,7 +23,7 @@
@import "CPObject.j"
@import "CPString.j"
/*!
/*!
@class CPData
@ingroup foundation
@brief A Cappuccino wrapper for any data type.
@@ -33,88 +33,99 @@
@implementation CPData : CPObject
{
id _plistObject;
}
+ (id)alloc
{
return new objj_data();
return new CFMutableData();
}
+ (CPData)data
{
return [[self alloc] initWithPlistObject:nil];
return [[self alloc] init];
}
+ (CPData)dataWithString:(CPString)aString
+ (CPData)dataWithEncodedString:(CPString)aString
{
return [[self alloc] initWithString:aString];
return [[self alloc] initWithEncodedString:aString];
}
+ (CPData)dataWithPlistObject:(id)aPlistObject
+ (CPData)dataWithSerializedPlistObject:(id)aPlistObject
{
return [[self alloc] initWithPlistObject:aPlistObject];
return [[self alloc] initWithSerializedPlistObject:aPlistObject];
}
- (id)initWithString:(CPString)aString
+ (CPData)dataWithSerializedPlistObject:(id)aPlistObject format:(CPPropertyListFormat)aFormat
{
return [[self alloc] initWithSerializedPlistObject:aPlistObject format:aFormat];
}
- (id)initWithEncodedString:(CPString)aString
{
self = [super init];
if (self)
string = aString;
[self setEncodedString:aString];
return self;
}
- (id)initWithPlistObject:(id)aPlistObject
- (id)initWithSerializedPlistObject:(id)aPlistObject
{
self = [super init];
if (self)
_plistObject = aPlistObject;
[self setSerializedPlistObject:aPlistObject];
return self;
}
- (id)initWithSerializedPlistObject:(id)aPlistObject format:aFormat
{
self = [super init];
if (self)
[self setSerializedPlistObject:aPlistObject format:aFormat];
return self;
}
- (int)length
{
return [[self string] length];
return [[self encodedString] length];
}
- (CPString)description
{
return string;
return self.toString();
}
- (CPString)string
- (CPString)encodedString
{
if (!string && _plistObject)
string = [[CPPropertyListSerialization dataFromPropertyList:_plistObject format:CPPropertyList280NorthFormat_v1_0 errorDescription:NULL] string];
return string;
return self.encodedString();
}
- (void)setString:(CPString)aString
- (void)setEncodedString:(CPString)aString
{
string = aString;
_plistObject = nil;
self.setEncodedString(aString);
}
- (id)plistObject
- (id)serializedPlistObject
{
if (string && !_plistObject)
// Attempt to autodetect the format.
_plistObject = [CPPropertyListSerialization propertyListFromData:self format:0 errorDescription:NULL];
return _plistObject;
return self.serializedPropertyList();
}
- (void)setPlistObject:(id)aPlistObject
- (void)setSerializedPlistObject:(id)aPlistObject
{
string = nil;
_plistObject = aPlistObject;
self.setSerializedPropertyList(aPlistObject);
}
- (void)setSerializedPlistObject:(id)aPlistObject format:(CPPropertyListFormat)aFormat
{
self.setSerializedPropertyList(aPlistObject, aFormat);
}
@end
objj_data.prototype.isa = CPData;
CFData.prototype.isa = CPData;
CFMutableData.prototype.isa = CPData;
+1 -1
View File
@@ -153,7 +153,7 @@ var CPDateReferenceDate = new Date(Date.UTC(2001,1,1,0,0,0,0));
- (BOOL)isEqualToDate:(CPDate)anotherDate
{
return !(self < anotherDate || self > anotherDate);
return self === anotherDate || (anotherDate !== nil && anotherDate.isa && [anotherDate isKindOfClass:CPDate] && !(self < anotherDate || self > anotherDate));
}
- (CPComparisonResult)compare:(CPDate)anotherDate
+44 -107
View File
@@ -20,11 +20,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
//@import "CPRange.j"
@import "CPArray.j"
@import "CPObject.j"
@import "CPEnumerator.j"
@import "CPException.j"
/* @ignore */
@implementation _CPDictionaryValueEnumerator : CPEnumerator
{
@@ -83,7 +84,7 @@
*/
+ (id)alloc
{
return new objj_dictionary();
return new CFMutableDictionary();
}
/*!
@@ -301,7 +302,7 @@
*/
- (int)count
{
return count;
return _count;
}
/*!
@@ -321,7 +322,7 @@
values = [];
while (index--)
values.push(dictionary_getValue(self, [_keys[index]]));
values.push(self.valueForKey(_keys[index]));
return values;
}
@@ -347,10 +348,13 @@
*/
- (BOOL)isEqualToDictionary:(CPDictionary)aDictionary
{
var count = [self count];
if (count !== [aDictionary count])
return NO;
var index = count;
while (index--)
{
var currentKey = _keys[index],
@@ -360,7 +364,7 @@
if (lhsObject === rhsObject)
continue;
if (lhsObject.isa && rhsObject.isa && [lhsObject respondsToSelector:@selector(isEqual:)] && [lhsObject isEqual:rhsObject])
if (lhsObject && lhsObject.isa && rhsObject && rhsObject.isa && [lhsObject respondsToSelector:@selector(isEqual:)] && [lhsObject isEqual:rhsObject])
continue;
return NO;
@@ -370,21 +374,6 @@
}
/*
Instance.isEqualToDictionary(aDictionary)
{
if(this.count()!=aDictionary.count()) return NO;
var i= this._keys.count();
while(i--) if(this.objectForKey(this._keys[i])!=aDictionary.objectForKey(this._keys[i])) return NO;
return YES;
}
Instance.allKeys()
{
return this._keys;
}
Instance.allKeysForObject(anObject)
{
var i= 0,
@@ -395,17 +384,7 @@
return keys;
}
Instance.allValues()
{
return this._objects;
}
Instance.keyEnumerator()
{
return this._keys.objectEnumerator();
}
Instance.keysSortedByValueUsingSelector(aSelector)
{
var dictionary= this,
@@ -416,11 +395,6 @@
return this._keys.sortedArrayUsingSelector(objectSelector);
}
Instance.objectEnumerator()
{
return this._objects.objectEnumerator();
}
*/
/*!
Returns the object for the entry with key \c aKey.
@@ -454,25 +428,13 @@
return base.valueForKey(aKey);
}
//
Instance.addEntriesFromDictionary(aDictionary)
{
var key,
keyEnumerator= aDictionary.keyEnumerator();
while(key= keyEnumerator.nextObject()) this.setObjectForKey(aDictionary.objectForKey(key), key);
}
*/
/*!
Removes all the entries from the dictionary.
*/
- (void)removeAllObjects
{
_keys = [];
count = 0;
_buckets = {};
self.removeAllValues();
}
/*!
@@ -481,37 +443,22 @@
*/
- (void)removeObjectForKey:(id)aKey
{
dictionary_removeValue(self, aKey);
self.removeValueForKey(aKey);
}
/*!
Removes each entry in allKeys from the receiver.
@param allKeys an array of keys that will be removed from the dictionary
*/
- (void)removeObjectsForKeys:(CPArray)allKeys
- (void)removeObjectsForKeys:(CPArray)keysForRemoval
{
var index = allKeys.length;
var index = keysForRemoval.length;
while (index--)
dictionary_removeValue(self, allKeys[index]);
self.removeValueForKey(keysForRemoval[index]);
}
/*
Instance.removeObjectForKey(aKey)
{
var entry= this._dictionary[aKey];
if(entry)
{
var range= CPMakeRange(entry.index, 1);
this._keys.removeObjectsInRange(range);
this._objects.removeObjectsInRange(range);
delete this._dictionary[aKey];
}
}
Instance.setDictionary(aDictionary)
{
this._keys= CPArray.arrayWithArray(aDictionary.allKeys());
@@ -530,20 +477,8 @@
*/
- (void)setObject:(id)anObject forKey:(id)aKey
{
dictionary_setValue(self, aKey, anObject);
self.setValueForKey(aKey, anObject);
}
/*
Instance.setValueForKey(aValue, aKey)
{
if(!aValue) this.removeObjectForKey(aKey);
else this.setObjectForKey(aValue, aKey);
}
Instance.copy()
{
return CPDictionary.alloc().dictionaryWithDictionary(this);
}
*/
/*!
Take all the key/value pairs in aDictionary and apply them to this dictionary.
@@ -569,27 +504,7 @@
*/
- (CPString)description
{
var description = @"CPDictionary {\n";
var i = _keys.length;
while (i--)
{
description += _keys[i] + ":";
var object = _buckets[_keys[i]];
if (object && object.isa)
description += [object description];
else
description += object;
description += "\n";
}
description += "}";
return description;
return self.toString();
}
@end
@@ -617,6 +532,31 @@
@end
@implementation CPDictionary (CPFastEnumeration)
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
var count = [self count];
if (aState.state >= count)
return 0;
var keys = [self allKeys],
index = count,
objects = new Array(count);
while (index--)
objects[index] = [self objectForKey:keys[index]];
aState.items0 = objects;
aState.items1 = keys;
aState.state = count;
return count;
}
@end
/*!
@class CPMutableDictionary
@ingroup compatability
@@ -629,8 +569,5 @@
@end
objj_dictionary.prototype.isa = CPDictionary;
objj_dictionary.prototype.toString = function()
{
return [this description];
}
CFDictionary.prototype.isa = CPDictionary;
CFMutableDictionary.prototype.isa = CPMutableDictionary;
+7
View File
@@ -56,4 +56,11 @@
return [];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
// This is pretty terrible, but what do you expect.
return [[self allObjects] countByEnumeratingWithState:aState objects:objects count:aCount];
}
@end
+14 -7
View File
@@ -46,6 +46,7 @@ if (input == nil)
*/
@implementation CPException : CPObject
{
id _userInfo;
}
/*
@@ -53,7 +54,7 @@ if (input == nil)
*/
+ (id)alloc
{
return new objj_exception();
return new Error();
}
/*!
@@ -93,7 +94,7 @@ if (input == nil)
{
name = aName;
message = aReason;
userInfo = aUserInfo;
_userInfo = aUserInfo;
}
return self;
@@ -120,7 +121,7 @@ if (input == nil)
*/
- (CPDictionary)userInfo
{
return userInfo;
return _userInfo;
}
/*!
@@ -136,7 +137,7 @@ if (input == nil)
*/
- (void)raise
{
objj_exception_throw(self);
throw self;
}
@end
@@ -145,7 +146,7 @@ if (input == nil)
- (id)copy
{
return [[self class] exceptionWithName:name reason:message userInfo:userInfo];
return [[self class] exceptionWithName:name reason:message userInfo:_userInfo];
}
@end
@@ -169,7 +170,7 @@ var CPExceptionNameKey = "CPExceptionNameKey",
{
name = [aCoder decodeObjectForKey:CPExceptionNameKey];
message = [aCoder decodeObjectForKey:CPExceptionReasonKey];
userInfo = [aCoder decodeObjectForKey:CPExceptionUserInfoKey];
_userInfo = [aCoder decodeObjectForKey:CPExceptionUserInfoKey];
}
return self;
@@ -183,7 +184,7 @@ var CPExceptionNameKey = "CPExceptionNameKey",
{
[aCoder encodeObject:name forKey:CPExceptionNameKey];
[aCoder encodeObject:message forKey:CPExceptionReasonKey];
[aCoder encodeObject:userInfo forKey:CPExceptionUserInfoKey];
[aCoder encodeObject:_userInfo forKey:CPExceptionUserInfoKey];
}
@end
@@ -191,6 +192,7 @@ var CPExceptionNameKey = "CPExceptionNameKey",
// toll-free bridge Error to CPException
// [CPException alloc] uses an objj_exception, which is a subclass of Error
Error.prototype.isa = CPException;
Error.prototype._userInfo = NULL;
[CPException initialize];
@@ -198,3 +200,8 @@ function _CPRaiseInvalidAbstractInvocation(anObject, aSelector)
{
[CPException raise:CPInvalidArgumentException reason:@"*** -" + sel_getName(aSelector) + @" cannot be sent to an abstract object of class " + [anObject className] + @": Create a concrete instance!"];
}
function _CPReportLenientDeprecation(/*Class*/ aClass, /*SEL*/ oldSelector, /*SEL*/ newSelector)
{
console.warn("[" + CPStringFromClass(aClass) + " " + CPStringFromSelector(oldSelector) + "] is deprecated, using " + CPStringFromSelector(newSelector) + " instead.");
}
+26
View File
@@ -834,6 +834,32 @@ var CPIndexSetCountKey = @"CPIndexSetCountKey",
@end
@implementation CPIndexSet (CPFastEnumeration)
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
var rangeIndex = aState.state;
if (aState.state >= _ranges.length)
return 0;
var range = _ranges[rangeIndex],
index = 0,
start = range.location,
end = start + range.length,
indexes = new Array(range.length);
while (start < end)
indexes[index++] = start++;
aState.items = indexes;
++aState.state;
return range.length;
}
@end
/*!
@class CPMutableIndexSet
@ingroup compatability
+8 -9
View File
@@ -174,17 +174,16 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey";
- (id)valueForKeyPath:(CPString)aKeyPath
{
var keys = aKeyPath.split("."),
index = 0,
count = keys.length,
value = self;
var firstDotIndex = aKeyPath.indexOf(".");
for(; index < count; ++index)
value = [value valueForKey:keys[index]];
if (firstDotIndex === -1)
return [self valueForKey:aKeyPath];
return value;
var firstKeyComponent = aKeyPath.substring(0, firstDotIndex),
remainingKeyPath = aKeyPath.substring(firstDotIndex+1),
value = [self valueForKey:firstKeyComponent];
return [value valueForKeyPath:remainingKeyPath];
}
- (CPDictionary)dictionaryWithValuesForKeys:(CPArray)keys
+3 -4
View File
@@ -236,7 +236,6 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld,
var kvoClass = objj_allocateClassPair(currentClass, kvoClassName);
objj_registerClassPair(kvoClass);
_class_initialize(kvoClass);
//copy in the methods from our model subclass
var methodList = _CPKVOModelSubclass.method_list,
@@ -422,8 +421,8 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld,
if (type == CPKeyValueChangeReplacement || type == CPKeyValueChangeInsertion)
{
//FIXME: do we need to go through and replace "" with CPNull?
var oldValues = [[_targetObject mutableArrayValueForKeyPath:aKey] objectsAtIndexes:indexes];
[changes setValue:oldValues forKey:CPKeyValueChangeNewKey];
var newValues = [[_targetObject mutableArrayValueForKeyPath:aKey] objectsAtIndexes:indexes];
[changes setValue:newValues forKey:CPKeyValueChangeNewKey];
}
}
else
@@ -436,7 +435,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld,
[changes setObject:newValue forKey:CPKeyValueChangeNewKey];
}
}
var observers = [_observersForKey[aKey] allValues],
count = observers ? observers.length : 0;
+6 -6
View File
@@ -147,7 +147,7 @@ var _CPKeyedArchiverStringClass = Nil,
*/
+ (CPData)archivedDataWithRootObject:(id)anObject
{
var data = [CPData dataWithPlistObject:nil],
var data = [CPData dataWithSerializedPlistObject:nil],
archiver = [[self alloc] initForWritingWithMutableData:data];
[archiver encodeObject:anObject forKey:@"root"];
@@ -222,7 +222,7 @@ var _CPKeyedArchiverStringClass = Nil,
[_plistObject setObject:[self className] forKey:_CPKeyedArchiverArchiverKey];
[_plistObject setObject:@"100000" forKey:_CPKeyedArchiverVersionKey];
[_data setPlistObject:_plistObject];
[_data setSerializedPlistObject:_plistObject];
if (_delegate && _delegateSelectors & _CPKeyedArchiverDidFinishSelector)
[_delegate archiverDidFinish:self];
@@ -556,7 +556,7 @@ var _CPKeyedArchiverEncodeObject = function(self, anObject, isConditional)
if (!className)
className = theClass.name;
else
theClass = window[className];
theClass = CPClassFromString(className);
var classUID = [self._UIDs objectForKey:className];
@@ -566,14 +566,14 @@ var _CPKeyedArchiverEncodeObject = function(self, anObject, isConditional)
hierarchy = [];
[plistClass setObject:className forKey:_CPKeyedArchiverClassNameKey];
do
{
[hierarchy addObject:CPStringFromClass(theClass)];
} while (theClass = [theClass superclass]);
[plistClass setObject:hierarchy forKey:_CPKeyedArchiverClassesKey];
classUID = [self._plistObjects count];
[self._plistObjects addObject:plistClass];
[self._UIDs setObject:classUID forKey:className];
+1 -1
View File
@@ -142,7 +142,7 @@ var _CPKeyedUnarchiverArrayClass = Ni
if (self)
{
_archive = [data plistObject];
_archive = [data serializedPlistObject];
_objects = [CPArray arrayWithObject:[CPNull null]];
_plistObject = [_archive objectForKey:_CPKeyedArchiverTopKey];
+1 -376
View File
@@ -1,376 +1 @@
/*
* CPLog.j
* Foundation
*
* Created by Thomas Robinson.
* Copyright 2008, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
window.CPLogDisable = false;
var CPLogDefaultTitle = "Cappuccino";
var CPLogLevels = ["fatal", "error", "warn", "info", "debug", "trace"];
var CPLogDefaultLevel = CPLogLevels[3];
var _CPLogLevelsInverted = {};
for (var i = 0; i < CPLogLevels.length; i++)
_CPLogLevelsInverted[CPLogLevels[i]] = i;
var _CPLogRegistrations = {};
// helpers:
var _CPFormatLogMessage = function(aString, aLevel, aTitle)
{
var now = new Date();
aLevel = ( aLevel == null ? '' : ' [' + aLevel + ']' );
if (typeof sprintf == "function")
return sprintf("%4d-%02d-%02d %02d:%02d:%02d.%03d %s%s: %s",
now.getFullYear(), now.getMonth(), now.getDate(),
now.getHours(), now.getMinutes(), now.getSeconds(), now.getMilliseconds(),
aTitle, aLevel, aString);
else
return now + " " + aTitle + aLevel + ": " + aString;
}
// Register Functions:
// Register a logger for all levels, or up to an optional max level
function CPLogRegister(aProvider, aMaxLevel)
{
CPLogRegisterRange(aProvider, CPLogLevels[0], aMaxLevel || CPLogLevels[CPLogLevels.length-1]);
}
// Register a logger for a range of levels
function CPLogRegisterRange(aProvider, aMinLevel, aMaxLevel)
{
var min = _CPLogLevelsInverted[aMinLevel];
var max = _CPLogLevelsInverted[aMaxLevel];
if (min != undefined && max != undefined)
for (var i = 0; i <= max; i++)
CPLogRegisterSingle(aProvider, CPLogLevels[i]);
}
// Regsiter a logger for
function CPLogRegisterSingle(aProvider, aLevel)
{
if (_CPLogRegistrations[aLevel] == undefined)
_CPLogRegistrations[aLevel] = [aProvider];
else
_CPLogRegistrations[aLevel].push(aProvider);
}
// Main CPLog, which dispatches to individual loggers
function _CPLogDispatch(parameters, aLevel, aTitle)
{
if (aTitle == undefined)
aTitle = CPLogDefaultTitle;
if (aLevel == undefined)
aLevel = CPLogDefaultLevel;
// use sprintf if param 0 is a string and there is more than one param. otherwise just convert param 0 to a string
var message = (typeof parameters[0] == "string" && parameters.length > 1) ? sprintf.apply(null, parameters) : String(parameters[0]);
if (_CPLogRegistrations[aLevel])
for (var i = 0; i < _CPLogRegistrations[aLevel].length; i++)
_CPLogRegistrations[aLevel][i](message, aLevel, aTitle);
}
// Setup CPLog() and CPLog.xxx() aliases
function CPLog() { _CPLogDispatch(arguments); }
for (var i = 0; i < CPLogLevels.length; i++)
CPLog[CPLogLevels[i]] = (function(level) { return function() { _CPLogDispatch(arguments, level); }; })(CPLogLevels[i]);
// Loggers:
ANSI_ESC = String.fromCharCode(0x1B);
ANSI_CSI = ANSI_ESC + '[';
ANSI_TEXT_PROP = 'm';
ANSI_RESET = '0';
ANSI_BOLD = '1';
ANSI_FAINT = '2'; // unsupported?
ANSI_NORMAL = '22';
ANSI_ITALIC = '3'; // unsupported?
ANSI_UNDER = '4';
ANSI_UNDER_DBL = '21'; // unsupported?
ANSI_UNDER_OFF = '24';
ANSI_BLINK = '5';
ANSI_BLINK_FAST = '6'; // unsupported?
ANSI_BLINK_OFF = '25';
ANSI_REVERSE = '7';
ANSI_POSITIVE = '27';
ANSI_CONCEAL = '8';
ANSI_REVEAL = '28';
ANSI_FG = '3';
ANSI_BG = '4';
ANSI_FG_INTENSE = '9';
ANSI_BG_INTENSE = '10';
ANSI_BLACK = '0';
ANSI_RED = '1';
ANSI_GREEN = '2';
ANSI_YELLOW = '3';
ANSI_BLUE = '4';
ANSI_MAGENTA = '5';
ANSI_CYAN = '6';
ANSI_WHITE = '7';
var colorCodeMap = {
"black" : ANSI_BLACK,
"red" : ANSI_RED,
"green" : ANSI_GREEN,
"yellow" : ANSI_YELLOW,
"blue" : ANSI_BLUE,
"magenta" : ANSI_MAGENTA,
"cyan" : ANSI_CYAN,
"white" : ANSI_WHITE
}
ANSIControlCode = function(code, parameters)
{
if (parameters == undefined)
parameters = "";
else if (typeof(parameters) == 'object' && (parameters instanceof Array))
parameters = parameters.join(';');
return ANSI_CSI + String(parameters) + String(code);
}
// simple text helpers:
ANSITextApplyProperties = function(string, properties)
{
return ANSIControlCode(ANSI_TEXT_PROP, properties) + String(string) + ANSIControlCode(ANSI_TEXT_PROP);
}
ANSITextColorize = function(string, color)
{
if (colorCodeMap[color] == undefined)
return string;
return ANSITextApplyProperties(string, ANSI_FG + colorCodeMap[color]);
}
// CPLogPrint uses the print() functions present in many non-browser command line JavaScript interpreters
var levelColorMap = {
"fatal": "red",
"error": "red",
"warn" : "yellow",
"info" : "green",
"debug": "cyan",
"trace": "blue"
}
function CPLogPrint(aString, aLevel, aTitle)
{
if (typeof print != "undefined")
{
if (aLevel == "fatal" || aLevel == "error" || aLevel == "warn")
var message = ANSITextColorize(_CPFormatLogMessage(aString, aLevel, aTitle), levelColorMap[aLevel]);
else
var message = _CPFormatLogMessage(aString, ANSITextColorize(aLevel, levelColorMap[aLevel]), aTitle);
print(message);
}
}
// CPLogAlert uses basic browser alert() functions
function CPLogAlert(aString, aLevel, aTitle)
{
if (typeof alert != "undefined" && !window.CPLogDisable)
{
var message = _CPFormatLogMessage(aString, aLevel, aTitle);
window.CPLogDisable = !confirm(message + "\n\n(Click cancel to stop log alerts)");
}
}
// CPLogConsole uses the built in "console" object
function CPLogConsole(aString, aLevel, aTitle)
{
if (typeof console != "undefined")
{
var message = _CPFormatLogMessage(aString, aLevel, aTitle);
var logger = {
"fatal": "error",
"error": "error",
"warn": "warn",
"info": "info",
"debug": "debug",
"trace": "debug"
}[aLevel];
if (logger && console[logger])
console[logger](message);
else if (console.log)
console.log(message);
}
}
// CPLogPopup uses a slick popup window in the browser:
var CPLogWindow = null;
CPLogPopup = function(aString, aLevel, aTitle)
{
try {
if (window.CPLogDisable || window.open == undefined)
return;
if (!CPLogWindow || !CPLogWindow.document)
{
CPLogWindow = window.open("", "_blank", "width=600,height=400,status=no,resizable=yes,scrollbars=yes");
if (!CPLogWindow) {
window.CPLogDisable = !confirm(aString + "\n\n(Disable pop-up blocking for CPLog window; Click cancel to stop log alerts)");
return;
}
_CPLogInitPopup(CPLogWindow);
}
var logDiv = CPLogWindow.document.createElement("div");
logDiv.setAttribute("class", aLevel || "fatal");
var message = _CPFormatLogMessage(aString, null, aTitle);
logDiv.appendChild(CPLogWindow.document.createTextNode(message));
CPLogWindow.log.appendChild(logDiv);
if (CPLogWindow.focusEnabled.checked)
CPLogWindow.focus();
if (CPLogWindow.blockEnabled.checked)
CPLogWindow.blockEnabled.checked = CPLogWindow.confirm(message+"\nContinue blocking?");
if (CPLogWindow.scrollEnabled.checked)
CPLogWindow.scrollToBottom();
} catch(e) {
// TODO: some error handling/reporting
}
}
var _CPLogInitPopup = function(logWindow)
{
var doc = logWindow.document;
// HACK so that head is available below:
doc.writeln("<html><head><title></title></head><body></body></html>");
doc.title = CPLogDefaultTitle + " Run Log";
var head = doc.getElementsByTagName("head")[0];
var body = doc.getElementsByTagName("body")[0];
var base = window.location.protocol + "//" + window.location.host + window.location.pathname;
base = base.substring(0,base.lastIndexOf("/")+1);
var link = doc.createElement("link");
link.setAttribute("type", "text/css");
link.setAttribute("rel", "stylesheet");
link.setAttribute("href", base+"Frameworks/Foundation/Resources/log.css");
link.setAttribute("media", "screen");
head.appendChild(link);
var div = doc.createElement("div");
div.setAttribute("id", "header");
body.appendChild(div);
// Enablers
var ul = doc.createElement("ul");
ul.setAttribute("id", "enablers");
div.appendChild(ul);
for (var i = 0; i < CPLogLevels.length; i++) {
var li = doc.createElement("li");
li.setAttribute("id", "en"+CPLogLevels[i]);
li.setAttribute("class", CPLogLevels[i]);
li.setAttribute("onclick", "toggle(this);");
li.setAttribute("enabled", "yes");
li.appendChild(doc.createTextNode(CPLogLevels[i]));
ul.appendChild(li);
}
// Options
var ul = doc.createElement("ul");
ul.setAttribute("id", "options");
div.appendChild(ul);
var options = {"focus":["Focus",false], "block":["Block",false], "wrap":["Wrap",false], "scroll":["Scroll",true], "close":["Close",true]};
for (o in options) {
var li = doc.createElement("li");
ul.appendChild(li);
logWindow[o+"Enabled"] = doc.createElement("input");
logWindow[o+"Enabled"].setAttribute("id", o);
logWindow[o+"Enabled"].setAttribute("type", "checkbox");
if (options[o][1])
logWindow[o+"Enabled"].setAttribute("checked", "checked");
li.appendChild(logWindow[o+"Enabled"]);
var label = doc.createElement("label");
label.setAttribute("for", o);
label.appendChild(doc.createTextNode(options[o][0]));
li.appendChild(label);
}
// Log
logWindow.log = doc.createElement("div");
logWindow.log.setAttribute("class", "enerror endebug enwarn eninfo enfatal entrace");
body.appendChild(logWindow.log);
logWindow.toggle = function(elem) {
var enabled = (elem.getAttribute("enabled") == "yes") ? "no" : "yes";
elem.setAttribute("enabled", enabled);
if (enabled == "yes")
logWindow.log.className += " " + elem.id
else
logWindow.log.className = logWindow.log.className.replace(new RegExp("[\\s]*"+elem.id, "g"), "");
}
// Scroll
logWindow.scrollToBottom = function() {
logWindow.scrollTo(0, body.offsetHeight);
}
// Wrap
logWindow.wrapEnabled.addEventListener("click", function() {
logWindow.log.setAttribute("wrap", logWindow.wrapEnabled.checked ? "yes" : "no");
}, false);
// Clear
logWindow.addEventListener("keydown", function(e) {
var e = e || logWindow.event;
if (e.keyCode == 75 && (e.ctrlKey || e.metaKey)) {
while (logWindow.log.firstChild) {
logWindow.log.removeChild(logWindow.log.firstChild);
}
e.preventDefault();
}
}, "false");
// Parent closing
window.addEventListener("unload", function() {
if (logWindow && logWindow.closeEnabled && logWindow.closeEnabled.checked) {
window.CPLogDisable = true;
logWindow.close();
}
}, false);
// Log popup closing
logWindow.addEventListener("unload", function() {
if (!window.CPLogDisable) {
window.CPLogDisable = !confirm("Click cancel to stop logging");
}
}, false);
}
// placeholder. moved to Objective-J/CPLog.js
+9
View File
@@ -58,3 +58,12 @@ var CPNullSharedNull = nil;
}
@end
@implementation CPNull (CPFastEnumeration)
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
return 0;
}
@end
+6 -1
View File
@@ -273,6 +273,11 @@ CPLog(@"Got some class: %@", inst);
return "<" + class_getName(isa) + " 0x" + [CPString stringWithHash:[self UID]] + ">";
}
+ (CPString)description
{
return class_getName(isa);
}
// Sending Messages
/*!
Sends the specified message to the receiver.
@@ -523,7 +528,7 @@ CPLog(@"Got some class: %@", inst);
// override toString on Objective-J objects so we get the actual description of the object
// when coerced to a string, instead of "[Object object]"
objj_object.prototype.toString = function()
objj_class.prototype.toString = objj_object.prototype.toString = function()
{
if (this.isa && class_getInstanceMethod(this.isa, "description") != NULL)
return [this description]
+20 -2
View File
@@ -33,14 +33,32 @@ CPPropertyList280NorthFormat_v1_0 = kCFPropertyList280NorthFormat_v1_0;
{
}
+ (CPData)dataFromPropertyList:(id)aPlist format:(CPPropertyListFormat)aFormat errorDescription:({CPString})anErrorString
+ (CPData)dataFromPropertyList:(id)aPlist format:(CPPropertyListFormat)aFormat
{
return CPPropertyListCreateData(aPlist, aFormat);
}
+ (id)propertyListFromData:(CPData)data format:(CSPropertyListFormat)aFormat errorDescription:({CPString})errorString
+ (id)propertyListFromData:(CPData)data format:(CPPropertyListFormat)aFormat
{
return CPPropertyListCreateFromData(data, aFormat);
}
@end
@implementation CPPropertyListSerialization (Deprecated)
+ (CPData)dataFromPropertyList:(id)aPlist format:(CPPropertyListFormat)aFormat errorDescription:(id)anErrorString
{
_CPReportLenientDeprecation(self, _cmd, @selector(dataFromPropertyList:format:));
return [self dataFromPropertyList:aPlist format:aFormat];
}
+ (id)propertyListFromData:(CPData)data format:(CPPropertyListFormat)aFormat errorDescription:(id)errorString
{
_CPReportLenientDeprecation(self, _cmd, @selector(propertyListFromData:format:));
return [self propertyListFromData:data format:aFormat];
}
@end
+16
View File
@@ -499,6 +499,22 @@ var CPSetObjectsKey = @"CPSetObjectsKey";
@end
@implementation CPSet (CPFastEnumeration)
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
var count = [self count];
if (aState.state >= count)
return 0;
count = [[self allObjects] countByEnumeratingWithState:aState objects:objects count:aCount];
return count;
}
@end
/*!
@class CPMutableSet
@ingroup compatability
+5 -5
View File
@@ -56,7 +56,7 @@ CPAnchoredSearch = 8;
*/
CPNumericSearch = 64;
var CPStringHashes = new objj_dictionary();
var CPStringHashes = new CFMutableDictionary();
var CPStringRegexSpecialCharacters = [
'/', '.', '*', '+', '?', '|', '$', '^',
@@ -526,14 +526,14 @@ var CPStringRegexSpecialCharacters = [
*/
- (unsigned)UID
{
var hash = dictionary_getValue(CPStringHashes, self);
var hash = CPStringHashes.valueForKey(self);
if (!hash)
{
hash = _objj_generateObjectHash();
dictionary_setValue(CPStringHashes, self, hash);
CPStringHashes.setValueForKey(self, hash);
}
return hash;
}
+6
View File
@@ -200,6 +200,12 @@ CPURLCustomIconKey = @"CPURLCustomIconKey";
[_resourceValues setObject:anObject forKey:aKey];
}
- (CPString)staticResourceData
{
// FIXME: This probably shouldn't go through CFBundle for no reason.
return CFBundle.dataContentsAtPath([self path]);
}
@end
@implementation CPURL (CPCoding)
+39 -27
View File
@@ -26,12 +26,6 @@
@import "CPURLResponse.j"
var XMLHTTPRequestUninitialized = 0,
XMLHTTPRequestLoading = 1,
XMLHTTPRequestLoaded = 2,
XMLHTTPRequestInteractive = 3,
XMLHTTPRequestComplete = 4;
var CPURLConnectionDelegate = nil;
/*!
@@ -84,8 +78,8 @@ var CPURLConnectionDelegate = nil;
id _delegate;
BOOL _isCanceled;
BOOL _isLocalFileConnection;
XMLHTTPRequest _XMLHTTPRequest;
HTTPRequest _HTTPRequest;
}
+ (void)setClassDelegate:(id)delegate
@@ -100,12 +94,12 @@ var CPURLConnectionDelegate = nil;
@param anError not used
@return the data at the URL or \c nil if there was an error
*/
+ (CPData)sendSynchronousRequest:(CPURLRequest)aRequest returningResponse:({CPURLResponse})aURLResponse error:({CPError})anError
+ (CPData)sendSynchronousRequest:(CPURLRequest)aRequest returningResponse:({CPURLResponse})aURLResponse
{
try
{
var request = objj_request_xmlhttp();
var request = new HTTPRequest();
request.open([aRequest HTTPMethod], [[aRequest URL] absoluteString], NO);
var fields = [aRequest allHTTPHeaderFields],
@@ -117,7 +111,7 @@ var CPURLConnectionDelegate = nil;
request.send([aRequest HTTPBody]);
return [CPData dataWithString:request.responseText];
return [CPData dataWithEncodedString:request.responseText()];
}
catch (anException)
{
@@ -163,7 +157,7 @@ var CPURLConnectionDelegate = nil;
window.location &&
(window.location.protocol === "file:" || window.location.protocol === "app:"));
_XMLHTTPRequest = objj_request_xmlhttp();
_HTTPRequest = new HTTPRequest();
if (shouldStartImmediately)
[self start];
@@ -194,18 +188,18 @@ var CPURLConnectionDelegate = nil;
try
{
_XMLHTTPRequest.open([_request HTTPMethod], [[_request URL] absoluteString], YES);
_XMLHTTPRequest.onreadystatechange = function() { [self _readyStateDidChange]; }
_HTTPRequest.open([_request HTTPMethod], [[_request URL] absoluteString], YES);
_HTTPRequest.onreadystatechange = function() { [self _readyStateDidChange]; }
var fields = [_request allHTTPHeaderFields],
key = nil,
keys = [fields keyEnumerator];
while (key = [keys nextObject])
_XMLHTTPRequest.setRequestHeader(key, [fields objectForKey:key]);
_XMLHTTPRequest.send([_request HTTPBody]);
_HTTPRequest.setRequestHeader(key, [fields objectForKey:key]);
_HTTPRequest.send([_request HTTPBody]);
}
catch (anException)
{
@@ -223,7 +217,7 @@ var CPURLConnectionDelegate = nil;
try
{
_XMLHTTPRequest.abort();
_HTTPRequest.abort();
}
// We expect an exception in some browsers like FireFox.
catch (anException)
@@ -239,9 +233,9 @@ var CPURLConnectionDelegate = nil;
/* @ignore */
- (void)_readyStateDidChange
{
if (_XMLHTTPRequest.readyState == XMLHTTPRequestComplete)
if (_HTTPRequest.readyState() === HTTPRequest.CompleteState)
{
var statusCode = _XMLHTTPRequest.status,
var statusCode = _HTTPRequest.status(),
URL = [_request URL];
if ([_delegate respondsToSelector:@selector(connection:didReceiveResponse:)])
@@ -259,12 +253,12 @@ var CPURLConnectionDelegate = nil;
}
if (!_isCanceled)
{
if (statusCode == 401 && [CPURLConnectionDelegate respondsToSelector:@selector(connectionDidReceiveAuthenticationChallenge:)])
if (statusCode === 401 && [CPURLConnectionDelegate respondsToSelector:@selector(connectionDidReceiveAuthenticationChallenge:)])
[CPURLConnectionDelegate connectionDidReceiveAuthenticationChallenge:self];
else
{
if ([_delegate respondsToSelector:@selector(connection:didReceiveData:)])
[_delegate connection:self didReceiveData:_XMLHTTPRequest.responseText];
[_delegate connection:self didReceiveData:_HTTPRequest.responseText()];
if ([_delegate respondsToSelector:@selector(connectionDidFinishLoading:)])
[_delegate connectionDidFinishLoading:self];
}
@@ -275,9 +269,27 @@ var CPURLConnectionDelegate = nil;
}
/* @ignore */
- (void)_XMLHTTPRequest
- (HTTPRequest)_HTTPRequest
{
return _XMLHTTPRequest;
return _HTTPRequest;
}
@end
@implementation CPURLConnection (Deprecated)
+ (CPData)sendSynchronousRequest:(CPURLRequest)aRequest returningResponse:({CPURLResponse})aURLResponse error:(id)anError
{
_CPReportLenientDeprecation(self, _cmd, @selector(sendSynchronousRequest:returningResponse:));
return [self sendSynchronousRequest:aRequest returningResponse:aURLResponse];
}
- (HTTPRequest)_XMLHTTPRequest
{
_CPReportLenientDeprecation(self, _cmd, @selector(_HTTPRequest));
return [self _HTTPRequest];
}
@end
+1 -1
View File
@@ -100,7 +100,7 @@ CPWebDAVManagerNonCollectionResourceType = 0;
[request setHTTPBody:HTTPBody.join("")];
if (!aBlock)
return parsePROPFINDResponse([[CPURLConnection sendSynchronousRequest:request returningResponse:nil error:nil] string]);
return parsePROPFINDResponse([[CPURLConnection sendSynchronousRequest:request returningResponse:nil error:nil] encodedString]);
else
{
+2 -2
View File
@@ -205,9 +205,9 @@ function pushPackage(path, remote)
{
stream.print("Pushing \0blue(" + path + "\0) to \0blue(" + remote + "\0)");
FILE.mkdirs("push-package");
FILE.mkdirs(".push-package");
var pushPackageDir = FILE.join("push-package", remote.replace(/[^\w]/g, "_"));
var pushPackageDir = FILE.join(".push-package", remote.replace(/[^\w]/g, "_"));
if (FILE.exists(pushPackageDir))
OS.system(buildCommandString([["cd", pushPackageDir], ["git", "pull"]]));
+60
View File
@@ -0,0 +1,60 @@
var cwd = FILE.cwd(),
rootResource = new StaticResource("", NULL, StaticResource.DirectoryType, cwd !== "/");
StaticResource.root = rootResource;
#ifdef BROWSER
if (rootResource.isResolved())
{
rootResource.nodeAtSubPath(FILE.dirname(cwd), YES);
resolveCWD();
}
else
{
rootResource.resolve();
rootResource.addEventListener("resolve", resolveCWD);
}
function resolveCWD()
{
rootResource.resolveSubPath(cwd, StaticResource.DirectoryType, function(/*StaticResource*/ aResource)
{
var includePaths = exports.includePaths(),
index = 0,
count = includePaths.length;
for (; index < count; ++index)
aResource.nodeAtSubPath(FILE.normal(includePaths[index]), YES);
if (typeof OBJJ_MAIN_FILE === "undefined")
OBJJ_MAIN_FILE = "main.j";
fileImporterForPath(cwd)(OBJJ_MAIN_FILE || "main.j", YES, function()
{
afterDocumentLoad(main);
});
});
}
function afterDocumentLoad(/*Function*/ aFunction)
{
if (documentLoaded)
return aFunction();
if (window.addEventListener)
window.addEventListener("load", aFunction, NO);
else if (window.attachEvent)
window.attachEvent("onload", aFunction);
}
var documentLoaded = NO;
afterDocumentLoad(function()
{
documentLoaded = YES;
});
#endif
makeExportsGlobal();
+27
View File
@@ -0,0 +1,27 @@
var global = { },
ObjectiveJ = { };
(function (global, exports, namespace)
{
var GLOBAL_NAMESPACE = namespace;
#include "Includes.js"
})(global, ObjectiveJ, window);
var hasOwnProperty = Object.prototype.hasOwnProperty;
// If we can't trust the host object, don't treat it as global
// and fall back to inferred global through eval. In IE this
// make a difference.
if (window.window !== window)
{
for (key in global)
if (hasOwnProperty.call(global, key))
eval(key + " = global[\"" + key + "\"];");
}
else
{
for (key in global)
if (hasOwnProperty.call(global, key))
window[key] = global[key];
}
+534
View File
@@ -0,0 +1,534 @@
var CFBundleUnloaded = 0,
CFBundleLoading = 1 << 0,
CFBundleLoadingInfoPlist = 1 << 1,
CFBundleLoadingExecutable = 1 << 2,
CFBundleLoadingSpritedImages = 1 << 3,
CFBundleLoaded = 1 << 4;
var CFBundlesForPaths = { },
CFBundlesForClasses = { },
CFCacheBuster = new Date().getTime();
function CFBundle(/*String*/ aPath)
{
aPath = FILE.absolute(aPath);
var existingBundle = CFBundlesForPaths[aPath];
if (existingBundle)
return existingBundle;
CFBundlesForPaths[aPath] = this;
this._path = aPath;
this._name = FILE.basename(aPath);
this._staticResource = NULL;
this._loadStatus = CFBundleUnloaded;
this._loadRequests = [];
this._infoDictionary = NULL;
this._URIMap = { };
this._eventDispatcher = new EventDispatcher(this);
}
CFBundle.bundleContainingPath = function(/*String*/ aPath)
{
aPath = FILE.absolute(aPath);
while (aPath !== "/")
{
var bundle = CFBundlesForPaths[aPath];
if (bundle)
return bundle;
aPath = FILE.dirname(aPath);
}
return NULL;
}
CFBundle.mainBundle = function()
{
return new CFBundle(FILE.cwd());
}
function addClassToBundle(aClass, aBundle)
{
if (aBundle)
CFBundlesForClasses[aClass.name] = aBundle;
}
CFBundle.bundleForClass = function(/*Class*/ aClass)
{
return CFBundlesForClasses[aClass.name] || CFBundle.mainBundle();
}
CFBundle.prototype.path = function()
{
return this._path;
}
CFBundle.prototype.infoDictionary = function()
{
return this._infoDictionary;
}
CFBundle.prototype.valueForInfoDictionary = function(/*String*/ aKey)
{
return this._infoDictionary.valueForKey(aKey);
}
CFBundle.prototype.resourcesPath = function()
{
return FILE.join(this.path(), "Resources");
}
CFBundle.prototype.pathForResource = function(/*String*/ aPath)
{
var mappedPath = this._URIMap[FILE.join("Resources", aPath)];
if (mappedPath)
return mappedPath;
// If not, return the trivial path.
return FILE.join(this.resourcesPath(), aPath);
}
CFBundle.prototype.executablePath = function()
{
var executableSubPath = this._infoDictionary.valueForKey("CPBundleExecutable");
if (executableSubPath)
return FILE.join(this.path(), this.mostEligibleEnvironment() + ".environment", executableSubPath);
return NULL;
}
CFBundle.prototype.hasSpritedImages = function()
{
var environments = this._infoDictionary.valueForKey("CPBundleEnvironmentsWithImageSprites") || [],
index = environments.length,
mostEligibleEnvironment = this.mostEligibleEnvironment();
while (index--)
if (environments[index] === mostEligibleEnvironment)
return YES;
return NO;
}
CFBundle.prototype.environments = function()
{
return this._infoDictionary.valueForKey("CPBundleEnvironments") || ["ObjJ"];
}
CFBundle.prototype.mostEligibleEnvironment = function(/*Array*/ environments)
{
environments = environments || this.environments();
var objj_environments = exports.environments(),
index = 0,
count = objj_environments.length,
innerCount = environments.length;
// Ugh, no indexOf, no objects-in-common.
for(; index < count; ++index)
{
var innerIndex = 0,
environment = objj_environments[index];
for (; innerIndex < innerCount; ++innerIndex)
if(environment === environments[innerIndex])
return environment;
}
return NULL;
}
CFBundle.prototype.isLoading = function()
{
return this._loadStatus & CFBundleLoading;
}
CFBundle.prototype.load = function(/*BOOL*/ shouldExecute)
{
if (this._loadStatus !== CFBundleUnloaded)
return;
this._loadStatus = CFBundleLoading | CFBundleLoadingInfoPlist;
var self = this;
rootResource.resolveSubPath(FILE.dirname(self.path()), StaticResource.DirectoryType, function(aStaticResource)
{
var path = self.path();
// If this bundle exists at the root path, no need to create a node.
if (path === "/")
self._staticResource = rootResource;
else
{
var name = FILE.basename(path);
self._staticResource = aStaticResource._children[name];
if (!self._staticResource)
self._staticResource = new StaticResource(name, aStaticResource, StaticResource.DirectoryType, NO);
}
function onsuccess(/*Event*/ anEvent)
{
self._loadStatus &= ~CFBundleLoadingInfoPlist;
self._infoDictionary = anEvent.request.responsePropertyList();
if (!self._infoDictionary)
{
finishBundleLoadingWithError(self, new Error("Could not load bundle at \"" + path + "\""));
return;
}
loadExecutableAndResources(self, shouldExecute);
}
function onfailure()
{
self._loadStatus = CFBundleUnloaded;
finishBundleLoadingWithError(self, new Error("Could not load bundle at \"" + path + "\""));
}
new FileRequest(FILE.join(path, "Info.plist"), onsuccess, onfailure);
});
}
function finishBundleLoadingWithError(/*CFBundle*/ aBundle, /*Event*/ anError)
{
resolveStaticResource(aBundle._staticResource);
aBundle._eventDispatcher.dispatchEvent(
{
type:"error",
error:anError,
bundle:aBundle
});
}
function loadExecutableAndResources(/*Bundle*/ aBundle, /*BOOL*/ shouldExecute)
{
if (!aBundle.mostEligibleEnvironment())
return failure();
loadExecutableForBundle(aBundle, success, failure);
loadSpritedImagesForBundle(aBundle, success, failure);
if (aBundle._loadStatus === CFBundleLoading)
return success();
function failure(/*Error*/ anError)
{
var loadRequests = aBundle._loadRequests,
count = loadRequests.length;
while (count--)
loadRequests[count].abort();
this._loadRequests = [];
aBundle._loadStatus = CFBundleUnloaded;
finishBundleLoadingWithError(aBundle, anError || new Error("Could not recognize executable code format in Bundle " + aBundle));
}
function success()
{
if (aBundle._loadStatus === CFBundleLoading)
aBundle._loadStatus = CFBundleLoaded;
else
return;
// Set resolved to true here in case during evaluation this bundle
// needs to resolve another bundle which in turn needs it to be resolved (cycle).
resolveStaticResource(aBundle._staticResource);
function complete()
{
aBundle._eventDispatcher.dispatchEvent(
{
type:"load",
bundle:aBundle
});
}
if (shouldExecute)
executeBundle(aBundle, complete);
else
complete();
}
}
function loadExecutableForBundle(/*Bundle*/ aBundle, success, failure)
{
if (!aBundle.executablePath())
return;
aBundle._loadStatus |= CFBundleLoadingExecutable;
new FileRequest(aBundle.executablePath(), function(/*Event*/ anEvent)
{
try
{
decompileStaticFile(aBundle, anEvent.request.responseText());
aBundle._loadStatus &= ~CFBundleLoadingExecutable;
success();
}
catch(anException)
{
failure(anException);
}
}, failure);
}
function loadSpritedImagesForBundle(/*Bundle*/ aBundle, success, failure)
{
if (!aBundle.hasSpritedImages())
return;
aBundle._loadStatus |= CFBundleLoadingSpritedImages;
if (!CFBundleHasTestedSpriteSupport())
return CFBundleTestSpriteSupport(spritedImagesTestPathForBundle(aBundle), function()
{
loadSpritedImagesForBundle(aBundle, success, failure);
});
var spritedImagesPath = spritedImagesPathForBundle(aBundle);
if (!spritedImagesPath)
{
aBundle._loadStatus &= ~CFBundleLoadingSpritedImages;
return success();
}
new FileRequest(spritedImagesPath, function(/*Event*/ anEvent)
{
try
{
decompileStaticFile(aBundle, anEvent.request.responseText());
aBundle._loadStatus &= ~CFBundleLoadingSpritedImages;
success();
}
catch(anException)
{
failure(anException);
}
}, failure);
}
var CFBundleSpriteSupportListeners = [],
CFBundleSupportedSpriteType = -1,
CFBundleNoSpriteType = 0,
CFBundleDataURLSpriteType = 1,
CFBundleMHTMLSpriteType = 2,
CFBundleMHTMLUncachedSpriteType = 3;
function CFBundleHasTestedSpriteSupport()
{
return CFBundleSupportedSpriteType !== -1;
}
function CFBundleTestSpriteSupport(/*String*/ MHTMLPath, /*Function*/ aCallback)
{
if (CFBundleHasTestedSpriteSupport())
return;
CFBundleSpriteSupportListeners.push(aCallback);
if (CFBundleSpriteSupportListeners.length > 1)
return;
CFBundleTestSpriteTypes([
CFBundleDataURLSpriteType,
"data:image/gif;base64,R0lGODlhAQABAIAAAMc9BQAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==",
CFBundleMHTMLSpriteType,
MHTMLPath,
CFBundleMHTMLUncachedSpriteType,
MHTMLPath+"?"+CFCacheBuster]);
}
function CFBundleNotifySpriteSupportListeners()
{
var count = CFBundleSpriteSupportListeners.length;
while (count--)
CFBundleSpriteSupportListeners[count]();
}
function CFBundleTestSpriteTypes(/*Array*/ spriteTypes)
{
var image = new Image();
image.onload = function()
{
if (image.width === 1 && image.height === 1)
{
CFBundleSupportedSpriteType = spriteTypes[0];
CFBundleNotifySpriteSupportListeners();
}
else
image.onerror();
}
image.onerror = function()
{
if (spriteTypes.length === 2)
{
CFBundleSupportedSpriteType = CFBundleNoSpriteType;
CFBundleNotifySpriteSupportListeners();
}
else
CFBundleTestSpriteTypes(spriteTypes.slice(2));
}
image.src = spriteTypes[1];
}
function spritedImagesTestPathForBundle(/*Bundle*/ aBundle)
{
return FILE.join(aBundle.path(), aBundle.mostEligibleEnvironment() + ".environment", "MHTMLTest.txt");
}
function spritedImagesPathForBundle(/*Bundle*/ aBundle)
{
if (CFBundleSupportedSpriteType === CFBundleDataURLSpriteType)
return FILE.join(aBundle.path(), aBundle.mostEligibleEnvironment() + ".environment", "dataURLs.txt");
if (CFBundleSupportedSpriteType === CFBundleMHTMLSpriteType)
return FILE.join(aBundle.path(), aBundle.mostEligibleEnvironment() + ".environment", "MHTML.txt");
if (CFBundleSupportedSpriteType === CFBundleMHTMLUncachedSpriteType)
return FILE.join(aBundle.path(), aBundle.mostEligibleEnvironment() + ".environment", "MHTML.txt?" + CFCacheBuster);
return NULL;
}
CFBundle.dataContentsAtPath = function(/*String*/ aPath)
{
var data = new CFMutableData();
data.setEncodedString(rootResource.nodeAtSubPath(aPath).contents());
return data;
}
function executeBundle(/*Bundle*/ aBundle)
{
var staticResources = [aBundle._staticResource];
function executeStaticResources(staticResources, index)
{
for (; index < staticResources.length; ++index)
{
var staticResource = staticResources[index];
if (staticResource.type() === StaticResource.FileType)
{
var executable = new FileExecutable(staticResource.path());
if (staticResource.hasLoadedFileDependencies())
executable.execute();
else
{
executable.addEventListeners("dependenciesload", function()
{
executeStaticResources(index);
});
return;
}
}
else
staticResources = staticResources.concat(staticResource.children());
}
}
executeStaticResources(0);
}
var STATIC_MAGIC_NUMBER = "@STATIC",
MARKER_PATH = "p",
MARKER_URI = "u",
MARKER_CODE = "c",
MARKER_TEXT = "t",
MARKER_IMPORT_STD = 'I',
MARKER_IMPORT_LOCAL = 'i';
function decompileStaticFile(/*Bundle*/ aBundle, /*String*/ aString)
{
var stream = new MarkedStream(aString);
if (stream.magicNumber() !== STATIC_MAGIC_NUMBER)
throw new Error("Could not read static file.");
if (stream.version() !== "1.0")
throw new Error("Could not read static file.");
var marker,
bundlePath = aBundle.path(),
file = NULL;
while (marker = stream.getMarker())
{
var text = stream.getString();
if (marker === MARKER_PATH)
{
var absolutePath = FILE.join(bundlePath, text),
parent = rootResource.nodeAtSubPath(FILE.dirname(absolutePath), YES);
file = new StaticResource(FILE.basename(absolutePath), parent, StaticResource.FileType, YES);
}
else if (marker === MARKER_URI)
{
var URI = stream.getString();
if (URI.toLowerCase().indexOf("mhtml:") === 0)
URI = "mhtml:" + FILE.join(bundlePath, URI.substr("mhtml:".length));
aBundle._URIMap[text] = URI;
// The unresolved directories must not be bundles.
var parent = rootResource.nodeAtSubPath(FILE.join(bundlePath, FILE.dirname(text)), YES);
new StaticResource(FILE.basename(text), parent, StaticResource.FileType, YES);
}
else if (marker === MARKER_TEXT)
file.write(text);
}
}
// Event Managament
CFBundle.prototype.addEventListener = function(/*String*/ anEventName, /*Function*/ anEventListener)
{
this._eventDispatcher.addEventListener(anEventName, anEventListener);
}
CFBundle.prototype.removeEventListener = function(/*String*/ anEventName, /*Function*/ anEventListener)
{
this._eventDispatcher.removeEventListener(anEventName, anEventListener);
}
CFBundle.prototype.onerror = function(/*Event*/ anEvent)
{
throw anEvent.error;
}
exports.CFBundle = CFBundle;
+194
View File
@@ -0,0 +1,194 @@
function CFData()
{
this._encodedString = NULL;
this._serializedPropertyList = NULL;
this._bytes = NULL;
this._base64 = NULL;
}
CFData.prototype.serializedPropertyList = function()
{
if (!this._serializedPropertyList)
this._serializedPropertyList = CFPropertyList.propertyListFromString(this.encodedString());
return this._serializedPropertyList;
}
CFData.prototype.encodedString = function()
{
if (this._encodedString === NULL)
{
var serializedPropertyList = this._serializedPropertyList;
if (this._serializedPropertyList)
this._encodedString = CFPropertyList.stringFromPropertyList(serializedPropertyList);
// Ideally we would convert these bytes or base64 into a string.
// else if (this._bytes)
// else if (this._base64)
else
throw "Can't convert data to string.";
}
return this._encodedString;
}
CFData.prototype.bytes = function()
{
return this._bytes;
}
CFData.prototype.base64 = function()
{
return this._base64;
}
function CFMutableData()
{
CFData.call(this);
}
CFMutableData.prototype = new CFData();
function clearMutableData(/*CFMutableData*/ aData)
{
this._encodedString = NULL;
this._serializedPropertyList = NULL;
this._bytes = NULL;
this._base64 = NULL;
}
CFMutableData.prototype.setSerializedPropertyList = function(/*PropertyList*/ aPropertyList)
{
clearMutableData(this);
this._serializedPropertyList = aPropertyList;
}
CFMutableData.prototype.setEncodedString = function(/*String*/ aString)
{
clearMutableData(this);
this._encodedString = aString;
}
CFMutableData.prototype.setBytes = function(/*Array*/ bytes)
{
clearMutableData(this);
this._bytes = bytes;
}
CFMutableData.prototype.setBase64String = function(/*String*/ aBase64String)
{
clearMutableData(this);
this._base64 = aBase64String;
}
// Base64 encoding and decoding
var base64_map_to = [
"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
"0","1","2","3","4","5","6","7","8","9","+","/","="],
base64_map_from = [];
for (var i = 0; i < base64_map_to.length; i++)
base64_map_from[base64_map_to[i].charCodeAt(0)] = i;
function base64_decode_to_array(input, strip)
{
if (strip)
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
var pad = (input[input.length-1] == "=" ? 1 : 0) + (input[input.length-2] == "=" ? 1 : 0),
length = input.length,
output = [];
var i = 0;
while (i < length)
{
var bits = (base64_map_from[input.charCodeAt(i++)] << 18) |
(base64_map_from[input.charCodeAt(i++)] << 12) |
(base64_map_from[input.charCodeAt(i++)] << 6) |
(base64_map_from[input.charCodeAt(i++)]);
output.push((bits & 0xFF0000) >> 16);
output.push((bits & 0xFF00) >> 8);
output.push(bits & 0xFF);
}
// strip "=" padding from end
if (pad > 0)
return output.slice(0, -1 * pad);
return output;
}
function base64_encode_array(input)
{
var pad = (3 - (input.length % 3)) % 3,
length = input.length + pad,
output = [];
// pad with nulls
if (pad > 0) input.push(0);
if (pad > 1) input.push(0);
var i = 0;
while (i < length)
{
var bits = (input[i++] << 16) |
(input[i++] << 8) |
(input[i++]);
output.push(base64_map_to[(bits & 0xFC0000) >> 18]);
output.push(base64_map_to[(bits & 0x3F000) >> 12]);
output.push(base64_map_to[(bits & 0xFC0) >> 6]);
output.push(base64_map_to[bits & 0x3F]);
}
// pad with "=" and revert array to previous state
if (pad > 0)
{
output[output.length-1] = "=";
input.pop();
}
if (pad > 1)
{
output[output.length-2] = "=";
input.pop();
}
return output.join("");
}
function base64_decode_to_string(input, strip)
{
return bytes_to_string(base64_decode_to_array(input, strip));
}
function bytes_to_string(bytes)
{
// This is relatively efficient, I think:
return String.fromCharCode.apply(NULL, bytes);
}
exports.bytes_to_string = bytes_to_string;
function base64_encode_string(input)
{
var temp = [];
for (var i = 0; i < input.length; i++)
temp.push(input.charCodeAt(i));
return base64_encode_array(temp);
}
exports.CFData = CFData;
exports.CFMutableData = CFMutableData;
+200
View File
@@ -0,0 +1,200 @@
function CFDictionary(/*CFDictionary*/ aDictionary)
{
this._keys = [];
this._count = 0;
this._buckets = { };
this._UID = generateObjectUID();
}
var indexOf = Array.prototype.indexOf,
hasOwnProperty = Object.prototype.hasOwnProperty;
CFDictionary.prototype.copy = function()
{
// Immutable, so no need to actually copy.
return this;
}
CFDictionary.prototype.mutableCopy = function()
{
var newDictionary = new CFMutableDictionary(),
keys = this._keys,
count = this._count;
newDictionary._keys = keys.slice();
newDictionary._count = count;
var index = 0,
buckets = this._buckets,
newBuckets = newDictionary._buckets;
for (; index < count; ++index)
{
var key = keys[index];
newBuckets[key] = buckets[key];
}
return newDictionary;
}
CFDictionary.prototype.containsKey = function(/*String*/ aKey)
{
return hasOwnProperty.apply(this._buckets, [aKey]);
}
CFDictionary.prototype.containsValue = function(/*id*/ anObject)
{
var keys = this._keys,
buckets = this._buckets,
index = 0,
count = keys.length;
for (; index < count; ++index)
if (buckets[keys] === anObject)
return YES;
return NO;
}
CFDictionary.prototype.count = function()
{
return this._count;
}
CFDictionary.prototype.countOfKey = function(/*String*/ aKey)
{
return this.containsKey(aKey) ? 1 : 0;
}
CFDictionary.prototype.countOfValue = function(/*id*/ anObject)
{
var keys = this._keys,
buckets = this._buckets,
index = 0,
count = keys.length,
countOfValue = 0;
for (; index < count; ++index)
if (buckets[keys] === anObject)
return ++countOfValue;
return countOfValue;
}
CFDictionary.prototype.keys = function()
{
return this._keys.slice();
}
CFDictionary.prototype.valueForKey = function(/*String*/ aKey)
{
var buckets = this._buckets;
if (!hasOwnProperty.apply(buckets, [aKey]))
return nil;
return buckets[aKey];
}
CFDictionary.prototype.toString = function()
{
var string = "{\n",
keys = this._keys,
index = 0,
count = this._count;
for (; index < count; ++index)
{
var key = keys[index];
string += "\t" + key + " = \"" + String(this.valueForKey(key)).split('\n').join("\n\t") + "\"\n";
}
return string + "}";
}
CFMutableDictionary = function(/*CFDictionary*/ aDictionary)
{
CFDictionary.apply(this, []);
}
CFMutableDictionary.prototype = new CFDictionary();
CFMutableDictionary.prototype.copy = function()
{
return this.mutableCopy();
}
CFMutableDictionary.prototype.addValueForKey = function(/*String*/ aKey, /*Object*/ aValue)
{
if (this.containsKey(aKey))
return;
++this._count;
this._keys.push(aKey);
this._buckets[aKey] = aValue;
}
CFMutableDictionary.prototype.removeValueForKey = function(/*String*/ aKey)
{
var indexOfKey = -1;
if (indexOf)
indexOfKey = indexOf.call(this._keys, aKey);
else
{
var keys = this._keys,
index = 0,
count = keys.length;
for (; index < count; ++index)
if (keys[index] === aKey)
{
indexOfKey = index;
break;
}
}
if (indexOfKey === -1)
return;
--this._count;
this._keys.splice(indexOfKey, 1);
delete this._buckets[aKey];
}
CFMutableDictionary.prototype.removeAllValues = function()
{
this._count = 0;
this._keys = [];
this._buckets = { };
}
CFMutableDictionary.prototype.replaceValueForKey = function(/*String*/ aKey, /*Object*/ aValue)
{
if (!this.containsKey(aKey))
return;
this._buckets[aKey] = aValue;
}
CFMutableDictionary.prototype.setValueForKey = function(/*String*/ aKey, /*Object*/ aValue)
{
if (aValue === nil || aValue === undefined)
this.removeValueForKey(aKey);
else if (this.containsKey(aKey))
this.replaceValueForKey(aKey, aValue);
else
this.addValueForKey(aKey, aValue);
}
// Exports
exports.CFDictionary = CFDictionary;
exports.CFMutableDictionary = CFMutableDictionary;
+595
View File
@@ -0,0 +1,595 @@
var OBJECT_COUNT = 0;
function generateObjectUID()
{
return OBJECT_COUNT++;
}
function CFPropertyList()
{
this._UID = generateObjectUID();
}
// We are really liberal when accepting DOCTYPEs.
CFPropertyList.DTDRE = /^\s*(?:<\?\s*xml\s+version\s*=\s*\"1.0\"[^>]*\?>\s*)?(?:<\!DOCTYPE[^>]*>\s*)?/i
CFPropertyList.XMLRE = /^\s*(?:<\?\s*xml\s+version\s*=\s*\"1.0\"[^>]*\?>\s*)?(?:<\!DOCTYPE[^>]*>\s*)?<\s*plist[^>]*\>/i;
CFPropertyList.FormatXMLDTD = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">";
CFPropertyList.Format280NorthMagicNumber = "280NPLIST";
// Serialization Formats
CFPropertyList.FormatOpenStep = 1,
CFPropertyList.FormatXML_v1_0 = 100,
CFPropertyList.FormatBinary_v1_0 = 200,
CFPropertyList.Format280North_v1_0 = -1000;
CFPropertyList.sniffedFormatOfString = function(/*String*/ aString)
{
// Check if this is an XML Plist.
if (aString.match(CFPropertyList.XMLRE))
return CFPropertyList.FormatXML_v1_0;
if (aString.substr(0, CFPropertyList.Format280NorthMagicNumber.length) === CFPropertyList.Format280NorthMagicNumber)
return CFPropertyList.Format280North_v1_0;
return NULL;
}
// Serialization
CFPropertyList.dataFromPropertyList = function(/*CFPropertyList*/ aPropertyList, /*Format*/ aFormat)
{
var data = new CFMutableData();
data.setEncodedString(CFPropertyList.stringFromPropertyList(aPropertyList, aFormat));
return data;
}
CFPropertyList.stringFromPropertyList = function(/*CFPropertyList*/ aPropertyList, /*Format*/ aFormat)
{
if (!aFormat)
aFormat = CFPropertyList.Format280North_v1_0;
var serializers = CFPropertyListSerializers[aFormat];
return serializers["start"]() +
serializePropertyList(aPropertyList, serializers) +
serializers["finish"]();
}
function serializePropertyList(/*CFPropertyList*/ aPropertyList, /*Object*/ serializers)
{
var type = typeof aPropertyList,
valueOf = aPropertyList.valueOf(),
typeValueOf = typeof valueOf;
if (type !== typeValueOf)
{
type = typeValueOf;
aPropertyList = valueOf;
}
if (aPropertyList === YES || aPropertyList === NO)
type = "boolean";
else if (type === "number")
{
if (FLOOR(aPropertyList) === aPropertyList)
type = "integer";
else
type = "real";
}
else if (type !== "string")
{
if (aPropertyList.slice)
type = "array";
else
type = "dictionary";
}
return serializers[type](aPropertyList, serializers);
}
var CFPropertyListSerializers = { };
CFPropertyListSerializers[CFPropertyList.FormatXML_v1_0] =
{
"start": function()
{
return CFPropertyList.FormatXMLDTD + "<plist version = \"1.0\">";
},
"finish": function()
{
return "</plist>";
},
"string": function(/*String*/ aString)
{
return "<string>" + encodeHTMLComponent(aString) + "</string>";;
},
"boolean" : function(/*Boolean*/ aBoolean)
{
return aBoolean ? "<true/>" : "<false/>";
},
"integer": function(/*Integer*/ anInteger)
{
return "<integer>" + anInteger + "</integer>";
},
"real": function(/*Float*/ aFloat)
{
return "<real>" + aFloat + "</real>";
},
"array": function(/*Array*/ anArray, /*Object*/ serializers)
{
var index = 0,
count = anArray.length,
string = "<array>";
for (; index < count; ++index)
string += serializePropertyList(anArray[index], serializers);
return string + "</array>";
},
"dictionary": function(/*CFDictionary*/ aDictionary, /*Object*/ serializers)
{
var keys = aDictionary._keys,
index = 0,
count = keys.length,
string = "<dict>";
for (; index < count; ++index)
{
var key = keys[index];
string += "<key>" + key + "</key>";
string += serializePropertyList(aDictionary.valueForKey(key), serializers);
}
return string + "</dict>";
}
}
// 280 North Plist Format
var ARRAY_MARKER = "A",
DICTIONARY_MARKER = "D",
FLOAT_MARKER = "f",
INTEGER_MARKER = "d",
STRING_MARKER = "S",
TRUE_MARKER = "T",
FALSE_MARKER = "F",
KEY_MARKER = "K",
END_MARKER = "E";
CFPropertyListSerializers[CFPropertyList.Format280North_v1_0] =
{
"start": function()
{
return CFPropertyList.Format280NorthMagicNumber + ";1.0;";
},
"finish": function()
{
return "";
},
"string" : function(/*String*/ aString)
{
return STRING_MARKER + ';' + aString.length + ';' + aString;
},
"boolean" : function(/*Boolean*/ aBoolean)
{
return (aBoolean ? TRUE_MARKER : FALSE_MARKER) + ';';
},
"integer": function(/*Integer*/ anInteger)
{
var string = "" + anInteger;
return INTEGER_MARKER + ';' + string.length + ';' + string;
},
"real": function(/*Float*/ aFloat)
{
var string = "" + aFloat;
return FLOAT_MARKER + ';' + string.length + ';' + string;
},
"array": function(/*Array*/ anArray, /*Object*/ serializers)
{
var index = 0,
count = anArray.length,
string = ARRAY_MARKER + ';';
for (; index < count; ++index)
string += serializePropertyList(anArray[index], serializers);
return string + END_MARKER + ';';
},
"dictionary": function(/*CFDictionary*/ aDictionary, /*Object*/ serializers)
{
var keys = aDictionary._keys,
index = 0,
count = keys.length,
string = DICTIONARY_MARKER +';';
for (; index < count; ++index)
{
var key = keys[index];
string += KEY_MARKER + ';' + key.length + ';' + key;
string += serializePropertyList(aDictionary.valueForKey(key), serializers);
}
return string + END_MARKER + ';';
}
}
// Deserialization
var XML_XML = "xml",
XML_DOCUMENT = "#document",
PLIST_PLIST = "plist",
PLIST_KEY = "key",
PLIST_DICTIONARY = "dict",
PLIST_ARRAY = "array",
PLIST_STRING = "string",
PLIST_BOOLEAN_TRUE = "true",
PLIST_BOOLEAN_FALSE = "false",
PLIST_NUMBER_REAL = "real",
PLIST_NUMBER_INTEGER = "integer",
PLIST_DATA = "data";
#define NODE_NAME(anXMLNode) (String(anXMLNode.nodeName))
#define NODE_TYPE(anXMLNode) (anXMLNode.nodeType)
#define NODE_VALUE(anXMLNode) (String(anXMLNode.nodeValue))
#define FIRST_CHILD(anXMLNode) (anXMLNode.firstChild)
#define NEXT_SIBLING(anXMLNode) (anXMLNode.nextSibling)
#define PARENT_NODE(anXMLNode) (anXMLNode.parentNode)
#define DOCUMENT_ELEMENT(aDocument) (aDocument.documentElement)
#define IS_OF_TYPE(anXMLNode, aType) (NODE_NAME(anXMLNode) === aType)
#define IS_PLIST(anXMLNode) IS_OF_TYPE(anXMLNode, PLIST_PLIST)
#define IS_WHITESPACE(anXMLNode) (NODE_TYPE(anXMLNode) === 8 || NODE_TYPE(anXMLNode) === 3)
#define IS_DOCUMENTTYPE(anXMLNode) (NODE_TYPE(anXMLNode) === 10)
#define PLIST_NEXT_SIBLING(anXMLNode) while ((anXMLNode = NEXT_SIBLING(anXMLNode)) && IS_WHITESPACE(anXMLNode)) ;
#define PLIST_FIRST_CHILD(anXMLNode) anXMLNode = FIRST_CHILD(anXMLNode); if (anXMLNode !== NULL && IS_WHITESPACE(anXMLNode)) PLIST_NEXT_SIBLING(anXMLNode)
// FIXME: no first child?
#define CHILD_VALUE(anXMLNode) (NODE_VALUE(FIRST_CHILD(anXMLNode)))
var _plist_traverseNextNode = function(anXMLNode, stayWithin, stack)
{
var node = anXMLNode;
PLIST_FIRST_CHILD(node);
// If this element has a child, traverse to it.
if (node)
return node;
// If not, first check if it is a container class (as opposed to a designated leaf).
// If it is, then we have to pop this container off the stack, since it is empty.
if (NODE_NAME(anXMLNode) === PLIST_ARRAY || NODE_NAME(anXMLNode) === PLIST_DICTIONARY)
stack.pop();
// If not, next check whether it has a sibling.
else
{
if (node === stayWithin)
return NULL;
node = anXMLNode;
PLIST_NEXT_SIBLING(node);
if (node)
return node;
}
// If it doesn't, start working our way back up the node tree.
node = anXMLNode;
// While we have a node and it doesn't have a sibling (and we're within our stayWithin),
// keep moving up.
while (node)
{
var next = node;
PLIST_NEXT_SIBLING(next);
// If we have a next sibling, just go to it.
if (next)
return next;
var node = PARENT_NODE(node);
// If we are being asked to move up, and our parent is the stay within, then just
if (stayWithin && node === stayWithin)
return NULL;
// Pop the stack if we have officially "moved up"
stack.pop();
}
return NULL;
}
CFPropertyList.propertyListFromData = function(/*Data*/ aData, /*Format*/ aFormat)
{
return CFPropertyList.propertyListFromString(aData.encodedString(), aFormat);
}
CFPropertyList.propertyListFromString = function(/*String*/ aString, /*Format*/ aFormat)
{
if (!aFormat)
aFormat = CFPropertyList.sniffedFormatOfString(aString);
if (aFormat === CFPropertyList.FormatXML_v1_0)
return CFPropertyList.propertyListFromXML(aString);
if (aFormat === CFPropertyList.Format280North_v1_0)
return propertyListFrom280NorthString(aString);
return NULL;
}
// 280 North Plist Format
var ARRAY_MARKER = "A",
DICTIONARY_MARKER = "D",
FLOAT_MARKER = "f",
INTEGER_MARKER = "d",
STRING_MARKER = "S",
TRUE_MARKER = "T",
FALSE_MARKER = "F",
KEY_MARKER = "K",
END_MARKER = "E";
function propertyListFrom280NorthString(/*String*/ aString)
{
var stream = new MarkedStream(aString),
marker = NULL,
key = "",
object = NULL,
plistObject = NULL,
containers = [],
currentContainer = NULL;
while (marker = stream.getMarker())
{
if (marker === END_MARKER)
{
containers.pop();
continue;
}
var count = containers.length;
if (count)
currentContainer = containers[count - 1];
if (marker === KEY_MARKER)
{
key = stream.getString();
marker = stream.getMarker();
}
switch (marker)
{
case ARRAY_MARKER: object = []
containers.push(object);
break;
case DICTIONARY_MARKER: object = new CFMutableDictionary();
containers.push(object);
break;
case FLOAT_MARKER: object = parseFloat(stream.getString());
break;
case INTEGER_MARKER: object = parseInt(stream.getString(), 10);
break;
case STRING_MARKER: object = stream.getString();
break;
case TRUE_MARKER: object = YES;
break;
case FALSE_MARKER: object = NO;
break;
default: throw new Error("*** " + marker + " marker not recognized in Plist.");
}
if (!plistObject)
plistObject = object;
else if (currentContainer)
// If the container is an array...
if (currentContainer.slice)
currentContainer.push(object);
else
currentContainer.setValueForKey(key, object);
}
return plistObject;
}
function encodeHTMLComponent(/*String*/ aString)
{
return aString.replace(/&/g,'&amp;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
function decodeHTMLComponent(/*String*/ aString)
{
return aString.replace(/&quot;/g, '"').replace(/&apos;/g, '\'').replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
}
function parseXML(/*String*/ aString)
{
if (window.DOMParser)
return DOCUMENT_ELEMENT(new window.DOMParser().parseFromString(aString, "text/xml"));
else if (window.ActiveXObject)
{
XMLNode = new ActiveXObject("Microsoft.XMLDOM");
// Extract the DTD, which confuses IE.
var matches = aString.match(CFPropertyList.DTDRE);
if (matches)
aString = aString.substr(matches[0].length);
XMLNode.loadXML(aString);
return XMLNode
}
return NULL;
}
CFPropertyList.propertyListFromXML = function(/*String | XMLNode*/ aStringOrXMLNode)
{
var XMLNode = aStringOrXMLNode;
if (aStringOrXMLNode.valueOf && typeof aStringOrXMLNode.valueOf() === "string")
XMLNode = parseXML(aStringOrXMLNode);
// Skip over DOCTYPE and so forth.
while (IS_OF_TYPE(XMLNode, XML_DOCUMENT) || IS_OF_TYPE(XMLNode, XML_XML))
PLIST_FIRST_CHILD(XMLNode);
// Skip over the DOCTYPE... see a pattern?
if (IS_DOCUMENTTYPE(XMLNode))
PLIST_NEXT_SIBLING(XMLNode);
// If this is not a PLIST, bail.
if (!IS_PLIST(XMLNode))
return NULL;
var key = "",
object = NULL,
plistObject = NULL,
plistNode = XMLNode,
containers = [],
currentContainer = NULL;
while (XMLNode = _plist_traverseNextNode(XMLNode, plistNode, containers))
{
var count = containers.length;
if (count)
currentContainer = containers[count - 1];
if (NODE_NAME(XMLNode) === PLIST_KEY)
{
key = CHILD_VALUE(XMLNode);
PLIST_NEXT_SIBLING(XMLNode);
}
switch (String(NODE_NAME(XMLNode)))
{
case PLIST_ARRAY: object = []
containers.push(object);
break;
case PLIST_DICTIONARY: object = new CFMutableDictionary();
containers.push(object);
break;
case PLIST_NUMBER_REAL: object = parseFloat(CHILD_VALUE(XMLNode));
break;
case PLIST_NUMBER_INTEGER: object = parseInt(CHILD_VALUE(XMLNode), 10);
break;
case PLIST_STRING: object = decodeHTMLComponent(FIRST_CHILD(XMLNode) ? CHILD_VALUE(XMLNode) : "");
break;
case PLIST_BOOLEAN_TRUE: object = YES;
break;
case PLIST_BOOLEAN_FALSE: object = NO;
break;
case PLIST_DATA: object = new CFMutableData();
object.bytes = FIRST_CHILD(XMLNode) ? base64_decode_to_array(CHILD_VALUE(XMLNode), YES) : [];
break;
default: throw new Error("*** " + NODE_NAME(XMLNode) + " tag not recognized in Plist.");
}
if (!plistObject)
plistObject = object;
else if (currentContainer)
// If the container is an array...
if (currentContainer.slice)
currentContainer.push(object);
else
currentContainer.setValueForKey(key, object);
}
return plistObject;
}
exports.generateObjectUID = generateObjectUID;
exports.CFPropertyList = CFPropertyList;
exports.CFPropertyListCreate = function()
{
return new CFPropertyList();
}
exports.kCFPropertyListOpenStepFormat = CFPropertyList.FormatOpenStep;
exports.kCFPropertyListXMLFormat_v1_0 = CFPropertyList.FormatXML_v1_0;
exports.kCFPropertyListBinaryFormat_v1_0 = CFPropertyList.FormatBinary_v1_0;
exports.kCFPropertyList280NorthFormat_v1_0 = CFPropertyList.Format280North_v1_0;
exports.CFPropertyListCreateFromXMLData = function(/*Data*/ data)
{
return CFPropertyList.propertyListFromData(data, CFPropertyList.FormatXML_v1_0);
}
exports.CFPropertyListCreateXMLData = function(/*PropertyList*/ aPropertyList)
{
return CFPropertyList.dataFromPropertyList(aPropertyList, CFPropertyList.FormatXML_v1_0);
}
exports.CFPropertyListCreateFrom280NorthData = function(/*Data*/ data)
{
return CFPropertyList.propertyListFromData(data, CFPropertyList.Format280North_v1_0);
}
exports.CFPropertyListCreate280NorthData = function(/*PropertyList*/ aPropertyList)
{
return CFPropertyList.dataFromPropertyList(aPropertyList, CFPropertyList.Format280North_v1_0);
}
exports.CPPropertyListCreateFromData = function(/*CFData*/ data, /*Format*/ aFormat)
{
return CFPropertyList.propertyListFromData(data, aFormat);
}
exports.CPPropertyListCreateData = function(/*PropertyList*/ aPropertyList, /*Format*/ aFormat)
{
return CFPropertyList.dataFromPropertyList(aPropertyList, aFormat);
}
+394
View File
@@ -0,0 +1,394 @@
/*
* CPLog.js
* Objective-J
*
* Created by Thomas Robinson.
* Copyright 2008-2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
exports.CPLogDisable = false;
var CPLogDefaultTitle = "Cappuccino";
var CPLogLevels = ["fatal", "error", "warn", "info", "debug", "trace"];
var CPLogDefaultLevel = CPLogLevels[3];
var _CPLogLevelsInverted = {};
for (var i = 0; i < CPLogLevels.length; i++)
_CPLogLevelsInverted[CPLogLevels[i]] = i;
var _CPLogRegistrations = {};
// Register Functions:
// Register a logger for all levels, or up to an optional max level
exports.CPLogRegister = function(aProvider, aMaxLevel)
{
exports.CPLogRegisterRange(aProvider, CPLogLevels[0], aMaxLevel || CPLogLevels[CPLogLevels.length-1]);
}
// Register a logger for a range of levels
exports.CPLogRegisterRange = function(aProvider, aMinLevel, aMaxLevel)
{
var min = _CPLogLevelsInverted[aMinLevel];
var max = _CPLogLevelsInverted[aMaxLevel];
if (min !== undefined && max !== undefined)
for (var i = 0; i <= max; i++)
CPLogRegisterSingle(aProvider, CPLogLevels[i]);
}
// Register a logger for a single level
exports.CPLogRegisterSingle = function(aProvider, aLevel)
{
if (!_CPLogRegistrations[aLevel])
_CPLogRegistrations[aLevel] = [];
// prevent duplicate registrations
for (var i = 0; i < _CPLogRegistrations[aLevel].length; i++)
if (_CPLogRegistrations[aLevel][i] === aProvider)
return;
_CPLogRegistrations[aLevel].push(aProvider);
}
exports.CPLogUnregister = function(aProvider) {
for (var aLevel in _CPLogRegistrations)
for (var i = 0; i < _CPLogRegistrations[aLevel].length; i++)
if (_CPLogRegistrations[aLevel][i] === aProvider)
_CPLogRegistrations[aLevel].splice(i--, 1); // decrement since we're removing an element
}
// Main CPLog, which dispatches to individual loggers
function _CPLogDispatch(parameters, aLevel, aTitle)
{
if (aTitle == undefined)
aTitle = CPLogDefaultTitle;
if (aLevel == undefined)
aLevel = CPLogDefaultLevel;
// use sprintf if param 0 is a string and there is more than one param. otherwise just convert param 0 to a string
var message = (typeof parameters[0] == "string" && parameters.length > 1) ? sprintf.apply(null, parameters) : String(parameters[0]);
if (_CPLogRegistrations[aLevel])
for (var i = 0; i < _CPLogRegistrations[aLevel].length; i++)
_CPLogRegistrations[aLevel][i](message, aLevel, aTitle);
}
// Setup CPLog() and CPLog.xxx() aliases
var CPLog = exports.CPLog = function() { _CPLogDispatch(arguments); }
for (var i = 0; i < CPLogLevels.length; i++)
CPLog[CPLogLevels[i]] = (function(level) { return function() { _CPLogDispatch(arguments, level); }; })(CPLogLevels[i]);
// Helpers functions:
var _CPFormatLogMessage = function(aString, aLevel, aTitle)
{
var now = new Date();
aLevel = ( aLevel == null ? '' : ' [' + aLevel + ']' );
if (typeof sprintf == "function")
return sprintf("%4d-%02d-%02d %02d:%02d:%02d.%03d %s%s: %s",
now.getFullYear(), now.getMonth(), now.getDate(),
now.getHours(), now.getMinutes(), now.getSeconds(), now.getMilliseconds(),
aTitle, aLevel, aString);
else
return now + " " + aTitle + aLevel + ": " + aString;
}
// Loggers:
var ANSI_ESC = String.fromCharCode(0x1B);
var ANSI_CSI = ANSI_ESC + '[';
var ANSI_TEXT_PROP = 'm';
var ANSI_RESET = '0';
var ANSI_BOLD = '1';
var ANSI_FAINT = '2'; // unsupported?
var ANSI_NORMAL = '22';
var ANSI_ITALIC = '3'; // unsupported?
var ANSI_UNDER = '4';
var ANSI_UNDER_DBL = '21'; // unsupported?
var ANSI_UNDER_OFF = '24';
var ANSI_BLINK = '5';
var ANSI_BLINK_FAST = '6'; // unsupported?
var ANSI_BLINK_OFF = '25';
var ANSI_REVERSE = '7';
var ANSI_POSITIVE = '27';
var ANSI_CONCEAL = '8';
var ANSI_REVEAL = '28';
var ANSI_FG = '3';
var ANSI_BG = '4';
var ANSI_FG_INTENSE = '9';
var ANSI_BG_INTENSE = '10';
var ANSI_BLACK = '0';
var ANSI_RED = '1';
var ANSI_GREEN = '2';
var ANSI_YELLOW = '3';
var ANSI_BLUE = '4';
var ANSI_MAGENTA = '5';
var ANSI_CYAN = '6';
var ANSI_WHITE = '7';
var colorCodeMap = {
"black" : ANSI_BLACK,
"red" : ANSI_RED,
"green" : ANSI_GREEN,
"yellow" : ANSI_YELLOW,
"blue" : ANSI_BLUE,
"magenta" : ANSI_MAGENTA,
"cyan" : ANSI_CYAN,
"white" : ANSI_WHITE
}
function ANSIControlCode(code, parameters)
{
if (parameters == undefined)
parameters = "";
else if (typeof(parameters) == 'object' && (parameters instanceof Array))
parameters = parameters.join(';');
return ANSI_CSI + String(parameters) + String(code);
}
// simple text helpers:
function ANSITextApplyProperties(string, properties)
{
return ANSIControlCode(ANSI_TEXT_PROP, properties) + String(string) + ANSIControlCode(ANSI_TEXT_PROP);
}
exports.ANSITextColorize = function(string, color)
{
if (colorCodeMap[color] == undefined)
return string;
return ANSITextApplyProperties(string, ANSI_FG + colorCodeMap[color]);
}
// CPLogPrint uses the print() functions present in many non-browser command line JavaScript interpreters
var levelColorMap = {
"fatal": "red",
"error": "red",
"warn" : "yellow",
"info" : "green",
"debug": "cyan",
"trace": "blue"
}
// CPLogConsole uses the built in "console" object
exports.CPLogConsole = function(aString, aLevel, aTitle)
{
if (typeof console != "undefined")
{
var message = _CPFormatLogMessage(aString, aLevel, aTitle);
var logger = {
"fatal": "error",
"error": "error",
"warn": "warn",
"info": "info",
"debug": "debug",
"trace": "debug"
}[aLevel];
if (logger && console[logger])
console[logger](message);
else if (console.log)
console.log(message);
}
}
#if COMMONJS
exports.CPLogPrint = function(aString, aLevel, aTitle)
{
if (typeof print != "undefined")
{
if (aLevel == "fatal" || aLevel == "error" || aLevel == "warn")
var message = exports.ANSITextColorize(_CPFormatLogMessage(aString, aLevel, aTitle), levelColorMap[aLevel]);
else
var message = _CPFormatLogMessage(aString, exports.ANSITextColorize(aLevel, levelColorMap[aLevel]), aTitle);
require("system").stderr.print(message);
}
}
#else
// CPLogAlert uses basic browser alert() functions
exports.CPLogAlert = function(aString, aLevel, aTitle)
{
if (typeof alert != "undefined" && !exports.CPLogDisable)
{
var message = _CPFormatLogMessage(aString, aLevel, aTitle);
exports.CPLogDisable = !confirm(message + "\n\n(Click cancel to stop log alerts)");
}
}
// CPLogPopup uses a slick popup window in the browser:
var CPLogWindow = null;
exports.CPLogPopup = function(aString, aLevel, aTitle)
{
try {
if (exports.CPLogDisable || window.open == undefined)
return;
if (!CPLogWindow || !CPLogWindow.document)
{
CPLogWindow = window.open("", "_blank", "width=600,height=400,status=no,resizable=yes,scrollbars=yes");
if (!CPLogWindow) {
exports.CPLogDisable = !confirm(aString + "\n\n(Disable pop-up blocking for CPLog window; Click cancel to stop log alerts)");
return;
}
_CPLogInitPopup(CPLogWindow);
}
var logDiv = CPLogWindow.document.createElement("div");
logDiv.setAttribute("class", aLevel || "fatal");
var message = _CPFormatLogMessage(aString, null, aTitle);
logDiv.appendChild(CPLogWindow.document.createTextNode(message));
CPLogWindow.log.appendChild(logDiv);
if (CPLogWindow.focusEnabled.checked)
CPLogWindow.focus();
if (CPLogWindow.blockEnabled.checked)
CPLogWindow.blockEnabled.checked = CPLogWindow.confirm(message+"\nContinue blocking?");
if (CPLogWindow.scrollEnabled.checked)
CPLogWindow.scrollToBottom();
} catch(e) {
// TODO: some error handling/reporting
}
}
function _CPLogInitPopup(logWindow)
{
var doc = logWindow.document;
// HACK so that head is available below:
doc.writeln("<html><head><title></title></head><body></body></html>");
doc.title = CPLogDefaultTitle + " Run Log";
var head = doc.getElementsByTagName("head")[0];
var body = doc.getElementsByTagName("body")[0];
var base = window.location.protocol + "//" + window.location.host + window.location.pathname;
base = base.substring(0,base.lastIndexOf("/")+1);
var link = doc.createElement("link");
link.setAttribute("type", "text/css");
link.setAttribute("rel", "stylesheet");
link.setAttribute("href", base+"Frameworks/Foundation/Resources/log.css");
link.setAttribute("media", "screen");
head.appendChild(link);
var div = doc.createElement("div");
div.setAttribute("id", "header");
body.appendChild(div);
// Enablers
var ul = doc.createElement("ul");
ul.setAttribute("id", "enablers");
div.appendChild(ul);
for (var i = 0; i < CPLogLevels.length; i++) {
var li = doc.createElement("li");
li.setAttribute("id", "en"+CPLogLevels[i]);
li.setAttribute("class", CPLogLevels[i]);
li.setAttribute("onclick", "toggle(this);");
li.setAttribute("enabled", "yes");
li.appendChild(doc.createTextNode(CPLogLevels[i]));
ul.appendChild(li);
}
// Options
var ul = doc.createElement("ul");
ul.setAttribute("id", "options");
div.appendChild(ul);
var options = {"focus":["Focus",false], "block":["Block",false], "wrap":["Wrap",false], "scroll":["Scroll",true], "close":["Close",true]};
for (o in options) {
var li = doc.createElement("li");
ul.appendChild(li);
logWindow[o+"Enabled"] = doc.createElement("input");
logWindow[o+"Enabled"].setAttribute("id", o);
logWindow[o+"Enabled"].setAttribute("type", "checkbox");
if (options[o][1])
logWindow[o+"Enabled"].setAttribute("checked", "checked");
li.appendChild(logWindow[o+"Enabled"]);
var label = doc.createElement("label");
label.setAttribute("for", o);
label.appendChild(doc.createTextNode(options[o][0]));
li.appendChild(label);
}
// Log
logWindow.log = doc.createElement("div");
logWindow.log.setAttribute("class", "enerror endebug enwarn eninfo enfatal entrace");
body.appendChild(logWindow.log);
logWindow.toggle = function(elem) {
var enabled = (elem.getAttribute("enabled") == "yes") ? "no" : "yes";
elem.setAttribute("enabled", enabled);
if (enabled == "yes")
logWindow.log.className += " " + elem.id
else
logWindow.log.className = logWindow.log.className.replace(new RegExp("[\\s]*"+elem.id, "g"), "");
}
// Scroll
logWindow.scrollToBottom = function() {
logWindow.scrollTo(0, body.offsetHeight);
}
// Wrap
logWindow.wrapEnabled.addEventListener("click", function() {
logWindow.log.setAttribute("wrap", logWindow.wrapEnabled.checked ? "yes" : "no");
}, false);
// Clear
logWindow.addEventListener("keydown", function(e) {
var e = e || logWindow.event;
if (e.keyCode == 75 && (e.ctrlKey || e.metaKey)) {
while (logWindow.log.firstChild) {
logWindow.log.removeChild(logWindow.log.firstChild);
}
e.preventDefault();
}
}, "false");
// Parent closing
window.addEventListener("unload", function() {
if (logWindow && logWindow.closeEnabled && logWindow.closeEnabled.checked) {
exports.CPLogDisable = true;
logWindow.close();
}
}, false);
// Log popup closing
logWindow.addEventListener("unload", function() {
if (!exports.CPLogDisable) {
exports.CPLogDisable = !confirm("Click cancel to stop logging");
}
}, false);
}
#endif
+10 -12
View File
@@ -3,7 +3,7 @@
var FILE = require("file");
var SYSTEM = require("system");
var OS = require("os");
var OBJJ = require("objective-j");
var CFPropertyList = require("objective-j").CFPropertyList;
var parser = new (require("args").Parser)();
@@ -13,8 +13,8 @@ parser.help("Cappuccino plist converter.");
parser.option("-c", "--convert", "format")
.help("rewrite property list files in format")
.choices({
"280north1" : OBJJ.kCFPropertyList280NorthFormat_v1_0,
"xml1": OBJJ.kCFPropertyListXMLFormat_v1_0
"280north1" : CFPropertyList.Format280North_v1_0,
"xml1": CFPropertyList.FormatXML_v1_0
});
parser.option("-l", "--lint", "lint")
@@ -50,15 +50,13 @@ exports.main = function(args)
if (typeof options.format !== "undefined" || options.lint)
{
ok = true;
options.args.forEach(function(filePath) {
var data = new OBJJ.objj_data();
data.string = FILE.read(filePath, { charset:"UTF-8" });
options.args.forEach(function(filePath)
{
var plistObject = CFPropertyList.propertyListFromString(FILE.read(filePath, { charset:"UTF-8" }));
var plistObject = OBJJ.CPPropertyListCreateFromData(data);
if (!plistObject)
{
// FIXME: more useful error messages
SYSTEM.stderr.print(filePath + ": parse error");
SYSTEM.stderr.print("Could not recognize format of plist at " + filePath);
ok = false;
return;
}
@@ -70,13 +68,13 @@ exports.main = function(args)
}
else
{
data = OBJJ.CPPropertyListCreateData(plistObject, options.format);
var encodedString = CFPropertyList.stringFromPropertyList(plistObject, options.format);
// outextension?
if (options.outPath === "-")
SYSTEM.stdout.write(data.string);
SYSTEM.stdout.write(encodedString);
else
FILE.write(options.outPath || filePath, data.string, { charset:"UTF-8" });
FILE.write(options.outPath || filePath, encodedString, { charset:"UTF-8" });
}
});
}
+83 -117
View File
@@ -1,5 +1,5 @@
var FILE = require("file");
var FILE = require("file");
var window = exports.window = require("browser/window");
if (system.engine === "rhino")
@@ -11,10 +11,11 @@ if (system.engine === "rhino")
// setup OBJJ_HOME, OBJJ_INCLUDE_PATHS, etc
window.OBJJ_HOME = exports.OBJJ_HOME = FILE.resolve(module.path, "..");
var frameworksPath = FILE.resolve(window.OBJJ_HOME, "Frameworks/"),
objectivejPath = FILE.resolve(frameworksPath, "Objective-J/", "CommonJS.environment/", "Objective-J.js");
var frameworksPath = FILE.resolve(window.OBJJ_HOME, "Frameworks/");
var OBJJ_INCLUDE_PATHS = window.OBJJ_INCLUDE_PATHS = exports.OBJJ_INCLUDE_PATHS = [];
var OBJJ_INCLUDE_PATHS = global.OBJJ_INCLUDE_PATHS = exports.OBJJ_INCLUDE_PATHS = [frameworksPath];
#include "Includes.js"
// Find all narwhal packages with Objective-J frameworks.
exports.objj_frameworks = [];
@@ -62,55 +63,10 @@ if (system.env["OBJJ_INCLUDE_PATHS"])
// TODO: somehow make window object the top scope?
with (window)
{
var objectivejSource = FILE.read(objectivejPath, { charset:"UTF-8" });
// read and eval Objective-J.js with the module's scope
if (system.engine === "rhino")
Packages.org.mozilla.javascript.Context.getCurrentContext().evaluateString(window, objectivejSource, objectivejPath, 0, null);
else
eval(objectivejSource);
// export desired variables. must eval variable name to obtain a reference.
[
"objj_preprocess",
"FRAGMENT_FILE", "FRAGMENT_LOCAL",
"MARKER_CODE", "MARKER_IMPORT_STD", "MARKER_IMPORT_LOCAL",
"OBJJ_PREPROCESSOR_DEBUG_SYMBOLS",
"objj_data",
"CPPropertyListCreateData", "CPPropertyListCreateFromData",
"kCFPropertyListXMLFormat_v1_0", "kCFPropertyList280NorthFormat_v1_0",
"objj_dictionary"
].forEach(function(v) {
exports[v] = eval(v);
});
// extra macros
exports.SET_CONTEXT = function(aFragment, aContext) { aFragment.context = aContext; }
exports.GET_CONTEXT = function(aFragment) { return aFragment.context; }
exports.SET_TYPE = function(aFragment, aType) { aFragment.type = aType; }
exports.GET_TYPE = function(aFragment) { return aFragment.type; }
exports.GET_CODE = function(aFragment) { return aFragment.info; }
exports.SET_CODE = function(aFragment, aCode) { aFragment.info = aCode; }
exports.GET_PATH = function(aFragment) { return aFragment.info; }
exports.SET_PATH = function(aFragment, aPath) { aFragment.info = aPath; }
exports.GET_BUNDLE = function(aFragment) { return aFragment.bundle; }
exports.SET_BUNDLE = function(aFragment, aBundle) { aFragment.bundle = aBundle; }
exports.GET_FILE = function(aFragment) { return aFragment.file; }
exports.SET_FILE = function(aFragment, aFile) { aFragment.file = aFile; }
exports.IS_FILE = function(aFragment) { return (aFragment.type & FRAGMENT_FILE); }
exports.IS_LOCAL = function(aFragment) { return (aFragment.type & FRAGMENT_LOCAL); }
exports.IS_IMPORT = function(aFragment) { return (aFragment.type & FRAGMENT_IMPORT); }
// runs the objj repl or file provided in args
exports.run = function(args)
{
if (args && args.length > 1)
if (args)
{
// we expect args to be in the format:
// 1) "objj" path
@@ -122,96 +78,106 @@ exports.run = function(args)
var argv = args.slice(1);
while (argv.length && argv[0].indexOf('-I') === 0)
OBJJ_INCLUDE_PATHS = argv.shift().substr(2).split(':').concat(OBJJ_INCLUDE_PATHS);
OBJJ_INCLUDE_PATHS.unshift.apply(OBJJ_INCLUDE_PATHS, argv.shift().substr(2).split(':'));
}
if (argv && argv.length > 0)
{
var arg0 = argv.shift();
var mainFilePath = FILE.canonical(arg0);
objj_import(mainFilePath, YES, function() {
if (typeof main === "function")
main([arg0].concat(argv));
});
exports.make_narwhal_factory(mainFilePath)(require, { }, module, system, print, window);
if (typeof main === "function")
main([arg0].concat(argv));
require("browser/timeout").serviceTimeouts();
}
else
{
while (true)
{
try {
system.stdout.write("objj> ").flush();
var result = objj_eval(require("readline").readline());
if (result !== undefined)
print(result);
} catch (e) {
print(e);
}
require("browser/timeout").serviceTimeouts();
}
exports.repl();
}
}
// synchronously evals Objective-J code
var objj_eval = exports.objj_eval = function(code)
exports.repl = function()
{
if (system.engine === "rhino")
var result = Packages.org.mozilla.javascript.Context.getCurrentContext().evaluateString(window, objj_preprocess_sync(code), "objj_eval", 0, null);
else
var result = eval(objj_preprocess_sync(code));
//require("browser/timeout").serviceTimeouts();
return result;
var READLINE = require("readline");
var historyPath = FILE.path(system.env["HOME"], ".objj_history");
var historyFile = null;
if (historyPath.exists() && READLINE.addHistory) {
historyPath.read({ charset : "UTF-8" }).split("\n").forEach(function(line) {
if (line.trim())
READLINE.addHistory(line);
});
}
try {
historyFile = historyPath.open("a", { charset : "UTF-8" });
} catch (e) {
system.stderr.print("Warning: Can't open history file '"+historyFile+"' for writing.");
}
while (true)
{
try {
system.stdout.write("objj> ").flush();
var line = READLINE.readline();
if (line && historyFile)
historyFile.write(line).write("\n").flush();
var result = exports.objj_eval(line);
if (result !== undefined)
print(result);
} catch (e) {
print(e);
}
require("browser/timeout").serviceTimeouts();
}
}
// prepocesses Objective-J code into JavaScript, which will perform imports synchronously when eval'd
window.objj_preprocess_sync = function(code, path)
exports.objj_eval = function(/*String*/ aString)
{
var fragments = objj_preprocess(code, new objj_bundle(), new objj_file(), OBJJ_PREPROCESSOR_DEBUG_SYMBOLS)
// We need this while code still refers to window.
Executable.setCommonJSArguments(require, exports, module, system, print, window);
var preprocessed = [];
var executable = preprocess(aString, "", 0);
fragments.forEach(function(fragment) {
if (fragment.type & FRAGMENT_CODE)
preprocessed.push(fragment.info);
else if (fragment.type & FRAGMENT_LOCAL)
preprocessed.push("objj_import_sync('"+(path ? FILE.join(FILE.dirname(path), fragment.info) : fragment.info)+"',YES);");
else
preprocessed.push("objj_import_sync('"+fragment.info+"',NO);");
});
return preprocessed.join("\n");
if (!executable.hasLoadedFileDependencies())
executable.loadFileDependencies();
// A bit of a hack. Executable compiles the code itself into a function, but we want
// the raw code to eval here.
var code = executable._code;
// Not clear why these should be global, varing them doesn't seem to take effect with evaluateString.
global.objj_executeFile = exports.fileExecuterForPath(FILE.cwd());
global.objj_importFile = fileImporterForPath(FILE.cwd());
if (typeof system !== "undefined" && system.engine === "rhino")
return Packages.org.mozilla.javascript.Context.getCurrentContext().evaluateString(global, code, "objj_eval", 0, NULL);
return eval(code);
}
// FIXME: Why does this need to be global?
// synchronously perform an import
window.objj_import_sync = function(pathOrPaths, isLocal)
{
var context = new objj_context();
context.pushFragment(fragment_create_file(pathOrPaths, new objj_bundle(), isLocal, NULL));
context.evaluate();
// HACK: need a real synchronous require
// FIXME: this is bad. not really synchronous. shouldn't have to call serviceTimeouts.
require("browser/timeout").serviceTimeouts();
}
Executable.setCommonJSParameters("require", "exports", "module", "system", "print", "window");
// creates a narwhal factory function in the objj module scope
exports.make_narwhal_factory = function(code, path) {
var OBJJ_CURRENT_BUNDLE = new objj_bundle();
var factoryText = "function(require,exports,module,system,print){" + objj_preprocess_sync(code, path) + "/**/\n}";
exports.make_narwhal_factory = function(path)
{
return function(require, exports, module, system, print)
{
Executable.setCommonJSArguments(require, exports, module, system, print, window);
if (system.engine === "rhino")
return Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(window, factoryText, path, 0, null);
// eval requires parenthesis, but parenthesis break compileFunction.
else
return eval("(" + factoryText + ")");
fileImporterForPath(FILE.dirname(path))(path, function()
{
print("all done");
});
}
}
} // end "with"
@@ -1,55 +1,36 @@
var FILE = require("file"),
OS = require("os"),
objj = require("objective-j"),
objj_preprocess = objj.objj_preprocess,
IS_FILE = objj.IS_FILE,
IS_LOCAL = objj.IS_LOCAL,
GET_CODE = objj.GET_CODE,
GET_FILE = objj.GET_FILE,
MARKER_IMPORT_STD = objj.MARKER_IMPORT_STD,
MARKER_IMPORT_LOCAL = objj.MARKER_IMPORT_LOCAL,
MARKER_CODE = objj.MARKER_CODE,
GET_PATH = objj.GET_PATH;
ObjectiveJ = require("objective-j");
require("objective-j/rhino/regexp-rhino-patch");
var OBJJ_PREPROCESSOR_DEBUG_SYMBOLS = exports.OBJJ_PREPROCESSOR_DEBUG_SYMBOLS = objj.OBJJ_PREPROCESSOR_DEBUG_SYMBOLS;
var OBJJ_PREPROCESSOR_TYPE_SIGNATURES = exports.OBJJ_PREPROCESSOR_TYPE_SIGNATURES = objj.OBJJ_PREPROCESSOR_TYPE_SIGNATURES;
var OBJJ_PREPROCESSOR_DEBUG_SYMBOLS = exports.OBJJ_PREPROCESSOR_DEBUG_SYMBOLS = ObjectiveJ.OBJJ_PREPROCESSOR_DEBUG_SYMBOLS;
var OBJJ_PREPROCESSOR_TYPE_SIGNATURES = exports.OBJJ_PREPROCESSOR_TYPE_SIGNATURES = ObjectiveJ.OBJJ_PREPROCESSOR_TYPE_SIGNATURES;
var OBJJ_PREPROCESSOR_PREPROCESS = exports.OBJJ_PREPROCESSOR_PREPROCESS = 1 << 10;
var OBJJ_PREPROCESSOR_COMPRESS = exports.OBJJ_PREPROCESSOR_COMPRESS = 1 << 11;
var OBJJ_PREPROCESSOR_SYNTAX = exports.OBJJ_PREPROCESSOR_SYNTAX = 1 << 12;
var SHRINKSAFE_PATH = FILE.join(objj.OBJJ_HOME, "shrinksafe", "shrinksafe.jar"),
RHINO_PATH = FILE.join(objj.OBJJ_HOME, "shrinksafe", "js.jar")
var compressor = null;
function sharedCompressor()
{
if (!compressor)
compressor = OS.popen("java -server -Dfile.encoding=UTF-8 -classpath " + RHINO_PATH + ":" + SHRINKSAFE_PATH + " org.dojotoolkit.shrinksafe.Main", { charset:"UTF-8" });
return compressor;
}
function compress(/*String*/ aCode, /*String*/ FIXME)
{
var tmpFile = FILE.join("/tmp", FIXME + Math.random() + ".tmp");
FILE.write(tmpFile, aCode, { charset:"UTF-8" });
var compressor = sharedCompressor();
output = "",
chunk = "";
compressor.stdin.write(tmpFile + "\n");
compressor.stdin.flush();
while ((chunk = compressor.stdout.readLine()) !== "/*----*/\n")
output += chunk;
return output;
// return OS.command(["java", "-Dfile.encoding=UTF-8", "-classpath", [RHINO_PATH, SHRINKSAFE_PATH].join(":"), "org.dojotoolkit.shrinksafe.Main", tmpFile]);
var compressors = {
ss : { id : "minify/shrinksafe" }
//,yui : { id : "minify/yuicompressor" }
// ,cc : { id : "minify/closure-compiler" }
};
var compressorStats = {};
function compressor(code) {
var winner, winnerName;
compressorStats['original'] = (compressorStats['original'] || 0) + code.length;
for (var name in compressors) {
var compressor = require(compressors[name].id);
var result = compressor.compress(code, { charset : "UTF-8", useServer : true });
compressorStats[name] = (compressorStats[name] || 0) + result.length;
if (!winner || result < winner.length) {
winner = result;
winnerName = name;
}
}
// print("winner="+winnerName+" compressorStats="+JSON.stringify(compressorStats));
return winner;
}
function compileWithResolvedFlags(aFilePath, objjcFlags, gccFlags)
@@ -76,53 +57,35 @@ function compileWithResolvedFlags(aFilePath, objjcFlags, gccFlags)
return fileContents;
// Preprocess contents into fragments.
var fragments = objj_preprocess(fileContents, { path : "/x" }, { path: FILE.basename(aFilePath) }, objjcFlags),
preprocessed = "";
// Writer preprocessed fragments out.
for (var index = 0; index < fragments.length; index++)
// FIXME: should calculate relative path, etc.
try
{
var fragment = fragments[index];
var executable = ObjectiveJ.preprocess(fileContents, FILE.basename(aFilePath), objjcFlags);
}
catch (anException)
{print(anException);
var lines = fileContents.split("\n"),
PAD = 3,
lineNumber = anException.lineNumber || anException.line,
errorInfo = "Syntax error in " + aFilePath +
" on preprocessed line number " + lineNumber + "\n\n" +
"\t" + lines.slice(Math.max(0, lineNumber - 1 - PAD), lineNumber + PAD).join("\n\t");
if (IS_FILE(fragment))
preprocessed += (IS_LOCAL(fragment) ? MARKER_IMPORT_LOCAL : MARKER_IMPORT_STD) + ';' + GET_PATH(fragment).length + ';' + GET_PATH(fragment);
else
{
var code = GET_CODE(fragment);
print(errorInfo);
if (shouldCheckSyntax)
{
try
{
new Function(GET_CODE(fragment));
}
catch (e)
{
var lines = code.split("\n"),
PAD = 3,
lineNumber = e.lineNumber || e.line,
errorInfo = "Syntax error in "+GET_FILE(fragment).path+
" on preprocessed line number "+lineNumber+"\n\n"+
"\t"+lines.slice(Math.max(0, lineNumber - 1 - PAD), lineNumber+PAD).join("\n\t");
print(errorInfo);
throw errorInfo;
}
}
if (shouldCompress)
{
code = compress("function(){" + code + '}', FILE.basename(aFilePath));
code = code.substr("function(){".length, code.length - "function(){};\n\n".length);
}
preprocessed += MARKER_CODE + ';' + code.length + ';' + code;
}
throw errorInfo;
}
return preprocessed;
if (shouldCompress)
{
var code = executable.code();
code = compressor("function(){" + code + "}");
// more robust function wrapper stripping
code = code.replace(/^\s*function\s*\(\s*\)\s*{|}\s*;?\s*$/g, "");
executable.setCode(code);
}
return executable.toMarkedString();
}
function resolveFlags(args)
@@ -1,5 +1,6 @@
var FILE = require("file"),
OS = require("OS"),
Jake = require("jake"),
BundleTask = require("objective-j/jake/bundletask").BundleTask;
@@ -11,6 +12,11 @@ function ApplicationTask(aName)
this._indexFilePath = "index.html";
else
this._indexFilePath = null;
if (FILE.exists("Frameworks"))
this._frameworksPath = "Frameworks";
else
this._frameworksPath = null;
}
ApplicationTask.__proto__ = BundleTask;
@@ -39,21 +45,44 @@ ApplicationTask.prototype.indexFilePath = function()
return this._indexFilePath;
}
ApplicationTask.prototype.setFrameworksPath = function(aFrameworksPath)
{
// The default will use local app frameworks
// Pass in ENV["CAPP_BUILD"] to use your built frameworks
// Pass in "capp" to use installed frameworks
this._frameworksPath = aFrameworksPath;
}
ApplicationTask.prototype.frameworksPath = function()
{
return this._frameworksPath;
}
ApplicationTask.prototype.defineFrameworksTask = function()
{
// FIXME: platform requires...
if (this.flattenedEnvironments().indexOf(require("objective-j/jake/environment").Browsers) === -1)
if (!this._frameworksPath && this.environments().indexOf(require("objective-j/jake/environment").Browser) === -1)
return;
var frameworks = FILE.join(this.buildProductPath(), "Frameworks"),
var buildPath = this.buildProductPath(),
newFrameworks = FILE.join(buildPath, "Frameworks"),
thisTask = this;
Jake.fileCreate(frameworks, function()
Jake.fileCreate(newFrameworks, function()
{
OS.system("capp gen -f " + thisTask.buildProductPath());
if (thisTask._frameworksPath === "capp")
OS.system("capp gen -f --force " + buildPath);
else if (thisTask._frameworksPath)
{
if (FILE.exists(newFrameworks))
FILE.rmtree(newFrameworks);
FILE.copyTree(thisTask._frameworksPath, newFrameworks);
}
});
this.enhance([frameworks]);
this.enhance([newFrameworks]);
}
ApplicationTask.prototype.buildIndexFilePath = function()
@@ -7,7 +7,12 @@ var FILE = require("file"),
CLEAN = require("jake/clean").CLEAN,
CLOBBER = require("jake/clean").CLOBBER,
base64 = require("base64"),
environment = require("objective-j/jake/environment");
environment = require("objective-j/jake/environment"),
ObjectiveJ = require("objective-j"),
task = Jake.task;
var CFPropertyList = ObjectiveJ.CFPropertyList,
CFMutableDictionary = ObjectiveJ.CFMutableDictionary;
var Task = Jake.Task,
filedir = Jake.filedir;
@@ -34,7 +39,7 @@ function BundleTask(aName, anApplication)
{
Task.apply(this, arguments);
this.setEnvironments([environment.Browsers, environment.CommonJS]);
this.setEnvironments([environment.Browser, environment.CommonJS]);
this._author = null;
this._email = null;
@@ -91,8 +96,6 @@ BundleTask.prototype.setEnvironments = function(environments)
else
this._environments = [environments];
this._flattenedEnvironments = environment.Environment.flattenedEnvironments(this._environments);
}
BundleTask.prototype.environments = function()
@@ -100,11 +103,6 @@ BundleTask.prototype.environments = function()
return this._environments;
}
BundleTask.prototype.flattenedEnvironments = function()
{
return this._flattenedEnvironments;
}
BundleTask.prototype.setAuthor = function(anAuthor)
{
this._author = anAuthor;
@@ -161,14 +159,13 @@ BundleTask.prototype.setSources = function(sources, environments)
this._sources = sources;
else
{
if (Array.isArray(environments))
environments = environment.Environment.flattenedEnvironments(environments);
else
environments = environments.flattenedEnvironments();
if (!this._sources)
this._sources = { };
// If a single envirnment was passed in...
if (!Array.isArray(environments))
environments = [environments];
environments.forEach(function(anEnvironment)
{
this._sources[anEnvironment] = sources;
@@ -318,6 +315,16 @@ BundleTask.prototype.buildProductStaticPathForEnvironment = function(anEnvironme
return FILE.join(this.buildProductPath(), anEnvironment.name() + ".environment", this.productName() + ".sj");
}
BundleTask.prototype.buildProductMHTMLPathForEnvironment = function(anEnvironment)
{
return FILE.join(this.buildProductPath(), anEnvironment.name() + ".environment", "MHTML.txt");
}
BundleTask.prototype.buildProductDataURLPathForEnvironment = function(anEnvironment)
{
return FILE.join(this.buildProductPath(), anEnvironment.name() + ".environment", "dataURLs.txt");
}
BundleTask.prototype.defineTasks = function()
{
this.defineResourceTasks();
@@ -325,6 +332,7 @@ BundleTask.prototype.defineTasks = function()
this.defineInfoPlistTask();
this.defineLicenseTask();
this.defineStaticTask();
this.defineSpritedImagesTask();
CLEAN.include(this.buildIntermediatesProductPath());
CLOBBER.include(this.buildProductPath());
@@ -337,39 +345,37 @@ BundleTask.prototype.packageType = function()
BundleTask.prototype.infoPlist = function()
{
var infoPlistPath = this.infoPlistPath(),
objj_dictionary = require("objective-j").objj_dictionary;
var infoPlistPath = this.infoPlistPath();
if (infoPlistPath && FILE.exists(infoPlistPath))
var infoPlist = require("objective-j/plist").readPlist(infoPlistPath);
var infoPlist = CFPropertyList.propertyListFromString(FILE.read(infoPlistPath, { charset:"UTF-8" }));
else
var infoPlist = new objj_dictionary();
var infoPlist = new CFMutableDictionary();
// FIXME: Should all of these unconditionally overwrite?
infoPlist.setValue("CPBundleInfoDictionaryVersion", 6.0);
infoPlist.setValue("CPBundleName", this.productName());
infoPlist.setValue("CPBundleIdentifier", this.identifier());
infoPlist.setValue("CPBundleVersion", this.version());
infoPlist.setValue("CPBundlePackageType", this.packageType());
infoPlist.setValue("CPBundleEnvironments", this.flattenedEnvironments().map(function(anEnvironment)
infoPlist.setValueForKey("CPBundleInfoDictionaryVersion", 6.0);
infoPlist.setValueForKey("CPBundleName", this.productName());
infoPlist.setValueForKey("CPBundleIdentifier", this.identifier());
infoPlist.setValueForKey("CPBundleVersion", this.version());
infoPlist.setValueForKey("CPBundlePackageType", this.packageType());
infoPlist.setValueForKey("CPBundleEnvironments", this.environments().map(function(anEnvironment)
{
return anEnvironment.name();
}));
infoPlist.setValueForKey("CPBundleExecutable", this.productName() + ".sj");
infoPlist.setValueForKey("CPBundleEnvironmentsWithImageSprites", this.environments().filter(
function(anEnvironment)
{
return anEnvironment.spritesImages();
}).map(function(anEnvironment)
{
return anEnvironment.name();
}));
infoPlist.setValue("CPBundleExecutable", this.productName() + ".sj");
var principalClass = this.principalClass();
if (principalClass)
infoPlist.setValue("CPPrincipalClass", principalClass);
var replacedFiles = this._replacedFiles,
replacedFilesDictionary = new objj_dictionary();
for (var engine in replacedFiles)
if (replacedFiles.hasOwnProperty(engine))
replacedFilesDictionary.setValue(engine, replacedFiles[engine]);
infoPlist.setValue("CPBundleReplacedFiles", replacedFilesDictionary);
infoPlist.setValueForKey("CPPrincipalClass", principalClass);
return infoPlist;
}
@@ -381,7 +387,7 @@ BundleTask.prototype.defineInfoPlistTask = function()
filedir (infoPlistProductPath, function()
{
require("objective-j/plist").writePlist(infoPlistProductPath, bundleTask.infoPlist());
FILE.write(infoPlistProductPath, CFPropertyList.stringFromPropertyList(bundleTask.infoPlist(), CFPropertyList.Format280North_v1_0), { charset:"UTF-8" });
});
var infoPlistPath = this.infoPlistPath();
@@ -391,7 +397,7 @@ BundleTask.prototype.defineInfoPlistTask = function()
// FIXME: ? We do this because adding a .j file should cause Info.plist to be updated.
// Any better way to handle this? Perhaps this should happen unconditionally.
this.flattenedEnvironments().forEach(function(/*Environment*/ anEnvironment)
this.environments().forEach(function(/*Environment*/ anEnvironment)
{
if (!anEnvironment.spritesImages())
return;
@@ -441,7 +447,7 @@ BundleTask.prototype.defineResourceTask = function(aResourcePath, aDestinationPa
// Don't sprite images larger than 32KB, IE 8 doesn't like it.
if (this.spritesResources() && isImage(aResourcePath) && FILE.size(aResourcePath) < 32768)
{
this.flattenedEnvironments().forEach(function(/*Environment*/ anEnvironment)
this.environments().forEach(function(/*Environment*/ anEnvironment)
{
if (!anEnvironment.spritesImages())
return;
@@ -451,11 +457,10 @@ BundleTask.prototype.defineResourceTask = function(aResourcePath, aDestinationPa
filedir (spritedDestinationPath, function()
{
FILE.write(spritedDestinationPath, base64.encode(FILE.read(aResourcePath, { mode : 'b'})), { charset:"UTF-8" });
FILE.write(spritedDestinationPath, base64.encode(FILE.read(aResourcePath, "b")), { charset:"UTF-8" });
});
// Add this as a dependency unconditionally because we need to set up the URL map either way.
filedir (this.buildProductStaticPathForEnvironment(anEnvironment), [spritedDestinationPath]);
task (anEnvironment.name() + "-sprites", [spritedDestinationPath]);
}, this);
}
@@ -565,9 +570,73 @@ BundleTask.prototype.defineResourceTasks = function()
}, this);
}
BundleTask.prototype.defineSpritedImagesTask = function()
{
this.environments().forEach(function(/*Environment*/ anEnvironment)
{
if (!anEnvironment.spritesImages())
return;
var folder = anEnvironment.name() + ".environment",
resourcesPath = FILE.join(this.buildIntermediatesProductPath(), folder, "Resources", ""),
dataURLPath = this.buildProductDataURLPathForEnvironment(anEnvironment),
MHTMLPath = this.buildProductMHTMLPathForEnvironment(anEnvironment),
productName = this.productName();
task(anEnvironment.name() + "-sprites", function(aTask)
{
TERM.stream.print("Creating sprited images file... \0green(" + dataURLPath +"\0)");
var dataURLStream = FILE.open(dataURLPath, "w+", { charset:"UTF-8" }),
MHTMLStream = FILE.open(MHTMLPath, "w+", { charset:"UTF-8" }),
MHTMLContents = "/*\r\nContent-Type: multipart/related; boundary=\"_ANY_STRING_WILL_DO_AS_A_SEPARATOR\"\r\n\r\n";
dataURLStream.write("@STATIC;1.0;");
MHTMLStream.write("@STATIC;1.0;");
aTask.prerequisites().forEach(function(aFilename)
{
if (!FILE.isFile(aFilename) || aFilename.indexOf(resourcesPath) !== 0 || !isImage(aFilename))
return;
var resourcePath = "Resources/" + FILE.relative(resourcesPath, aFilename);
dataURLStream.write("u;" + resourcePath.length + ";" + resourcePath);
MHTMLStream.write("u;" + resourcePath.length + ";" + resourcePath);
// As data URL...
var contents = "data:" + mimeType(aFilename) +
";base64," + FILE.read(aFilename, "b").decodeToString("UTF-8");
dataURLStream.write(contents.length + ";" + contents);
// As MHTML...
contents = "mhtml:" + FILE.join(folder, productName + ".sj!") + resourcePath;
MHTMLContents += "--_ANY_STRING_WILL_DO_AS_A_SEPARATOR\r\n";
MHTMLContents += "Content-Location:" + resourcePath + "\r\nContent-Transfer-Encoding:base64\r\n\r\n";
MHTMLContents += FILE.read(aFilename, "b").decodeToString("UTF-8");
MHTMLContents += "\r\n";
MHTMLStream.write(contents.length + ";" + contents);
});
dataURLStream.write("e;");
dataURLStream.close();
MHTMLStream.write("e;");
MHTMLStream.write(MHTMLContents + "*/");
MHTMLStream.close();
});
this.enhance([anEnvironment.name() + "-sprites"]);
}, this);
}
BundleTask.prototype.defineStaticTask = function()
{
this.flattenedEnvironments().forEach(function(/*Environment*/ anEnvironment)
this.environments().forEach(function(/*Environment*/ anEnvironment)
{
var folder = anEnvironment.name() + ".environment",
sourcesPath = FILE.join(this.buildIntermediatesProductPath(), folder, "Sources", ""),
@@ -597,56 +666,28 @@ BundleTask.prototype.defineStaticTask = function()
{
var relativePath = flattensSources ? FILE.basename(aFilename) : FILE.relative(sourcesPath, aFilename);
// FIXME: We need to do this for now due to file.read adding newlines in Rhino. Revert when fixed.
//fileStream.write(FILE.read(aFilename, "b").decodeToString("UTF-8"));
fileStream.write("p;" + relativePath.length + ";" + relativePath);
// FIXME: We need to do this for now due to file.read adding newlines. Revert when fixed.
//fileStream.write(FILE.read(aFilename, { charset:"UTF-8" }));
fileStream.write(FILE.read(aFilename, { mode:"b" }).decodeToString("UTF-8"));
var fileContents = FILE.read(aFilename, "b").decodeToString("UTF-8");
fileStream.write("t;" + fileContents.length + ";" + fileContents);
}
else if (aFilename.indexOf(resourcesPath) === 0)
else if (aFilename.indexOf(resourcesPath) === 0 && !isImage(aFilename))
{
var contents = "",
resourcePath = "Resources/" + FILE.relative(resourcesPath, aFilename);
var resourcePath = "Resources/" + FILE.relative(resourcesPath, aFilename);
if (isImage(aFilename))
{
fileStream.write("u;");
fileStream.write("p;");
if (anEnvironment.spritesImagesAsDataURLs())
contents = "data:" + mimeType(aFilename) + ";base64," + FILE.read(aFilename, { charset:"UTF-8" });
else if (anEnvironment.spritesImagesAsMHTML())
{
contents = "mhtml:" + FILE.join(folder, productName + ".sj!") + resourcePath;
if (!MHTMLContents.length)
MHTMLContents = "/*\r\nContent-Type: multipart/related; boundary=\"_ANY_STRING_WILL_DO_AS_A_SEPARATOR\"\r\n\r\n";
MHTMLContents += "--_ANY_STRING_WILL_DO_AS_A_SEPARATOR\r\n";
MHTMLContents += "Content-Location:" + resourcePath + "\r\nContent-Transfer-Encoding:base64\r\n\r\n";
MHTMLContents += FILE.read(aFilename, { charset:"UTF-8" });
MHTMLContents += "\r\n";
}
contents = contents.length + ";" + contents;
}
else
{
fileStream.write("p;");
contents = FILE.read(aFilename, { charset:"UTF-8" });
}
contents = FILE.read(aFilename, "b").decodeToString("UTF-8");
fileStream.write(resourcePath.length + ";" + resourcePath + contents);
}
}, this);
fileStream.write("e;");
if (MHTMLContents.length > 0)
fileStream.write(MHTMLContents + "*/");
fileStream.close();
});
@@ -670,10 +711,9 @@ BundleTask.prototype.defineSourceTasks = function()
else if (compilerFlags.join)
compilerFlags = compilerFlags.join(" ");
var environments = this.flattenedEnvironments(),
flattensSources = this.flattensSources();
var flattensSources = this.flattensSources();
environments.forEach(function(/*Environment*/ anEnvironment)
this.environments().forEach(function(/*Environment*/ anEnvironment)
{
var environmentSources = sources,
folder = anEnvironment.name() + ".environment",
@@ -5,9 +5,8 @@ function Environment(/*String*/ aName)
{
this._name = aName;
this._compilerFlags = [];
this._spritesImagesAsMHTML = false;
this._spritesImagesAsDataURLs = false;
this._spritesImages = false;
environments[aName] = this;
}
@@ -16,18 +15,6 @@ Environment.environmentWithName = function(/*String*/ aName)
return environments[aName];
}
Environment.flattenedEnvironments = function(/*Array*/ environments)
{
var flattenedEnvironments = [];
environments.forEach(function(/*Environment*/ anEnvironment)
{
Array.prototype.push.apply(flattenedEnvironments, anEnvironment.flattenedEnvironments());
});
return flattenedEnvironments;
}
Environment.prototype.name = function()
{
return this._name;
@@ -38,11 +25,6 @@ Environment.prototype.toString = function()
return this._name;
}
Environment.prototype.flattenedEnvironments = function()
{
return [this];
}
Environment.prototype.compilerFlags = function()
{
return this._compilerFlags;
@@ -53,29 +35,14 @@ Environment.prototype.setCompilerFlags = function(flags)
this._compilerFlags = flags;
}
Environment.prototype.setSpritesImagesAsMHTML = function(/*Boolean*/ shouldSpriteImagesAsMHTML)
Environment.prototype.setSpritesImages = function(/*Boolean*/ shouldSpriteImages)
{
this._spritesImagesAsMHTML = !!shouldSpriteImagesAsMHTML;
}
Environment.prototype.spritesImagesAsMHTML = function()
{
return this._spritesImagesAsMHTML;
}
Environment.prototype.setSpritesImagesAsDataURLs = function(/*Boolean*/ shouldSpriteImagesAsDataURLs)
{
this._spritesImagesAsDataURLs = !!shouldSpriteImagesAsDataURLs;
}
Environment.prototype.spritesImagesAsDataURLs = function()
{
return this._spritesImagesAsDataURLs;
this._spritesImages = !!shouldSpriteImages;
}
Environment.prototype.spritesImages = function()
{
return this.spritesImagesAsMHTML() || this.spritesImagesAsDataURLs();
return this._spritesImages;
}
exports.Environment = Environment;
@@ -88,56 +55,9 @@ CommonJS.setCompilerFlags(["-DPLATFORM_COMMONJS"]);
exports.CommonJS = CommonJS;
var W3C = new Environment("W3C");
var Browser = new Environment("Browser");
W3C.setCompilerFlags(["-DPLATFORM_BROWSER", "-DPLATFORM_DOM"]);
W3C.setSpritesImagesAsDataURLs(true);
exports.W3C = W3C;
var IE7 = new Environment("IE7");
IE7.setCompilerFlags(["-DPLATFORM_BROWSER", "-DPLATFORM_DOM"]);
IE7.setSpritesImagesAsMHTML(true);
exports.IE7 = IE7;
var IE8 = new Environment("IE8");
IE8.setCompilerFlags(["-DPLATFORM_BROWSER", "-DPLATFORM_DOM"]);
IE8.setSpritesImagesAsDataURLs(true);
exports.IE8 = IE8;
function EnvironmentCollection(/*String*/ aName, /*Array*/ environments)
{
this._name = aName;
this._environments = environments;
environments[aName] = this;
}
EnvironmentCollection.prototype.name = function()
{
return this._name;
}
EnvironmentCollection.prototype.toString = function()
{
return this._name;
}
EnvironmentCollection.prototype.flattenedEnvironments = function()
{
var environments = [];
this._environments.forEach(function(anEnvironment)
{
Array.prototype.push.apply(environments, anEnvironment.flattenedEnvironments());
});
return environments;
}
exports.Browsers = new EnvironmentCollection("Browsers", [W3C, IE7, IE8]);
Browser.setCompilerFlags(["-DPLATFORM_BROWSER", "-DPLATFORM_DOM"]);
Browser.setSpritesImages(true);
exports.Browser = Browser;
@@ -8,7 +8,8 @@ function ObjectiveJLoader() {
if (!objj) objj = require("objective-j");
//print("loading objective-j: " + topId + " (" + path + ")");
factories[topId] = objj.make_narwhal_factory(system.fs.read(path), path);
factories[topId] = objj.make_narwhal_factory(path);
factories[topId].path = path;
}
loader.load = function(topId, path) {
@@ -1,17 +0,0 @@
var FILE = require("file"),
OBJJ = require("objective-j"),
CPPropertyListCreateData = OBJJ.CPPropertyListCreateData,
kCFPropertyListXMLFormat_v1_0 = OBJJ.kCFPropertyListXMLFormat_v1_0;
exports.readPlist = function(aPath)
{
var plistData = new OBJJ.objj_data();
plistData.string = FILE.read(aPath, { charset:"UTF-8" });
return OBJJ.CPPropertyListCreateFromData(plistData);
}
exports.writePlist = function(aPath, plist, format)
{
format = format || OBJJ.kCFPropertyListXMLFormat_v1_0;
FILE.write(aPath, OBJJ.CPPropertyListCreateData(plist, format).string, { charset:"UTF-8" });
}
+94
View File
@@ -0,0 +1,94 @@
var undefined;
exports.environments = function()
{
return ENVIRONMENTS;
}
if (typeof window !== "undefined")
{
window.setNativeTimeout = window.setTimeout;
window.clearNativeTimeout = window.clearTimeout;
window.setNativeInterval = window.setInterval;
window.clearNativeInterval = window.clearNativeInterval;
}
// Objective-J Constants
var NO = false,
YES = true,
nil = null,
Nil = null,
NULL = null,
ABS = Math.abs,
ASIN = Math.asin,
ACOS = Math.acos,
ATAN = Math.atan,
ATAN2 = Math.atan2,
SIN = Math.sin,
COS = Math.cos,
TAN = Math.tan,
EXP = Math.exp,
POW = Math.pow,
CEIL = Math.ceil,
FLOOR = Math.floor,
ROUND = Math.round,
MIN = Math.min,
MAX = Math.max,
RAND = Math.random,
SQRT = Math.sqrt,
E = Math.E,
LN2 = Math.LN2,
LN10 = Math.LN10,
LOG2E = Math.LOG2E,
LOG10E = Math.LOG10E,
PI = Math.PI,
PI2 = Math.PI * 2.0,
PI_2 = Math.PI / 2.0,
SQRT1_2 = Math.SQRT1_2,
SQRT2 = Math.SQRT2;
exports.NO = NO;
exports.YES = YES;
exports.nil = nil;
exports.Nil = Nil;
exports.NULL = NULL;
exports.ABS = ABS;
exports.ASIN = ASIN;
exports.ACOS = ACOS;
exports.ATAN = ATAN;
exports.ATAN2 = ATAN2;
exports.SIN = SIN;
exports.COS = COS;
exports.TAN = TAN;
exports.EXP = EXP;
exports.POW = POW;
exports.CEIL = CEIL;
exports.FLOOR = FLOOR;
exports.ROUND = ROUND;
exports.MIN = MIN;
exports.MAX = MAX;
exports.RAND = RAND;
exports.SQRT = SQRT;
exports.E = E;
exports.LN2 = LN2;
exports.LN10 = LN10;
exports.LOG2E = LOG2E;
exports.LOG10E = LOG10E;
exports.PI = PI;
exports.PI2 = PI * 2.0;
exports.PI_2 = PI / 2.0;
exports.SQRT1_2 = SQRT1_2;
exports.SQRT2 = SQRT2;
@@ -39,7 +39,7 @@ function objj_msgSend_decorate()
function objj_msgSend_set_decorators()
{
objj_msgSend_reset();
objj_msgSend_decorate.apply(null, arguments);
objj_msgSend_decorate.apply(NULL, arguments);
}
@@ -62,7 +62,7 @@ function objj_backtrace_decorator(msgSend)
objj_backtrace.push({ receiver: aReceiver, selector : aSelector });
try
{
return msgSend.apply(null, arguments);
return msgSend.apply(NULL, arguments);
}
catch (anException)
{
@@ -81,7 +81,7 @@ function objj_backtrace_decorator(msgSend)
// type checking decorator
var objj_typechecks_reported = {},
objj_typecheck_prints_backtrace = false;
objj_typecheck_prints_backtrace = NO;
function objj_typecheck_decorator(msgSend)
{
@@ -90,7 +90,7 @@ function objj_typecheck_decorator(msgSend)
var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper);
if (!aReceiver)
return msgSend.apply(null, arguments);
return msgSend.apply(NULL, arguments);
var types = aReceiver.isa.method_dtable[aSelector].types;
for (var i = 2; i < arguments.length; i++)
@@ -103,7 +103,7 @@ function objj_typecheck_decorator(msgSend)
{
var key = [GETMETA(aReceiver).name, aSelector, i, e].join(";");
if (!objj_typechecks_reported[key]) {
objj_typechecks_reported[key] = true;
objj_typechecks_reported[key] = YES;
objj_fprintf(warning_stream, "Type check failed on argument " + (i-2) + " of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e);
if (objj_typecheck_prints_backtrace)
objj_backtrace_print(warning_stream);
@@ -111,7 +111,7 @@ function objj_typecheck_decorator(msgSend)
}
}
var result = msgSend.apply(null, arguments);
var result = msgSend.apply(NULL, arguments);
try
{
@@ -121,7 +121,7 @@ function objj_typecheck_decorator(msgSend)
{
var key = [GETMETA(aReceiver).name, aSelector, "ret", e].join(";");
if (!objj_typechecks_reported[key]) {
objj_typechecks_reported[key] = true;
objj_typechecks_reported[key] = YES;
objj_fprintf(warning_stream, "Type check failed on return val of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e);
if (objj_typecheck_prints_backtrace)
objj_backtrace_print(warning_stream);
@@ -171,7 +171,7 @@ function objj_debug_typecheck(expectedType, object)
}
var actualType;
if (object === null)
if (object === NULL)
actualType = "null";
else if (object === undefined)
actualType = "void";
+3
View File
@@ -0,0 +1,3 @@
#define DEPENDENCY_LOGGING 0
#define EXECUTION_LOGGING 0
+64
View File
@@ -0,0 +1,64 @@
function Event(/*String*/ aType)
{
this.type = aType;
}
function EventDispatcher(/*Object*/ anOwner)
{
this._eventListenersForEventNames = { };
this._owner = anOwner;
}
EventDispatcher.prototype.addEventListener = function(/*String*/ anEventName, /*Function*/ anEventListener)
{
var eventListenersForEventName = this._eventListenersForEventNames[anEventName];
if (!eventListenersForEventName)
{
eventListenersForEventName = [];
this._eventListenersForEventNames[anEventName] = eventListenersForEventName;
}
var index = eventListenersForEventName.length;
while (index--)
if (eventListenersForEventName[index] === anEventListener)
return;
eventListenersForEventName.push(anEventListener);
}
EventDispatcher.prototype.removeEventListener = function(/*String*/ anEventName, /*Function*/ anEventListener)
{
var eventListenersForEventName = this._eventListenersForEventNames[anEventName];
if (!eventListenersForEventName)
return;
var index = eventListenersForEventName.length;
while (index--)
if (eventListenersForEventName[index] === anEventListener)
return eventListenersForEventName.splice(index, 1);
}
EventDispatcher.prototype.dispatchEvent = function(/*Event*/ anEvent)
{
var type = anEvent.type,
eventListenersForEventName = this._eventListenersForEventNames[type];
if (eventListenersForEventName)
{
var index = 0,
count = eventListenersForEventName.length;
for (; index < count; ++index)
eventListenersForEventName[index](anEvent);
}
var manual = (this._owner || this)["on" + type];
if (manual)
manual(anEvent);
}
+317
View File
@@ -0,0 +1,317 @@
/*
* Executable.js
* Objective-J
*
* Created by Francisco Tolmasky.
* Copyright 2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
var ExecutableUnloadedFileDependencies = 0,
ExecutableLoadingFileDependencies = 1,
ExecutableLoadedFileDependencies = 2;
function Executable(/*String*/ aCode, /*Array*/ fileDependencies, /*String*/ aScope, /*Function*/ aFunction)
{
if (arguments.length === 0)
return this;
this._code = aCode;
this._function = aFunction || NULL;
this._scope = aScope || "(Anonymous)";
this._fileDependencies = fileDependencies;
this._fileDependencyLoadStatus = ExecutableUnloadedFileDependencies;
this._eventDispatcher = new EventDispatcher(this);
if (this._function)
return;
this.setCode(aCode);
}
Executable.prototype.path = function()
{
return FILE.join(FILE.cwd(), "(Anonymous)");
}
Executable.prototype.functionParameters = function()
{
var functionParameters = ["global", "objj_executeFile", "objj_importFile"];
//exportedNames().concat("objj_executeFile", "objj_importFile");
#ifdef COMMONJS
functionParameters = functionParameters.concat("require", "exports", "module", "system", "print", "window");
#endif
return functionParameters;
}
Executable.prototype.functionArguments = function()
{
var dirname = FILE.dirname(this.path()),
functionArguments = [global, exports.fileExecuterForPath(dirname), fileImporterForPath(dirname)];
//functionArguments = exportedValues().concat(exports.fileExecuterForPath(path), fileImporterForPath(path));
#ifdef COMMONJS
functionArguments = functionArguments.concat(Executable.commonJSArguments());
#endif
return functionArguments;
}
#ifdef COMMONJS
Executable.setCommonJSParameters = function()
{
this._commonJSParameters = Array.prototype.slice.call(arguments);
}
Executable.commonJSParameters = function()
{
return this._commonJSParameters || [];
}
Executable.setCommonJSArguments = function()
{
this._commonJSArguments = Array.prototype.slice.call(arguments);
}
Executable.commonJSArguments = function()
{
return this._commonJSArguments || [];
}
Executable.prototype.toMarkedString = function()
{
var markedString = "@STATIC;1.0;",
dependencies = this.fileDependencies(),
index = 0,
count = dependencies.length;
for (; index < count; ++index)
markedString += dependencies[index].toMarkedString();
var code = this.code();
return markedString + MARKER_TEXT + ";" + code.length + ";" + code;
}
#endif
Executable.prototype.execute = function()
{
#if EXECUTION_LOGGING
CPLog("EXECUTION: " + this.path());
#endif
var oldContextBundle = CONTEXT_BUNDLE;
CONTEXT_BUNDLE = CFBundle.bundleContainingPath(this.path());
var result = this._function.apply(global, this.functionArguments());
CONTEXT_BUNDLE = oldContextBundle;
return result;
}
Executable.prototype.code = function()
{
return this._code;
}
Executable.prototype.setCode = function(code)
{
this._code = code;
var parameters = this.functionParameters().join(",");
#if COMMONJS
if (typeof system !== "undefined" && system.engine === "rhino")
{
code = "function(" + parameters + "){" + code + "/**/\n}";
this._function = Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(window, code, this._scope, 0, NULL);
}
else
{
#endif
// "//@ sourceURL=" at the end lets us name our eval'd files for debuggers, etc.
// * WebKit: http://pmuellr.blogspot.com/2009/06/debugger-friendly.html
// * Firebug: http://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/
//if (YES) {
code += "/**/\n//@ sourceURL=" + this._scope;
this._function = new Function(parameters, code);
//} else {
// // Firebug only does it for "eval()", not "new Function()". Ugh. Slower.
// var functionText = "(function(){"+GET_CODE(aFragment)+"/**/\n})\n//@ sourceURL="+GET_FILE(aFragment).path;
// compiled = eval(functionText);
//}
this._function.displayName = this._scope;
#if COMMONJS
}
#endif
}
Executable.prototype.fileDependencies = function()
{
return this._fileDependencies;
}
Executable.prototype.scope = function()
{
return this._scope;
}
Executable.prototype.hasLoadedFileDependencies = function()
{
return this._fileDependencyLoadStatus === ExecutableLoadedFileDependencies;
}
var globalIteration = 0;
Executable.prototype.loadFileDependencies = function()
{
#if DEPENDENCY_LOGGING
CPLog("DEPENDENCY: initiated by " + this.scope());
#endif
if (this._fileDependencyLoadStatus !== ExecutableUnloadedFileDependencies)
return;
this._fileDependencyLoadStatus = ExecutableLoadingFileDependencies;
var searchedPaths = [{ }, { }],
foundExecutablePaths = { },
fileExecutableSearches = new CFMutableDictionary(),
incompleteFileExecutableSearches = new CFMutableDictionary(),
executablesNeedingEventDispatch = [this];
function searchForFileDependencies(/*Executable*/ anExecutable)
{
if (anExecutable.hasLoadedFileDependencies())
return;
var executables = [anExecutable],
executableIndex = 0,
executableCount = executables.length;
for (; executableIndex < executableCount; ++executableIndex)
{
var executable = executables[executableIndex],
cwd = FILE.dirname(executable.path()),
fileDependencies = executable.fileDependencies(),
fileDependencyIndex = 0,
fileDependencyCount = fileDependencies.length;
for (; fileDependencyIndex < fileDependencyCount; ++fileDependencyIndex)
{
var fileDependency = fileDependencies[fileDependencyIndex],
isLocal = fileDependency.isLocal(),
path = importablePath(fileDependency.path(), isLocal, cwd);
if (searchedPaths[isLocal ? 1 : 0][path])
continue;
searchedPaths[isLocal ? 1 : 0][path] = YES;
var fileExecutableSearch = new FileExecutableSearch(path, isLocal),
fileExecutableSearchUID = fileExecutableSearch.UID();
if (fileExecutableSearches.containsKey(fileExecutableSearchUID))
continue;
fileExecutableSearches.setValueForKey(fileExecutableSearchUID, fileExecutableSearch);
if (fileExecutableSearch.isComplete())
{
var newFileExecutable = fileExecutableSearch.result();
foundExecutablePaths[newFileExecutable.path()] = executable;
executables.push(newFileExecutable);
++executableCount;
}
else
{
incompleteFileExecutableSearches.setValueForKey(fileExecutableSearchUID, fileExecutableSearch);
fileExecutableSearch.addEventListener("complete", function( anEvent)
{
var fileExecutableSearch = anEvent.fileExecutableSearch,
fileExecutable = fileExecutableSearch.result();
foundExecutablePaths[fileExecutable.path()] = fileExecutable;
incompleteFileExecutableSearches.removeValueForKey(fileExecutableSearch.UID());
searchForFileDependencies(fileExecutable);
});
}
}
}
if (incompleteFileExecutableSearches.count() > 0)
#if !DEPENDENCY_LOGGING
return;
#else
{
CPLog("DEPENDENCY: more dependencies: ");
CPLog(incompleteFileExecutableSearches.toString());
return;
}
CPLog("DEPENDENCY: Ended");
#endif
for (var executablePath in foundExecutablePaths)
if (hasOwnProperty.apply(foundExecutablePaths, [executablePath]))
{
var fileExecutable = new FileExecutable(executablePath);
//CPLog("no go for... " + fileExecutable.path());
if (fileExecutable.hasLoadedFileDependencies())
continue;
executablesNeedingEventDispatch.push(fileExecutable);
fileExecutable._fileDependencyLoadStatus = FileExecutableLoadedDependencies;
}
var index = 0,
count = executablesNeedingEventDispatch.length;
for (; index < count; ++index)
{
var fileExecutable = executablesNeedingEventDispatch[index];
fileExecutable._eventDispatcher.dispatchEvent(
{
type:"dependenciesload",
fileExecutable:fileExecutable
});
}
}
searchForFileDependencies(this);
}
Executable.prototype.addEventListener = function(/*String*/ anEventName, /*Function*/ aListener)
{
this._eventDispatcher.addEventListener(anEventName, aListener);
}
Executable.prototype.removeEventListener = function(/*String*/ anEventName, /*Function*/ aListener)
{
this._eventDispatcher.removeEventListener(anEventName, aListener);
}
exports.Executable = Executable;
@@ -1,9 +1,9 @@
/*
* bootstrap.js
* FileDependency.js
* Objective-J
*
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
* Copyright 2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,29 +20,31 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
if (window.OBJJ_MAIN_FILE)
function FileDependency(/*String*/ aPath, /*BOOL*/ isLocal)
{
var addOnload = function(handler)
{
if (window.addEventListener)
window.addEventListener("load", handler, false);
else if (window.attachEvent)
window.attachEvent("onload", handler);
}
var documentLoaded = NO;
var defaultHandler = function()
{
documentLoaded = YES;
}
addOnload(defaultHandler);
objj_import(OBJJ_MAIN_FILE, YES, function()
{
if (documentLoaded)
main();
else
addOnload(main);
});
this._path = FILE.normal(aPath);
this._isLocal = isLocal;
}
FileDependency.prototype.path = function()
{
return this._path;
}
FileDependency.prototype.isLocal = function()
{
return this._isLocal;
}
FileDependency.prototype.toMarkedString = function()
{
return (this.isLocal() ? MARKER_IMPORT_LOCAL : MARKER_IMPORT_STD) + ";" +
this.path().length + ";" + this.path();
}
FileDependency.prototype.toString = function()
{
return (this.isLocal() ? "LOCAL: " : "STD: ") + this.path();
}
exports.FileDependency = FileDependency;
+111
View File
@@ -0,0 +1,111 @@
/*
* FileExecutable.js
* Objective-J
*
* Created by Francisco Tolmasky.
* Copyright 2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
var FileExecutableUnloadedDependencies = 0,
FileExecutableLoadingDependencies = 1,
FileExecutableLoadedDependencies = 2,
FileExecutablesForPaths = { };
function FileExecutable(/*String*/ aPath)
{
var existingFileExecutable = FileExecutablesForPaths[aPath];
if (existingFileExecutable)
return existingFileExecutable;
FileExecutablesForPaths[aPath] = this;
var fileContents = rootResource.nodeAtSubPath(aPath).contents(),
executable = NULL,
extension = FILE.extension(aPath);
if (fileContents.match(/^@STATIC;/))
executable = decompile(fileContents, aPath);
else if (extension === ".j" || extension === "")
executable = preprocess(fileContents, aPath, OBJJ_PREPROCESSOR_DEBUG_SYMBOLS);
else
executable = new Executable(fileContents, [], aPath);
Executable.apply(this, [executable.code(), executable.fileDependencies(), aPath, executable._function]);
this._path = aPath;
this._hasExecuted = NO;
}
FileExecutable.prototype = new Executable();
FileExecutable.prototype.execute = function(/*BOOL*/ shouldForce)
{
if (this._hasExecuted && !shouldForce)
return;
this._hasExecuted = YES;
Executable.prototype.execute.apply(this, []);
}
FileExecutable.prototype.path = function()
{
return this._path;
}
FileExecutable.prototype.hasExecuted = function()
{
return this._hasExecuted;
}
function decompile(/*String*/ aString, /*String*/ aPath)
{
var stream = new MarkedStream(aString);
/*
if (stream.version !== "1.0")
return;
*/
var marker = NULL,
code = "",
dependencies = [];
while (marker = stream.getMarker())
{
var text = stream.getString();
if (marker === MARKER_TEXT)
code += text;
else if (marker === MARKER_IMPORT_STD)
dependencies.push(new FileDependency(FILE.normal(text), NO));
else if (marker === MARKER_IMPORT_LOCAL)
dependencies.push(new FileDependency(FILE.normal(text), YES));
}
return new Executable(code, dependencies, aPath);
}
/*
global.objj_executeFile = executeFile;
global.objj_importFile = importFile;
global.objj_import = importFile;
*/
exports.FileExecutable = FileExecutable;
exports.FileExecutablesForPaths = FileExecutablesForPaths;
+109
View File
@@ -0,0 +1,109 @@
/*
* FileExecutableSearch.js
* Objective-J
*
* Created by Francisco Tolmasky.
* Copyright 2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
var FileExecutableSearchesForPaths = [{ }, { }];
function FileExecutableSearch(/*String*/ aPath, /*BOOL*/ isLocal)
{
if (!FILE.isAbsolute(aPath) && isLocal)
throw "Local searches cannot be relative: " + aPath;
var existingSearch = FileExecutableSearchesForPaths[isLocal ? 1 : 0][aPath];
if (existingSearch)
return existingSearch;
FileExecutableSearchesForPaths[isLocal ? 1 : 0][aPath] = this;
this._UID = generateObjectUID();
this._isComplete = NO;
this._eventDispatcher = new EventDispatcher(this);
this._path = aPath;
this._result = NULL;
var self = this;
function completed(/*String*/ aStaticResource)
{
if (!aStaticResource)
throw new Error("Could not load file at " + aPath);
self._result = new FileExecutable(aStaticResource.path());
self._isComplete = YES;
self._eventDispatcher.dispatchEvent(
{
type:"complete",
fileExecutableSearch:self
});
}
if (isLocal)
rootResource.resolveSubPath(aPath, StaticResource.FileType, completed);
else
StaticResource.resolveStandardNodeAtPath(aPath, completed);
}
FileExecutableSearch.prototype.path = function()
{
return this._path;
}
FileExecutableSearch.prototype.result = function()
{
return this._result;
}
FileExecutableSearch.prototype.UID = function()
{
return this._UID;
}
FileExecutableSearch.prototype.isComplete = function()
{
return this._isComplete;
}
FileExecutableSearch.prototype.result = function()
{
return this._result;
}
FileExecutableSearch.prototype.addEventListener = function(/*String*/ anEventName, /*Function*/ aListener)
{
this._eventDispatcher.addEventListener(anEventName, aListener);
}
FileExecutableSearch.prototype.removeEventListener = function(/*String*/ anEventName, /*Function*/ aListener)
{
this._eventDispatcher.removeEventListener(anEventName, aListener);
}
#if DEPENDENCY_LOGGING
FileExecutableSearch.prototype.toString = function()
{
return "<FileExecutableSearch: " + this.path() + ">";
}
#endif
exports.FileExecutableSearch = FileExecutableSearch;
+274
View File
@@ -0,0 +1,274 @@
var asynchronousTimeoutCount = 0,
asynchronousTimeoutId = null,
asynchronousFunctionQueue = [];
function Asynchronous(/*Function*/ aFunction)
{
currentAsynchronousTimeoutCount = asynchronousTimeoutCount;
if (asynchronousTimeoutId === null)
{
window.setNativeTimeout(function()
{
var queue = asynchronousFunctionQueue,
index = 0,
count = asynchronousFunctionQueue.length;
++asynchronousTimeoutCount;
asynchronousTimeoutId = null;
asynchronousFunctionQueue = [];
for (; index < count; ++index)
queue[index]();
}, 0);
}
return function()
{
var args = arguments;
if (asynchronousTimeoutCount > currentAsynchronousTimeoutCount)
aFunction.apply(this, args);
else
asynchronousFunctionQueue.push(function() { aFunction.apply(this, args) });
};
}
var NativeRequest = null;
// We check ActiveXObject first, because we require local file access and
// overrideMimeType feature (which the native XMLHttpRequest does not have in IE).
if (window.ActiveXObject !== undefined)
{
// DON'T try 4.0 and 5.0: http://bit.ly/microsoft-msxml-explanation
var MSXML_XMLHTTP_OBJECTS = ["Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP.6.0"],
index = MSXML_XMLHTTP_OBJECTS.length;
while (index--)
{
try
{
var MSXML_XMLHTTP = MSXML_XMLHTTP_OBJECTS[index];
new ActiveXObject(MSXML_XMLHTTP);
NativeRequest = function()
{
return new ActiveXObject(MSXML_XMLHTTP);
}
break;
}
catch (anException)
{
}
}
}
if (!NativeRequest)
NativeRequest = window.XMLHttpRequest;
function HTTPRequest()
{
this._eventDispatcher = new EventDispatcher(this);
this._nativeRequest = new NativeRequest();
var self = this;
this._nativeRequest.onreadystatechange = function()
{
determineAndDispatchHTTPRequestEvents(self);
}
}
HTTPRequest.UninitializedState = 0;
HTTPRequest.LoadingState = 1;
HTTPRequest.LoadedState = 2;
HTTPRequest.InteractiveState = 3;
HTTPRequest.CompleteState = 4;
HTTPRequest.prototype.status = function()
{
try
{
return this._nativeRequest.status || 0;
}
catch (anException)
{
return 0;
}
}
HTTPRequest.prototype.statusText = function()
{
try
{
return this._nativeRequest.statusText || "";
}
catch (anException)
{
return "";
}
}
HTTPRequest.prototype.readyState = function()
{
return this._nativeRequest.readyState;
}
HTTPRequest.prototype.success = function()
{
var status = this.status();
if (status >= 200 && status < 300)
return YES;
// file:// requests return with status 0, to know if they succeeded, we
// need to know if there was any content.
return status === 0 && this.responseText() && this.responseText().length;
}
HTTPRequest.prototype.responseXML = function()
{
var responseXML = this._nativeRequest.responseXML;
if (responseXML && (NativeRequest === XMLHttpRequest))
return responseXML;
return parseXML(this.responseText());
}
HTTPRequest.prototype.responsePropertyList = function()
{
var responseText = this.responseText();
if (CFPropertyList.sniffedFormatOfString(responseText) === CFPropertyList.FormatXML_v1_0)
return CFPropertyList.propertyListFromXML(this.responseXML());
return CFPropertyList.propertyListFromString(responseText);
}
HTTPRequest.prototype.responseText = function()
{
return this._nativeRequest.responseText;
}
HTTPRequest.prototype.setRequestHeader = function(/*String*/ aHeader, /*Object*/ aValue)
{
return this._nativeRequest.setRequestHeader(aHeader, aValue);
}
HTTPRequest.prototype.getResponseHeader = function(/*String*/ aHeader)
{
return this._nativeRequest.getResponseHeader(aHeader);
}
HTTPRequest.prototype.getAllResponseHeaders = function()
{
return this._nativeRequest.getAllResponseHeaders();
}
HTTPRequest.prototype.overrideMimeType = function(/*String*/ aMimeType)
{
if ("overrideMimeType" in this._nativeRequest)
return this._nativeRequest.overrideMimeType(aMimeType);
}
HTTPRequest.prototype.open = function(/*...*/)
{
return this._nativeRequest.open(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
}
HTTPRequest.prototype.send = function(/*Object*/ aBody)
{
try
{
return this._nativeRequest.send(aBody);
}
catch (anException)
{
// FIXME: Do something more complex, with 404's?
this._eventDispatcher.dispatchEvent({ type:"failure", request:this });
}
}
HTTPRequest.prototype.abort = function()
{
return this._nativeRequest.abort();
}
HTTPRequest.prototype.addEventListener = function(/*String*/ anEventName, /*Function*/ anEventListener)
{
this._eventDispatcher.addEventListener(anEventName, anEventListener);
}
HTTPRequest.prototype.removeEventListener = function(/*String*/ anEventName, /*Function*/ anEventListener)
{
this._eventDispatcher.removeEventListener(anEventName, anEventListener);
}
function determineAndDispatchHTTPRequestEvents(/*HTTPRequest*/ aRequest)
{
var eventDispatcher = aRequest._eventDispatcher;
eventDispatcher.dispatchEvent({ type:"readystatechange", request:aRequest});
var nativeRequest = aRequest._nativeRequest,
readyState = ["uninitialized", "loading", "loaded", "interactive", "complete"][aRequest.readyState()];
eventDispatcher.dispatchEvent({ type:readyState, request:aRequest});
if (readyState === "complete")
{
var status = "HTTP" + aRequest.status();
eventDispatcher.dispatchEvent({ type:status, request:aRequest });
var result = aRequest.success() ? "success" : "failure";
eventDispatcher.dispatchEvent({ type:result, request:aRequest });
}
}
function FileRequest(/*String*/ aFilePath, onsuccess, onfailure)
{
#ifdef BROWSER
var request = new HTTPRequest();
request.onsuccess = Asynchronous(onsuccess);
request.onfailure = Asynchronous(onfailure);
if (FILE.extension(aFilePath) === ".plist")
request.overrideMimeType("text/xml");
request.open("GET", aFilePath, YES);
request.send("");
#else
if (!FILE.exists(aFilePath))
return onfailure();
this._responseText = FILE.read(aFilePath, { charset:"UTF-8" });
onsuccess({ type:"success", request:this });
#endif
}
#ifdef COMMONJS
FileRequest.prototype.responseText = function()
{
return this._responseText;
}
FileRequest.prototype.responseXML = function()
{
return new DOMParser().parseFromString(anXMLString, "text/xml");
}
FileRequest.prototype.responsePropertyList = function()
{
return CFPropertyList.propertyListFromString(this.responseText());
}
#endif
exports.HTTPRequest = HTTPRequest;
+23
View File
@@ -0,0 +1,23 @@
#include "DebugOptions.js"
#include "json2.js"
#include "sprintf.js"
#include "CPLog.js"
#include "Constants.js"
#include "EventDispatcher.js"
#include "HTTPRequest.js"
#include "CFPropertyList.js"
#include "CFDictionary.js"
#include "CFData.js"
#include "MarkedStream.js"
#include "CFBundle.js"
#include "StaticResource.js"
#include "Preprocessor.js"
#include "FileDependency.js"
#include "Executable.js"
#include "FileExecutable.js"
#include "FileExecutableSearch.js"
#include "Scope.js"
#include "Runtime.js"
#include "Debug.js"
#include "Bootstrap.js"
+51 -71
View File
@@ -21,44 +21,26 @@
*/
var FILE = require("file"),
OS = require("os");
OS = require("os"),
stream = require("term").stream;
require("../common.jake");
//$BUILD_CONFIGURATION_DIR = "../Build"
$BROWSER_FILE = FILE.join("Browser", "Objective-J.js");
$BUILD_OBJECTIVE_J = FILE.join($BUILD_CONFIGURATION_DIR, "Objective-J");
var OBJECTIVE_J_FILES = new FileList(
"Runtime/constants.js",
"Runtime/utilities.js",
"Runtime/json2.js",
"Runtime/runtime.js",
"Runtime/dictionary.js",
"Runtime/plist.js",
"Runtime/file.js",
"Runtime/exception.js",
"Runtime/preprocess.js",
"Runtime/evaluate.js",
"Runtime/bootstrap.js"
);
if ($CONFIGURATION === "Debug")
OBJECTIVE_J_FILES.include("Runtime/debug.js");
$BUILD_BROWSER_FILE = FILE.join($BUILD_OBJECTIVE_J, "Objective-J.js");
$BUILD_CJS_FILE = FILE.join($BUILD_OBJECTIVE_J, "CommonJS.environment", "Objective-J.js");
filedir($BUILD_BROWSER_FILE, OBJECTIVE_J_FILES, function(aTask)
$INCLUDE_FLAGS = " -I" + FILE.cwd();
$OBJECTIVEJ_FILES = new FileList("*.js");
$BROWSER_FILES = new FileList($BROWSER_FILE).include($OBJECTIVEJ_FILES);
filedir($BUILD_BROWSER_FILE, $BROWSER_FILES, function(aTask)
{
build_product(aTask.name(), environmentFlags("ObjJ") + " -DPLATFORM_USERAGENT");
});
filedir($BUILD_CJS_FILE, OBJECTIVE_J_FILES, function(aTask)
{
flags = environmentFlags("CommonJS", "ObjJ");
flags += ' -DRHINO'
build_product(aTask.name(), flags)
gcc($BROWSER_FILE,
$BUILD_BROWSER_FILE,
environmentFlags("Browser", "ObjJ") + $INCLUDE_FLAGS, $CONFIGURATION !== "Debug");
});
$LICENSE = FILE.join("CommonJS", "lib", "objective-j", "jake", "LICENSES", "LGPL-v2.1");
@@ -71,16 +53,25 @@ filedir($BUILD_LICENSE, [$LICENSE], function()
new FileList("CommonJS/**/*").forEach(function(aFilename)
{
if (!FILE.isFile(aFilename))
// . files should be left out of FileList...
if (!FILE.isFile(aFilename) || FILE.basename(aFilename).charAt(0) === ".")
return;
var buildFilename = FILE.join($BUILD_CJS_OBJECTIVE_J, FILE.relative("CommonJS/", aFilename));
filedir (buildFilename, [aFilename], function ()
filedir (buildFilename, new FileList(aFilename).include($OBJECTIVEJ_FILES), function ()
{
cp(aFilename, buildFilename);
if (FILE.extension(aFilename) !== ".js")
{
stream.print("Copying... \0green(" + aFilename +"\0)");
cp(aFilename, buildFilename);
}
else
gcc(aFilename,
buildFilename,
environmentFlags("CommonJS", "ObjJ") + $INCLUDE_FLAGS, false);
});
if (FILE.dirname(aFilename) === FILE.join("CommonJS", "bin"))
{
filedir (buildFilename, function ()
@@ -104,45 +95,34 @@ CLOBBER.include($BUILD_OBJECTIVE_J);
function environmentFlags()
{
return "-DENVIRONMENTS=\"[" + Array.prototype.map.apply(arguments, [function(anEnvironment) {
return Array.prototype.map.apply(arguments, [function(anEnvironment)
{
return "-D" + anEnvironment.toUpperCase();
}]).join(" ") +
" -DENVIRONMENTS=\"[" + Array.prototype.map.apply(arguments, [function(anEnvironment) {
return "\\\"" + anEnvironment + "\\\"";
}]).join(", ") + "]\"";
}
function build_product(path, flags)
{
var sources = OBJECTIVE_J_FILES.filter(function(aName) { return !!aName.match(/\.js$/); });
var productOut = FILE.open(path, "w", { charset : "UTF-8" });
FILE.open("Runtime/header.txt", "r", { charset : "UTF-8" })
.copy(productOut)
.close();
var preprocessor = OS.popen("gcc " + flags + " -E -x c -P -");
sources.forEach(function(source) {
FILE.open(source, "r", { charset : "UTF-8" })
.copy(preprocessor.stdin)
.close();
});
preprocessor.stdin.close();
preprocessor.stdout.copy(productOut);
productOut.close();
var code = preprocessor.wait();
// this is equivalent to the above, but less cross platform:
//OS.system(["cp", "Runtime/header.txt", path]);
//var code = OS.system("cat " + sources.map(OS.enquote).join(' ') + " | gcc " + flags + " -E -x c -P - >> " + OS.enquote(path));
if (code !== 0) {
FILE.remove(path);
OS.exit(1);
}
// rake abort if ($? != 0)
var SHRINKSAFE = require("minify/shrinksafe");
function compressor(code) {
return SHRINKSAFE.compress(code, { charset : "UTF-16", useServer : true });
}
task("build", [$BUILD_BROWSER_FILE, $BUILD_CJS_FILE, $BUILD_LICENSE, $BUILD_CJS_OBJECTIVE_J_FRAMEWORK]);
function gcc(inputFilePath, outputFilePath, flags, compress)
{
stream.print("Building... \0green(" + outputFilePath +"\0)");
// GCC preprocess the file.
var gcc = OS.popen("gcc -E -x c -P " + flags + " " + inputFilePath, { charset:"UTF-8" });
var contents = FILE.read("header.txt", { charset : "UTF-8" });
contents += gcc.stdout.read();
if (FILE.extension(inputFilePath) === ".js" && compress)
contents = compressor(contents);
FILE.write(outputFilePath, contents, { charset : "UTF-8" });
}
task("build", [$BUILD_BROWSER_FILE, $BUILD_LICENSE, $BUILD_CJS_OBJECTIVE_J_FRAMEWORK]);
+71
View File
@@ -0,0 +1,71 @@
function MarkedStream(/*String*/ aString)
{
this._string = aString;
var index = aString.indexOf(";");
// Grab the magic number.
this._magicNumber = aString.substr(0, index);
this._location = aString.indexOf(";", ++index);
// Grab the version number.
this._version = aString.substring(index, this._location++);
}
MarkedStream.prototype.magicNumber = function()
{
return this._magicNumber;
}
MarkedStream.prototype.version = function()
{
return this._version;
}
MarkedStream.prototype.getMarker = function()
{
var string = this._string,
location = this._location;
if (location >= string.length)
return null;
var next = string.indexOf(';', location);
if (next < 0)
return null;
var marker = string.substring(location, next);
if (marker === 'e')
return null;
this._location = next + 1;
return marker;
}
MarkedStream.prototype.getString = function()
{
var string = this._string,
location = this._location;
if (location >= string.length)
return null;
var next = string.indexOf(';', location);
if (next < 0)
return null;
var size = parseInt(string.substring(location, next)),
text = string.substr(next + 1, size);
this._location = next + 1 + size;
return text;
}
exports.MarkedStream = MarkedStream;
@@ -1,5 +1,5 @@
/*
* preprocessor.js
* Preprocessor.js
* Objective-J
*
* Created by Francisco Tolmasky.
@@ -23,33 +23,19 @@
var OBJJ_PREPROCESSOR_DEBUG_SYMBOLS = 1 << 0,
OBJJ_PREPROCESSOR_TYPE_SIGNATURES = 1 << 1;
function objj_preprocess(/*String*/ aString, /*objj_bundle*/ aBundle, /*objj_file*/ aSourceFile, /*unsigned*/ flags)
{
try
{
return new objj_preprocessor(aString.replace(/^#[^\n]+\n/, "\n"), aSourceFile, aBundle, flags).fragments();
}
catch (anException)
{
objj_exception_report(anException, aSourceFile);
}
return [];
}
var OBJJParseException = "OBJJParseException",
OBJJClassNotFoundException = "OBJJClassNotFoundException";
var TOKEN_ACCESSORS = "accessors",
TOKEN_CLASS = "class",
TOKEN_END = "end",
TOKEN_FUNCTION = "function",
TOKEN_IMPLEMENTATION = "implementation",
TOKEN_IMPORT = "import",
TOKEN_EACH = "each",
TOKEN_NEW = "new",
TOKEN_SELECTOR = "selector",
TOKEN_SUPER = "super",
TOKEN_VAR = "var",
TOKEN_IN = "in",
TOKEN_EQUAL = '=',
TOKEN_PLUS = '+',
TOKEN_MINUS = '-',
@@ -69,22 +55,15 @@ var TOKEN_ACCESSORS = "accessors",
TOKEN_QUESTION_MARK = '?',
TOKEN_OPEN_PARENTHESIS = '(',
TOKEN_CLOSE_PARENTHESIS = ')',
TOKEN_WHITESPACE = /^(?:(?:\s+$)|(?:\/(?:\/|\*)))/,
TOKEN_NUMBER = /^[+-]?\d+(([.]\d+)*([eE][+-]?\d+))?$/,
TOKEN_IDENTIFIER = /^[a-zA-Z_$](\w|$)*$/;
#define IS_WORD(token) /^\w+$/.test(token)
#define IS_NOT_EMPTY(buffer) buffer.atoms.length !== 0
#define CONCAT(buffer, atom) buffer.atoms[buffer.atoms.length] = atom
var SUPER_CLASSES = new objj_dictionary();
var OBJJ_CURRENT_BUNDLE = NULL;
// FIXME: Used fixed regex
var objj_lexer = function(aString)
function Lexer(/*String*/ aString)
{
this._index = -1;
this._tokens = (aString + '\n').match(/\/\/.*(\r|\n)?|\/\*(?:.|\n|\r)*?\*\/|\w+\b|[+-]?\d+(([.]\d+)*([eE][+-]?\d+))?|"[^"\\]*(\\[\s\S][^"\\]*)*"|'[^'\\]*(\\[\s\S][^'\\]*)*'|\s+|./g);
@@ -93,17 +72,17 @@ var objj_lexer = function(aString)
return this;
}
objj_lexer.prototype.push = function()
Lexer.prototype.push = function()
{
this._context.push(this._index);
}
objj_lexer.prototype.pop = function()
Lexer.prototype.pop = function()
{
this._index = this._context.pop();
}
objj_lexer.prototype.peak = function(shouldSkipWhitespace)
Lexer.prototype.peak = function(shouldSkipWhitespace)
{
if (shouldSkipWhitespace)
{
@@ -117,17 +96,17 @@ objj_lexer.prototype.peak = function(shouldSkipWhitespace)
return this._tokens[this._index + 1];
}
objj_lexer.prototype.next = function()
Lexer.prototype.next = function()
{
return this._tokens[++this._index];
}
objj_lexer.prototype.previous = function()
Lexer.prototype.previous = function()
{
return this._tokens[--this._index];
}
objj_lexer.prototype.last = function()
Lexer.prototype.last = function()
{
if (this._index < 0)
return NULL;
@@ -135,7 +114,7 @@ objj_lexer.prototype.last = function()
return this._tokens[this._index - 1];
}
objj_lexer.prototype.skip_whitespace= function(shouldMoveBackwards)
Lexer.prototype.skip_whitespace= function(shouldMoveBackwards)
{
var token;
@@ -147,52 +126,57 @@ objj_lexer.prototype.skip_whitespace= function(shouldMoveBackwards)
return token;
}
var objj_stringBuffer = function()
#define IS_NOT_EMPTY(buffer) buffer.atoms.length !== 0
#define CONCAT(buffer, atom) buffer.atoms[buffer.atoms.length] = atom
function StringBuffer()
{
this.atoms = [];
}
objj_stringBuffer.prototype.toString = function()
StringBuffer.prototype.toString = function()
{
return this.atoms.join("");
}
objj_stringBuffer.prototype.clear = function()
function preprocess(/*String*/ aString, /*String*/ aPath, /*unsigned*/ flags)
{
this.atoms = [];
return new Preprocessor(aString, aPath, flags).executable();
}
objj_stringBuffer.prototype.isEmpty = function()
function Preprocessor(/*String*/ aString, /*String*/ aPath, /*unsigned*/ flags)
{
return (this.atoms.length === 0);
}
// Remove the shebang.
aString = aString.replace(/^#[^\n]+\n/, "\n");
var objj_preprocessor = function(aString, aSourceFile, aBundle, flags)
{
this._currentSelector = "";
this._currentClass = "";
this._currentSuperClass = "";
this._currentSuperMetaClass = "";
this._file = aSourceFile;
this._fragments = [];
this._preprocessed = new objj_stringBuffer();
this._tokens = new objj_lexer(aString);
this._filePath = aPath;
this._buffer = new StringBuffer();
this._preprocessed = NULL;
this._dependencies = [];
this._tokens = new Lexer(aString);
this._flags = flags;
this._bundle = aBundle;
this._classMethod = false;
this.preprocess(this._tokens, this._preprocessed);
//alert(this._preprocessed + "");
this.fragment();
this._executable = NULL;
this.preprocess(this._tokens, this._buffer);
}
objj_preprocessor.prototype.fragments = function()
Preprocessor.prototype.executable = function()
{
return this._fragments;
if (!this._executable)
this._executable = new Executable(this._buffer.toString(), this._dependencies);
return this._executable;
}
objj_preprocessor.prototype.accessors = function(tokens)
Preprocessor.prototype.accessors = function(tokens)
{
var token = tokens.skip_whitespace(),
attributes = {};
@@ -210,19 +194,19 @@ objj_preprocessor.prototype.accessors = function(tokens)
value = true;
if (!IS_WORD(name))
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** @property attribute name not valid.")));
throw new SyntaxError(this.error_message("*** @property attribute name not valid."));
if ((token = tokens.skip_whitespace()) == TOKEN_EQUAL)
{
value = tokens.skip_whitespace();
if (!IS_WORD(value))
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** @property attribute value not valid.")));
throw new SyntaxError(this.error_message("*** @property attribute value not valid."));
if (name == "setter")
{
if ((token = tokens.next()) != TOKEN_COLON)
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** @property setter attribute requires argument with \":\" at end of selector name.")));
throw new SyntaxError(this.error_message("*** @property setter attribute requires argument with \":\" at end of selector name."));
value += ":";
}
@@ -236,13 +220,13 @@ objj_preprocessor.prototype.accessors = function(tokens)
break;
if (token != TOKEN_COMMA)
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected ',' or ')' in @property attribute list.")));
throw new SyntaxError(this.error_message("*** Expected ',' or ')' in @property attribute list."));
}
return attributes;
}
objj_preprocessor.prototype.brackets = function(/*objj_lexer*/ tokens, /*objj_stringBuffer*/ aStringBuffer)
Preprocessor.prototype.brackets = function(/*Lexer*/ tokens, /*StringBuffer*/ aStringBuffer)
{
var tuples = [];
@@ -252,7 +236,7 @@ objj_preprocessor.prototype.brackets = function(/*objj_lexer*/ tokens, /*objj_st
{
CONCAT(aStringBuffer, '[');
// When we have an empty array literal ([]), tuples[0][0] will be an empty objj_stringBuffer
// When we have an empty array literal ([]), tuples[0][0] will be an empty StringBuffer
CONCAT(aStringBuffer, tuples[0][0]);
CONCAT(aStringBuffer, ']');
@@ -260,7 +244,7 @@ objj_preprocessor.prototype.brackets = function(/*objj_lexer*/ tokens, /*objj_st
else
{
var selector = new objj_stringBuffer();
var selector = new StringBuffer();
//alert(tuples[0][0].toString() + "]" );
// The first two arguments are always the receiver and the selector.
if (tuples[0][0].atoms[0] == TOKEN_SUPER)
@@ -273,12 +257,12 @@ objj_preprocessor.prototype.brackets = function(/*objj_lexer*/ tokens, /*objj_st
CONCAT(aStringBuffer, "objj_msgSend(");
CONCAT(aStringBuffer, tuples[0][0]);
}
CONCAT(selector, tuples[0][1]);
var index = 1,
count = tuples.length,
marg_list = new objj_stringBuffer();
marg_list = new StringBuffer();
for(; index < count; ++index)
{
@@ -296,10 +280,10 @@ objj_preprocessor.prototype.brackets = function(/*objj_lexer*/ tokens, /*objj_st
}
}
objj_preprocessor.prototype.directive = function(tokens, aStringBuffer, allowedDirectivesFlags)
Preprocessor.prototype.directive = function(tokens, aStringBuffer, allowedDirectivesFlags)
{
// Grab the next token, preprocessor directives follow '@' immediately.
var buffer = aStringBuffer ? aStringBuffer : new objj_stringBuffer(),
var buffer = aStringBuffer ? aStringBuffer : new StringBuffer(),
token = tokens.next();
// To provide compatibility with Objective-C files, we convert NSString literals into
@@ -309,7 +293,7 @@ objj_preprocessor.prototype.directive = function(tokens, aStringBuffer, allowedD
// Currently we simply swallow forward declarations and only provide them to allow
// compatibility with Objective-C files.
else if (token == TOKEN_CLASS)
else if (token === TOKEN_CLASS)
{
tokens.skip_whitespace();
@@ -317,36 +301,118 @@ objj_preprocessor.prototype.directive = function(tokens, aStringBuffer, allowedD
}
// @implementation Class implementations
else if (token == TOKEN_IMPLEMENTATION)
else if (token === TOKEN_IMPLEMENTATION)
this.implementation(tokens, buffer);
// @import
else if (token == TOKEN_IMPORT)
else if (token === TOKEN_IMPORT)
this._import(tokens);
else if (token === TOKEN_EACH)
this.each(tokens, buffer);
// @selector
else if (token == TOKEN_SELECTOR)
else if (token === TOKEN_SELECTOR)
this.selector(tokens, buffer);
else if (token == TOKEN_ACCESSORS)
return this.accessors(tokens);
if (!aStringBuffer)
return buffer;
}
objj_preprocessor.prototype.fragment = function()
var fastEnumeratorCount = 0;
Preprocessor.prototype.each = function(tokens, /*StringBuffer*/ aStringBuffer)
{
var preprocessed = this._preprocessed.toString();
// But make sure it's not just all whitespace!
if ((/[^\s]/).test(preprocessed))
this._fragments.push(fragment_create_code(preprocessed, this._bundle, this._file));
this._preprocessed.clear();
var token = tokens.skip_whitespace();
// If we reach an open parenthesis, we are declaring a category.
if (token !== TOKEN_OPEN_PARENTHESIS)
throw new SyntaxError(this.error_message("*** Expecting (, found: \"" + token + "\"."));
var identifiers = [],
isVared = NO;
do
{
token = tokens.skip_whitespace();
if (identifiers.length === 0 && token === TOKEN_VAR)
{
isVared = YES;
token = tokens.skip_whitespace();
}
if (!TOKEN_IDENTIFIER.test(token))
throw new SyntaxError(this.error_message("*** Expecting identifier, found: \"" + token + "\"."));
identifiers.push(token);
token = tokens.skip_whitespace();
if (token !== TOKEN_COMMA && token !== TOKEN_IN)
throw new SyntaxError(this.error_message("*** Expecting \",\", found: \"" + token + "\"."));
} while (token && token === TOKEN_COMMA);
if (token !== TOKEN_IN)
throw new SyntaxError(this.error_message("*** Expecting \"in\", found: \"" + token + "\"."));
var generatedFastEnumeratorName = "$OBJJ_GENERATED_FAST_ENUMERATOR_" + fastEnumeratorCount++;
CONCAT(aStringBuffer, "var ");
CONCAT(aStringBuffer, generatedFastEnumeratorName);
CONCAT(aStringBuffer, " = new objj_fastEnumerator(");
this.preprocess(tokens, aStringBuffer, TOKEN_CLOSE_PARENTHESIS, TOKEN_OPEN_PARENTHESIS);
CONCAT(aStringBuffer, ", ");
CONCAT(aStringBuffer, identifiers.length);
CONCAT(aStringBuffer, ");\n");
// var $E = new objj_fastEnumerator(expression);
// for ([[var] arg1[, arg2[, ... argN]]];
// $E.i < $E.l || $E.e() && ((arg1 = $E.o0[$E.i][, $E.o1[$E.i][, ... $E.oN[$E.i]]]) || YES);
// ++$E.i)
CONCAT(aStringBuffer, "for (");
if (isVared)
{
CONCAT(aStringBuffer, "var ");
CONCAT(aStringBuffer, identifiers.join(", "));
}
CONCAT(aStringBuffer, ";(");
CONCAT(aStringBuffer, generatedFastEnumeratorName);
CONCAT(aStringBuffer, ".i < ");
CONCAT(aStringBuffer, generatedFastEnumeratorName);
CONCAT(aStringBuffer, ".l || ");
CONCAT(aStringBuffer, generatedFastEnumeratorName);
CONCAT(aStringBuffer, ".e()) && ((");
// Man don't you wish we had fast enumeration here!!
for (var index = 0, count = identifiers.length; index < count; ++index)
{
CONCAT(aStringBuffer, identifiers[index]);
CONCAT(aStringBuffer, " = ");
CONCAT(aStringBuffer, generatedFastEnumeratorName);
CONCAT(aStringBuffer, ".o");
CONCAT(aStringBuffer, index);
CONCAT(aStringBuffer, "[");
CONCAT(aStringBuffer, generatedFastEnumeratorName);
CONCAT(aStringBuffer, ".i]");
if (index + 1 < count)
CONCAT(aStringBuffer, ", ");
}
CONCAT(aStringBuffer, ") || YES); ++");
CONCAT(aStringBuffer, generatedFastEnumeratorName);
CONCAT(aStringBuffer, ".i)");
}
objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffer*/ aStringBuffer)
Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStringBuffer)
{
var buffer = aStringBuffer,
token = "",
@@ -354,14 +420,15 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
class_name = tokens.skip_whitespace(),
superclass_name = "Nil",
instance_methods = new objj_stringBuffer(),
class_methods = new objj_stringBuffer();
instance_methods = new StringBuffer(),
class_methods = new StringBuffer();
if (!(/^\w/).test(class_name))
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected class name, found \"" + class_name + "\".")));
this._currentSuperClass = NULL;
this._currentSuperMetaClass = NULL;
throw new Error(this.error_message("*** Expected class name, found \"" + class_name + "\"."));
this._currentSuperClass = "objj_getClass(\"" + class_name + "\").super_class";
this._currentSuperMetaClass = "objj_getMetaClass(\"" + class_name + "\").super_class";
this._currentClass = class_name;
this._currentSelector = "";
@@ -371,28 +438,14 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
token = tokens.skip_whitespace();
if (token == TOKEN_CLOSE_PARENTHESIS)
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Can't Have Empty Category Name for class \"" + class_name + "\".")));
throw new SyntaxError(this.error_message("*** Can't Have Empty Category Name for class \"" + class_name + "\"."));
if (tokens.skip_whitespace() != TOKEN_CLOSE_PARENTHESIS)
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Improper Category Definition for class \"" + class_name + "\".")));
throw new SyntaxError(this.error_message("*** Improper Category Definition for class \"" + class_name + "\"."));
CONCAT(buffer, "{\nvar the_class = objj_getClass(\"" + class_name + "\")\n");
CONCAT(buffer, "if(!the_class) objj_exception_throw(new objj_exception(OBJJClassNotFoundException, \"*** Could not find definition for class \\\"" + class_name + "\\\"\"));\n");
CONCAT(buffer, "if(!the_class) throw new SyntaxError(\"*** Could not find definition for class \\\"" + class_name + "\\\"\");\n");
CONCAT(buffer, "var meta_class = the_class.isa;");
var superclass_name = dictionary_getValue(SUPER_CLASSES, class_name);
// FIXME: We should have a better solution for this case, although it's actually not much slower than the real case.
if (!superclass_name)
{
this._currentSuperClass = "objj_getClass(\"" + class_name + "\").super_class";
this._currentSuperMetaClass = "objj_getMetaClass(\"" + class_name + "\").super_class";
}
else
{
this._currentSuperClass = "objj_getClass(\"" + superclass_name + "\")";
this._currentSuperMetaClass = "objj_getMetaClass(\"" + superclass_name + "\")";
}
}
else
{
@@ -402,15 +455,10 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
token = tokens.skip_whitespace();
if (!TOKEN_IDENTIFIER.test(token))
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected class name, found \"" + token + "\".")));
throw new SyntaxError(this.error_message("*** Expected class name, found \"" + token + "\"."));
superclass_name = token;
this._currentSuperClass = "objj_getClass(\"" + superclass_name + "\")";
this._currentSuperMetaClass = "objj_getMetaClass(\"" + superclass_name + "\")";
dictionary_setValue(SUPER_CLASSES, class_name, superclass_name);
token = tokens.skip_whitespace();
}
@@ -427,8 +475,8 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
while((token = tokens.skip_whitespace()) && token != TOKEN_CLOSE_BRACE)
{
if (token == TOKEN_PREPROCESSOR)
attributes = this.directive(tokens);
if (token === TOKEN_PREPROCESSOR && tokens.next() === TOKEN_ACCESSORS)
attributes = this.accessors(tokens);
else if (token == TOKEN_SEMICOLON)
{
@@ -455,14 +503,14 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
// If we have objects in our declaration, the user forgot a ';'.
if (declaration.length)
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected ';' in ivar declaration, found '}'.")));
throw new SytnaxError(this.error_message("*** Expected ';' in ivar declaration, found '}'."));
if (ivar_count)
CONCAT(buffer, "]);\n");
if (!token)
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected '}'")));
throw new SyntaxError(this.error_message("*** Expected '}'"));
for (ivar_name in accessors)
{
var accessor = accessors[ivar_name],
@@ -475,7 +523,7 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
if (IS_NOT_EMPTY(instance_methods))
CONCAT(instance_methods, ",\n");
CONCAT(instance_methods, this.method(new objj_lexer(getterCode)));
CONCAT(instance_methods, this.method(new Lexer(getterCode)));
// setter
if (accessor["readonly"])
@@ -499,7 +547,7 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
if (IS_NOT_EMPTY(instance_methods))
CONCAT(instance_methods, ",\n");
CONCAT(instance_methods, this.method(new objj_lexer(setterCode)));
CONCAT(instance_methods, this.method(new Lexer(setterCode)));
}
}
else
@@ -507,9 +555,6 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
// We must make a new class object for our class definition.
CONCAT(buffer, "objj_registerClassPair(the_class);\n");
// Add this class to the current bundle.
CONCAT(buffer, "objj_addClassForBundle(the_class, objj_getBundleWithPath(OBJJ_CURRENT_BUNDLE.path));\n");
}
while ((token = tokens.skip_whitespace()))
@@ -542,7 +587,7 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
break;
else
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected \"@end\", found \"@" + token + "\".")));
throw new SyntaxError(this.error_message("*** Expected \"@end\", found \"@" + token + "\"."));
}
}
@@ -565,36 +610,37 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
this._currentClass = "";
}
objj_preprocessor.prototype._import = function(tokens)
Preprocessor.prototype._import = function(tokens)
{
// The introduction of an import statement forces the creation of a code fragment.
this.fragment();
var path = "",
token = tokens.skip_whitespace(),
isLocal = (token != TOKEN_LESS_THAN);
if (token == TOKEN_LESS_THAN)
if (token === TOKEN_LESS_THAN)
{
while((token = tokens.next()) && token != TOKEN_GREATER_THAN)
path += token;
if(!token)
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Unterminated import statement.")));
throw new SyntaxError(this.error_message("*** Unterminated import statement."));
}
else if (token.charAt(0) == TOKEN_DOUBLE_QUOTE)
path = token.substr(1, token.length - 2);
else
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expecting '<' or '\"', found \"" + token + "\".")));
this._fragments.push(fragment_create_file(path, NULL, isLocal, this._file));
throw new SyntaxError(this.error_message("*** Expecting '<' or '\"', found \"" + token + "\"."));
CONCAT(this._buffer, "objj_executeFile(\"");
CONCAT(this._buffer, path);
CONCAT(this._buffer, isLocal ? "\", true);" : "\", false);");
this._dependencies.push(new FileDependency(path, isLocal));
}
objj_preprocessor.prototype.method = function(tokens)
Preprocessor.prototype.method = function(/*Lexer*/ tokens)
{
var buffer = new objj_stringBuffer(),
var buffer = new StringBuffer(),
token,
selector = "",
parameters = [],
@@ -644,8 +690,8 @@ objj_preprocessor.prototype.method = function(tokens)
{
// At this point, "..." MUST follow.
if ((token = tokens.skip_whitespace()) != TOKEN_PERIOD || tokens.next() != TOKEN_PERIOD || tokens.next() != TOKEN_PERIOD)
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Argument list expected after ','.")));
throw new SyntaxError(this.error_message("*** Argument list expected after ','."));
// FIXME: Shouldn't allow any more after this.
}
@@ -687,9 +733,9 @@ objj_preprocessor.prototype.method = function(tokens)
return buffer;
}
objj_preprocessor.prototype.preprocess = function(tokens, /*objj_stringBuffer*/ aStringBuffer, terminator, instigator, tuple)
Preprocessor.prototype.preprocess = function(tokens, /*StringBuffer*/ aStringBuffer, terminator, instigator, tuple)
{
var buffer = aStringBuffer ? aStringBuffer : new objj_stringBuffer(),
var buffer = aStringBuffer ? aStringBuffer : new StringBuffer(),
count = 0,
token = "";
@@ -701,7 +747,7 @@ objj_preprocessor.prototype.preprocess = function(tokens, /*objj_stringBuffer*/
closures = [0, 0, 0];
}
while ((token = tokens.next()) && ((token != terminator) || count))
while ((token = tokens.next()) && ((token !== terminator) || count))
{
if (tuple)
{
@@ -812,37 +858,32 @@ objj_preprocessor.prototype.preprocess = function(tokens, /*objj_stringBuffer*/
}
if (instigator)
{
if (token == instigator)
++count;
else if (token == terminator)
--count;
}
// imports are deprecated in favor of @imort
if(token == TOKEN_IMPORT)
{
objj_fprintf(warning_stream, this._file.path + ": import keyword is deprecated, use @import instead.");
this._import(tokens);
if (token === instigator)
++count;
else if (token === terminator)
--count;
}
// Safari can't handle function declarations of the form function [name]([arguments]) { }
// in evals. It requires them to be in the form [name] = function([arguments]) { }. So we
// need to find these and fix them.
else if (token === TOKEN_FUNCTION)
if (token === TOKEN_FUNCTION)
{//if (window.p) alert("function");
var accumulator = "";
// Following the function identifier we can either have an open parenthesis or an identifier:
while((token = tokens.next()) && token != TOKEN_OPEN_PARENTHESIS && !(/^\w/).test(token))
while((token = tokens.next()) && token !== TOKEN_OPEN_PARENTHESIS && !(/^\w/).test(token))
accumulator += token;
// If the next token is an open parenthesis, we have a standard function and we don't have to
// change it:
if (token === TOKEN_OPEN_PARENTHESIS)
{
if (instigator === TOKEN_OPEN_PARENTHESIS)
++count;
CONCAT(buffer, "function" + accumulator + '(');
if (tuple)
@@ -892,28 +933,28 @@ objj_preprocessor.prototype.preprocess = function(tokens, /*objj_stringBuffer*/
// If we get this far and we're parsing an objj_msgSend (or array), then we have a problem.
if (tuple)
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected ']' - Unterminated message send or array.")));
new SyntaxError(this.error_message("*** Expected ']' - Unterminated message send or array."));
if (!aStringBuffer)
return buffer;
}
objj_preprocessor.prototype.selector = function(tokens, aStringBuffer)
Preprocessor.prototype.selector = function(tokens, aStringBuffer)
{
var buffer = aStringBuffer ? aStringBuffer : new objj_stringBuffer();
var buffer = aStringBuffer ? aStringBuffer : new StringBuffer();
CONCAT(buffer, "sel_getUid(\"");
// Swallow open parenthesis.
if (tokens.skip_whitespace() != TOKEN_OPEN_PARENTHESIS)
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected '('")));
throw new SyntaxError(this.error_message("*** Expected '('"));
// Eat leading whitespace
var selector = tokens.skip_whitespace();
if (selector == TOKEN_CLOSE_PARENTHESIS)
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Unexpected ')', can't have empty @selector()")));
throw new SyntaxError(this.error_message("*** Unexpected ')', can't have empty @selector()"));
CONCAT(aStringBuffer, selector);
var token,
@@ -928,9 +969,9 @@ objj_preprocessor.prototype.selector = function(tokens, aStringBuffer)
if (tokens.skip_whitespace() == TOKEN_CLOSE_PARENTHESIS)
break;
else
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Unexpected whitespace in @selector().")));
throw new SyntaxError(this.error_message("*** Unexpected whitespace in @selector()."));
else
objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Illegal character '" + token + "' in @selector().")));
throw new SyntaxError(this.error_message("*** Illegal character '" + token + "' in @selector()."));
}
CONCAT(buffer, token);
@@ -943,9 +984,13 @@ objj_preprocessor.prototype.selector = function(tokens, aStringBuffer)
return buffer;
}
objj_preprocessor.prototype.error_message = function(errorMessage)
Preprocessor.prototype.error_message = function(errorMessage)
{
return errorMessage + " <Context File: "+ this._file.path +
return errorMessage + " <Context File: "+ this._filePath +
(this._currentClass ? " Class: "+this._currentClass : "") +
(this._currentSelector ? " Method: "+this._currentSelector : "") +">";
}
exports.Lexer = Lexer;
exports.Preprocessor = Preprocessor;
exports.preprocess = preprocess;
@@ -73,17 +73,6 @@ function objj_object()
this.__address = -1;
}
// Addressing Objects
var OBJECT_COUNT = 0;
function _objj_generateObjectHash()
{
return OBJECT_COUNT++;
}
#define _objj_generateObjectHash() (OBJECT_COUNT++)
// Working with Classes
function class_getName(/*Class*/ aClass)
@@ -112,12 +101,9 @@ function class_getSuperclass(/*Class*/ aClass)
function class_setSuperclass(/*Class*/ aClass, /*Class*/ aSuperClass)
{
// FIXME: implement.
}
function class_isMetaClass(/*Class*/ aClass)
{
return ISMETA(aClass);
// Set up the actual class hierarchy.
aClass.super_class = aSuperClass;
aClass.isa.super_class = aSuperClass.isa;
}
function class_addIvar(/*Class*/ aClass, /*String*/ aName, /*String*/ aType)
@@ -250,7 +236,8 @@ function class_replaceMethod(/*Class*/ aClass, /*SEL*/ aSelector, /*IMP*/ aMetho
return method_imp;
}
var _class_initialize = function(/*Class*/ aClass)
// Private: Don't exports.
function _class_initialize(/*Class*/ aClass)
{
var meta = GETMETA(aClass);
@@ -295,9 +282,8 @@ function class_getMethodImplementation(/*Class*/ aClass, /*SEL*/ aSelector)
}
// Adding Classes
var GLOBAL_NAMESPACE = window,
REGISTERED_CLASSES = {};
var GLOBAL_NAMESPACE = GLOBAL_NAMESPACE || global,
REGISTERED_CLASSES = { };
function objj_allocateClassPair(/*Class*/ superclass, /*String*/ aName)
{
@@ -333,20 +319,24 @@ function objj_allocateClassPair(/*Class*/ superclass, /*String*/ aName)
classObject.isa = metaClassObject;
classObject.name = aName;
classObject.info = CLS_CLASS;
classObject.__address = _objj_generateObjectHash();
classObject.__address = generateObjectUID();
metaClassObject.isa = rootClassObject.isa;
metaClassObject.name = aName;
metaClassObject.info = CLS_META;
metaClassObject.__address = _objj_generateObjectHash();
metaClassObject.__address = generateObjectUID();
return classObject;
}
var CONTEXT_BUNDLE = nil;
function objj_registerClassPair(/*Class*/ aClass)
{
GLOBAL_NAMESPACE[aClass.name] = aClass;
REGISTERED_CLASSES[aClass.name] = aClass;
addClassToBundle(aClass, CONTEXT_BUNDLE);
}
// Instantiating Classes
@@ -358,7 +348,7 @@ function class_createInstance(/*Class*/ aClass)
var object = new aClass.allocator;
object.__address = _objj_generateObjectHash();
object.__address = generateObjectUID();
object.isa = aClass;
return object;
@@ -542,3 +532,163 @@ function sel_registerName(aName)
{
return aName;
}
var fastEnumerationSelector = sel_getUid("countByEnumeratingWithState:objects:count:");
function objj_fastEnumerator(/*Object*/ anObject, /*Integer*/ anAssigneeCount)
{
// If this object doesn't respond to countByEnumeratingWithState:objects:count:
// (which is obviously the case for non-Objective-J objects), then just iterate
// this one object.
if (anObject && (!anObject.isa || !class_getInstanceMethod(anObject.isa, fastEnumerationSelector)))
this._target = [anObject];
// Else, use it's implementation.
else
this._target = anObject;
this._state = { state:0, assigneeCount:anAssigneeCount };
this._index = 0;
// Nothing to iterate in this case.
if (!anObject)
{
this.i = 0;
this.l = 0;
}
else
this.e();
}
objj_fastEnumerator.prototype.e = function()
{
var object = this._target;
// Nothing to iterate, don't iterate
if (!object)
return NO;
var state = this._state,
index = state.assigneeCount;
while (index--)
state["items" + index] = nil;
this.i = 0;
// We optimize the array case.
if (CPArray && object.isa === CPArray)
{
if (this.l)
return NO;
this.o0 = object;
this.l = object.length;
}
else
{
// Clear out all the old state.
state.items = nil;
state.itemsPtr = nil;
this.o0 = [];
this.l = objj_msgSend(object, fastEnumerationSelector, state, this.o0, 16);
// We're flexible on this.
this.o0 = state.items || state.itemsPtr || state.items0 || this.o0;
// We allow the user to not explictly return anything in countByEnumeratingWithState:objects:count:
if (this.l === undefined)
this.l = this.o0.length;
}
var assigneeCount = state.assigneeCount;
index = assigneeCount - 1;
// Handle all items from [1 .. assigneeCount - 1]
while (index-- > 1)
this["o" + index] = state["items" + index] || [];
var lastAssigneeIndex = assigneeCount - 1;
// Autogenerate the indexes if this was left blank.
if (lastAssigneeIndex > 0)
if (state["items" + lastAssigneeIndex])
this["o" + lastAssigneeIndex] = state["items" + lastAssigneeIndex];
else
{
var count = this.l,
indexIndex = 0,
indexes = new Array(count)
for (; indexIndex < count; ++indexIndex, ++this._index)
indexes[indexIndex] = this._index;
this["o" + lastAssigneeIndex] = indexes;
}
// If this is the last iteration, set target to nil so that we don't call the
// fast enumeration method again.
return this.l > 0;
}
// Exports and Globals
exports.objj_ivar = objj_ivar;
exports.objj_method = objj_method;
exports.objj_class = objj_class;
exports.objj_object = objj_object;
exports.class_getName = class_getName;
exports.class_getSuperclass = class_getSuperclass;
exports.class_setSuperclass = class_setSuperclass;
exports.class_isMetaClass = class_isMetaClass;
exports.class_addIvar = class_addIvar;
exports.class_addIvars = class_addIvars;
exports.class_copyIvarList = class_copyIvarList;
exports.class_addMethod = class_addMethod;
exports.class_addMethods = class_addMethods;
exports.class_getInstanceMethod = class_getInstanceMethod;
exports.class_getClassMethod = class_getClassMethod;
exports.class_copyMethodList = class_copyMethodList;
exports.class_replaceMethod = class_replaceMethod;
exports.class_getMethodImplementation = class_getMethodImplementation;
exports.objj_allocateClassPair = objj_allocateClassPair;
exports.objj_registerClassPair = objj_registerClassPair;
exports.class_createInstance = class_createInstance;
exports.object_getClassName = object_getClassName;
exports.objj_lookUpClass = objj_lookUpClass;
exports.objj_getClass = objj_getClass;
exports.objj_getMetaClass = objj_getMetaClass;
exports.ivar_getName = ivar_getName;
exports.ivar_getTypeEncoding = ivar_getTypeEncoding;
exports.objj_msgSend = objj_msgSend;
exports.objj_msgSendSuper = objj_msgSendSuper;
exports.method_getName = method_getName;
exports.method_getImplementation = method_getImplementation;
exports.method_setImplementation = method_setImplementation;
exports.method_exchangeImplementations = method_exchangeImplementations;
exports.sel_getName = sel_getName;
exports.sel_getUid = sel_getUid;
exports.sel_isEqual = sel_isEqual;
exports.sel_registerName = sel_registerName;
exports.objj_fastEnumerator = objj_fastEnumerator;
exports.objj_generateObjectUID = generateObjectUID;
exports._objj_generateObjectHash = generateObjectUID;
-115
View File
@@ -1,115 +0,0 @@
/*
* constants.js
* Objective-J
*
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
// Objective-J Constants
var NO = false,
YES = true,
nil = null,
Nil = null,
NULL = null,
// In IE, it is much faster to call these global methods than their Math. equivalents.
// We var them in order to make them DontDelete globals, which are known to be much faster in Safari.
ABS = Math.abs,
ASIN = Math.asin,
ACOS = Math.acos,
ATAN = Math.atan,
ATAN2 = Math.atan2,
SIN = Math.sin,
COS = Math.cos,
TAN = Math.tan,
EXP = Math.exp,
POW = Math.pow,
CEIL = Math.ceil,
FLOOR = Math.floor,
ROUND = Math.round,
MIN = Math.min,
MAX = Math.max,
RAND = Math.random,
SQRT = Math.sqrt,
E = Math.E,
LN2 = Math.LN2,
LN10 = Math.LN10,
LOG2E = Math.LOG2E,
LOG10E = Math.LOG10E,
PI = Math.PI,
PI2 = Math.PI * 2.0,
PI_2 = Math.PI / 2.0,
SQRT1_2 = Math.SQRT1_2,
SQRT2 = Math.SQRT2;
window.setNativeTimeout = window.setTimeout;
window.clearNativeTimeout = window.clearTimeout;
window.setNativeInterval = window.setInterval;
window.clearNativeInterval = window.clearInterval;
// Detecting Browser Features
#define ACTIVE_X window.ActiveXObject
#define OPERA window.opera
#define NATIVE_XMLHTTPREQUEST window.XMLHttpRequest
#define IF(FEATURE) if (FEATURE) {
#define ELSE } else {
#define ELIF(FEATURE) } else if (FEATURE) {
#define ENDIF }
//
// FIXME: Should we just override normal alerts?
var objj_continue_alerting = NO;
function objj_alert(aString)
{
if (!objj_continue_alerting)
return;
objj_continue_alerting = confirm(aString + "\n\nClick cancel to prevent further alerts.");
}
function objj_fprintf(stream, string)
{
stream(string);
}
function objj_printf(string)
{
objj_fprintf(alert, string);
}
#if COMMON_JS
var warning_stream = function (aString) { print(aString) };
#else
if (window.console && window.console.warn)
var warning_stream = function(aString) { window.console.warn(aString); }
else
var warning_stream = function(){};
#endif
-126
View File
@@ -1,126 +0,0 @@
/*
* dictionary.js
* Objective-J
*
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
function objj_dictionary()
{
this._keys = [];
this.count = 0;
this._buckets = {};
this.__address = _objj_generateObjectHash();
}
objj_dictionary.prototype.containsKey = function(aKey) { return dictionary_containsKey(this, aKey); }
objj_dictionary.prototype.getCount = function() { return dictionary_getCount(this); }
objj_dictionary.prototype.getValue = function(aKey) { return dictionary_getValue(this, aKey); }
objj_dictionary.prototype.setValue = function(aKey, aValue) { return dictionary_setValue(this, aKey, aValue); }
objj_dictionary.prototype.removeValue = function(aKey) { return dictionary_removeValue(this, aKey); }
function dictionary_containsKey(aDictionary, aKey)
{
return aDictionary._buckets[aKey] != NULL;
}
#define dictionary_containsKey(aDictionary, aKey) ((aDictionary)._buckets[aKey] != NULL)
function dictionary_getCount(aDictionary)
{
return aDictionary.count;
}
#define dictionary_getCount(aDictionary) ((aDictionary).count)
function dictionary_getValue(aDictionary, aKey)
{
return aDictionary._buckets[aKey];
}
#define dictionary_getValue(aDictionary, aKey) ((aDictionary)._buckets[aKey])
function dictionary_setValue(aDictionary, aKey, aValue)
{
if (aDictionary._buckets[aKey] == NULL)
{
aDictionary._keys.push(aKey);
++aDictionary.count;
}
if ((aDictionary._buckets[aKey] = aValue) == NULL)
--aDictionary.count;
}
#define dictionary_setValue(aDictionary, aKey, aValue)\
{\
if ((aDictionary)._buckets[aKey] == NULL)\
{\
(aDictionary)._keys.push(aKey);\
++(aDictionary).count;\
}\
\
if (((aDictionary)._buckets[aKey] = aValue) == NULL) \
--(aDictionary).count;\
}
function dictionary_removeValue(aDictionary, aKey)
{
if (aDictionary._buckets[aKey] == NULL)
return;
--aDictionary.count;
if (aDictionary._keys.indexOf)
aDictionary._keys.splice(aDictionary._keys.indexOf(aKey), 1);
else
{
var keys = aDictionary._keys,
index = 0,
count = keys.length;
for (; index < count; ++index)
if (keys[index] == aKey)
{
keys.splice(index, 1);
break;
}
}
delete aDictionary._buckets[aKey];
}
function dictionary_replaceValue(aDictionary, aKey, aValue)
{
if (aDictionary[aKey] == NULL)
return;
// FIXME: Implement
// aDictionary.keys.splice(aDictionary.keys.indexOf(aKey), 1);
}
function dictionary_description(aDictionary)
{
var str = "{ ";
for ( x in aDictionary._buckets)
str += x + ":" + aDictionary._buckets[x] + ",";
str += " }";
return str;
}
-278
View File
@@ -1,278 +0,0 @@
/*
* evaluate.js
* Objective-J
*
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
var objj_included_files = { };
var FRAGMENT_CODE = 1,
FRAGMENT_FILE = 1 << 2,
FRAGMENT_LOCAL = 1 << 3;
function objj_fragment()
{
this.info = NULL;
this.type = 0;
this.context = NULL;
this.bundle = NULL;
this.file = NULL;
}
#define EVALUATION_PERIOD 3000
function objj_context()
{
this.fragments = [];
this.scheduled = NO;
this.blocked = NO;
}
#define SET_CONTEXT(aFragment, aContext) aFragment.context = aContext
#define GET_CONTEXT(aFragment) aFragment.context
#define SET_TYPE(aFragment, aType) aFragment.type = (aType)
#define GET_TYPE(aFragment) aFragment.type
#define GET_CODE(aFragment) aFragment.info
#define SET_CODE(aFragment, aCode) aFragment.info = (aCode)
#define GET_PATH(aFragment) aFragment.info
#define SET_PATH(aFragment, aPath) aFragment.info = aPath
#define GET_BUNDLE(aFragment) aFragment.bundle
#define SET_BUNDLE(aFragment, aBundle) aFragment.bundle = aBundle
#define GET_FILE(aFragment) aFragment.file
#define SET_FILE(aFragment, aFile) aFragment.file = aFile
#define IS_FILE(aFragment) (aFragment.type & FRAGMENT_FILE)
#define IS_LOCAL(aFragment) (aFragment.type & FRAGMENT_LOCAL)
objj_fragment.prototype.toMarkedString = function()
{
return IS_FILE(this) ? (IS_LOCAL(this) ? MARKER_IMPORT_LOCAL : MARKER_IMPORT_STD) + ';' + GET_PATH(this).length + ';' + GET_PATH(this) :
MARKER_CODE + ';' + GET_CODE(this).length + ';' + GET_CODE(this);
}
function fragment_create_code(aCode, aBundle, aFile)
{
var fragment = new objj_fragment();
SET_TYPE(fragment, FRAGMENT_CODE);
SET_CODE(fragment, aCode);
SET_BUNDLE(fragment, aBundle);
SET_FILE(fragment, aFile);
return fragment;
}
function fragment_create_file(aPath, aBundle, isLocal, aFile)
{
var fragment = new objj_fragment();
SET_TYPE(fragment, FRAGMENT_FILE | (FRAGMENT_LOCAL * isLocal));
SET_PATH(fragment, aPath);
SET_BUNDLE(fragment, aBundle);
SET_FILE(fragment, aFile);
return fragment;
}
objj_context.prototype.evaluate = function()
{
this.scheduled = NO;
// If we're blocked by IO, then just reschedule.
if (this.blocked)
return this.schedule();
// If not, begin the evaluation loop.
var sleep = NO,
start = new Date(),
fragments = this.fragments;
while (!sleep && fragments.length)
{
var fragment = fragments.pop();
if (IS_FILE(fragment))
sleep = fragment_evaluate_file(fragment);
else
sleep = fragment_evaluate_code(fragment);
// Sleep evaluation if we've been at it too long to avoid
// unresponsive script errors.
sleep = sleep || ((new Date() - start) > EVALUATION_PERIOD);
}
if (sleep)
this.schedule();
else if (this.didCompleteCallback)
this.didCompleteCallback(this);
}
objj_context.prototype.schedule = function()
{
if (this.scheduled)
return;
this.scheduled = YES;
var context = this;
window.setNativeTimeout(function () { context.evaluate(); }, 0);
}
objj_context.prototype.pushFragment = function(aFragment)
{
SET_CONTEXT(aFragment, this);
this.fragments.push(aFragment);
}
function fragment_evaluate_code(aFragment)
{
var compiled;
OBJJ_CURRENT_BUNDLE = GET_BUNDLE(aFragment);
try
{
#if RHINO
var functionText = "function(){"+GET_CODE(aFragment)+"/**/\n}";
if (typeof system !== "undefined" && system.engine === "rhino")
compiled = Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(window, functionText, GET_FILE(aFragment).path, 0, null);
else
compiled = eval("("+functionText+")");
#else
// "//@ sourceURL=" at the end lets us name our eval'd files for debuggers, etc.
// * WebKit: http://pmuellr.blogspot.com/2009/06/debugger-friendly.html
// * Firebug: http://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/
//if (true) {
var functionText = GET_CODE(aFragment)+"/**/\n//@ sourceURL="+GET_FILE(aFragment).path;
compiled = new Function(functionText);
//} else {
// // Firebug only does it for "eval()", not "new Function()". Ugh. Slower.
// var functionText = "(function(){"+GET_CODE(aFragment)+"/**/\n})\n//@ sourceURL="+GET_FILE(aFragment).path;
// compiled = eval(functionText);
//}
compiled.displayName = GET_FILE(aFragment).path;
#endif
}
catch(anException)
{
objj_exception_report(anException, GET_FILE(aFragment));
}
#if RHINO
compiled();
#else
try
{
compiled();
}
catch(anException)
{
objj_exception_report(anException, GET_FILE(aFragment));
}
#endif
return NO;
}
function fragment_evaluate_file(aFragment)
{
var context = GET_CONTEXT(aFragment),
requiresSleep = YES;
// Make us IO Blocked until we receive the file.
context.blocked = YES;
objj_request_file(GET_PATH(aFragment), IS_LOCAL(aFragment), function(aFile)
{
// Use the captured value from the closure. If objj_request_file
// returns immediately, then this will cause us to avoid breaking,
// but if it doesn't, then this will have no effect.
requiresSleep = NO;
// We've received the file, so no longer block execution.
context.blocked = NO;
// FIXME: We need to actually support this, and handle it better
// as well.
if (aFile == OBJJ_NO_FILE)
objj_alert("uh oh!");
// If this file has already been included, skip it and bail.
if (objj_included_files[aFile.path])
return;
// If not, then mark it as included, for future imports.
objj_included_files[aFile.path] = YES;
// Grab the file's fragments if it has them, or preprocess it if not.
if (!aFile.fragments)
aFile.fragments = objj_preprocess(aFile.contents, aFile.bundle, aFile, OBJJ_PREPROCESSOR_DEBUG_SYMBOLS);
var fragments = aFile.fragments,
count = fragments.length,
directory = aFile.path.substr(0, aFile.path.lastIndexOf('/') + 1);
// Put the individual fragments at the head of the evaluation
// stack to be evaluated.
while (count--)
{
var fragment = fragments[count];
if (IS_FILE(fragment))
{
if (IS_LOCAL(fragment))
SET_PATH(fragment, directory + GET_PATH(fragment));
objj_request_file(GET_PATH(fragment), IS_LOCAL(fragment), NULL);
}
context.pushFragment(fragment);
}
});
return requiresSleep;
}
function objj_import(/*String | Array*/ pathOrPaths, /*BOOL*/ isLocal, /*Function*/ didCompleteCallback)
{
var context = new objj_context(),
paths = pathOrPaths;
if (typeof paths === "string")
paths = [paths];
var index = 0,
count = paths.length;
for (; index < count; ++index)
context.pushFragment(fragment_create_file(paths[index], new objj_bundle(""), isLocal, NULL));
context.didCompleteCallback = didCompleteCallback;
context.evaluate();
}
-67
View File
@@ -1,67 +0,0 @@
/*
* exception.js
* Objective-J
*
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
var OBJJ_EXCEPTION_OUTPUT_STREAM = NULL;
function objj_exception(aName, aReason, aUserInfo)
{
this.name = aName;
this.message = aReason;
this.userInfo = aUserInfo;
this.__address = _objj_generateObjectHash();
// add rhinoException to get better stack traces
if (typeof Packages !== "undefined" && Packages && Packages.org)
this.rhinoException = Packages.org.mozilla.javascript.JavaScriptException(this, null, 0);
}
// make objj_exception a subclass of Error
// later we toll-free bridge Error to CPException
objj_exception.prototype = new Error();
function objj_exception_throw(anException)
{
throw anException;
}
function objj_exception_report(anException, aSourceFile)
{
objj_fprintf(OBJJ_EXCEPTION_OUTPUT_STREAM, aSourceFile.path + "\n" + anException);
throw anException;
}
function objj_exception_setOutputStream(aStream)
{
OBJJ_EXCEPTION_OUTPUT_STREAM = aStream;
}
#if RHINO
objj_exception_setOutputStream(warning_stream);
#elif DEBUG
if (window.console && window.console.error)
objj_exception_setOutputStream(function (aString) { console.error(aString) } );
else
objj_exception_setOutputStream(alert);
#else
objj_exception_setOutputStream(function(aString) { });
#endif
-679
View File
@@ -1,679 +0,0 @@
/*
* file.js
* Objective-J
*
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
// Notes: requests may return immediately (i.e. in IE when a file has been cached). Don't assume
// One line of code thus follows another, it may call the callback first!
// FIXME: If we ever have bundles that replace only some files, we will definitely run into problems.
// Look inside bundleResponseCallback.
var OBJJ_ENVIRONMENTS = ENVIRONMENTS;
#ifdef PLATFORM_USERAGENT
var userAgent = window.navigator.userAgent;
if (userAgent.indexOf("MSIE") !== -1)
{
if (userAgent.indexOf("MSIE 8") !== -1)
OBJJ_ENVIRONMENTS.unshift("IE8");
else
OBJJ_ENVIRONMENTS.unshift("IE7");
}
else
OBJJ_ENVIRONMENTS.unshift("W3C");
#endif
#define DIRECTORY(aPath) (aPath).substr(0, (aPath).lastIndexOf('/') + 1)
function objj_mostEligibleEnvironmentFromArray(environments)
{
var index = 0,
count = OBJJ_ENVIRONMENTS.length,
innerCount = environments.length;
// Ugh, no indexOf, no objects-in-common.
for(; index < count; ++index)
{
var innerIndex = 0,
environment = OBJJ_ENVIRONMENTS[index];
for (; innerIndex < innerCount; ++innerIndex)
if(environment === environments[innerIndex])
return environment;
}
return NULL;
}
var OBJJFileNotFoundException = "OBJJFileNotFoundException",
OBJJExecutableNotFoundException = "OBJJExecutableNotFoundException";
var objj_files = { },
objj_bundles = { },
objj_bundlesForClass = { },
objj_searches = { };
var OBJJ_NO_FILE = {};
if (typeof OBJJ_INCLUDE_PATHS === "undefined")
OBJJ_INCLUDE_PATHS = ["Frameworks", "SomethingElse"];
var OBJJ_BASE_URI = "";
IF (OPERA)
var DOMBaseElement = document.getElementsByTagName("base")[0];
if (DOMBaseElement)
OBJJ_BASE_URI = DIRECTORY(DOMBaseElement.getAttribute('href'));
ENDIF
function objj_file()
{
this.path = NULL;
this.bundle = NULL;
this.included = NO;
this.contents = NULL;
this.fragments = NULL;
}
function objj_bundle()
{
this.path = NULL;
this.info = NULL;
this._URIMap = { };
this.__address = _objj_generateObjectHash();
}
function objj_getBundleWithPath(aPath)
{
return objj_bundles[aPath];
}
function objj_setBundleForPath(aPath, aBundle)
{
objj_bundles[aPath] = aBundle;
}
function objj_bundleForClass(aClass)
{
return objj_bundlesForClass[aClass.name];
}
function objj_addClassForBundle(aClass, aBundle)
{
objj_bundlesForClass[aClass.name] = aBundle;
}
function objj_request_file(aFilePath, shouldSearchLocally, aCallback)
{
new objj_search(aFilePath, shouldSearchLocally, aCallback).attemptNextSearchPath();
}
var objj_search = function(aFilePath, shouldSearchLocally, aCallback)
{
this.filePath = aFilePath;
this.bundle = NULL;
this.bundleObservers = [];
this.searchPath = NULL;
this.searchedPaths = [];
this.includePathsIndex = shouldSearchLocally ? -1 : 0;
this.searchRequest = NULL;
this.didCompleteCallback = aCallback;
}
objj_search.prototype.nextSearchPath = function()
{
// FIXME: Path searching should be more complex (go up directories, etc).
var path = objj_standardize_path((this.includePathsIndex == -1 ? "" : OBJJ_INCLUDE_PATHS[this.includePathsIndex] + '/') + this.filePath);
++this.includePathsIndex;
return path;
}
objj_search.prototype.attemptNextSearchPath = function()
{
var searchPath = this.nextSearchPath(),
file = objj_files[searchPath];
objj_alert("Will attempt to find " + this.filePath + " at " + searchPath);
// If a file for this search path already exists, then it has already been downloaded.
// If there is a callback, we can just call it, if not, we can simply return.
if (file)
{
objj_alert("The file request at " + this.filePath + " has already been downloaded at " + searchPath);
// FIXME: Do we need this for everything?
#if RHINO
var index = 0,
count = this.searchedPaths.length;
for (; index < count; ++index)
objj_files[this.searchedPaths[index]] = file;
#endif
if (this.didCompleteCallback)
this.didCompleteCallback(file);
return;
}
var existingSearch = objj_searches[searchPath];
// If there is already an ongoing search for this search path, then we can let it find
// the file for us. Make sure to assign it our callback, if we have one, since only
// one search can have a callback at a time.
if (existingSearch)
{
if (this.didCompleteCallback)
existingSearch.didCompleteCallback = this.didCompleteCallback;
return;
}
// At this point we have a legitimate search, so we should take note of this search path
// in our search paths.
this.searchedPaths.push(this.searchPath = searchPath);
// Before we kick off our ajax requests, see whether this directory already has
// a bundle associated with it.
var infoPath = objj_standardize_path(DIRECTORY(searchPath) + "Info.plist"),
bundle = objj_bundles[infoPath];
// If there is, then simply look for the file in question.
if (bundle)
{
this.bundle = bundle;
this.request(searchPath, this.didReceiveSearchResponse);
}
else
{
// If there isn't a bundle associated with this directory, then we also have to
// search for an Info.plist.
var existingBundleSearch = objj_searches[infoPath];
// Again, if a search already exists for this bundle, then add ourselves to the list
// of observers for when this bundle is either found or created.
if (existingBundleSearch)
{
--this.includePathsIndex;
this.searchedPaths.pop();
if (this.searchedPaths.length)
this.searchPath = this.searchedPaths[this.searchedPaths.length - 1];
else
this.searchPath = NULL;
existingBundleSearch.bundleObservers.push(this);
return;
}
// If not, then look for it.
else
{
this.bundleObservers.push(this);
this.request(infoPath, this.didReceiveBundleResponse);
// Requests may return immediately, so by this point, we may have already gotten the bundle and replaced the file.
if (!this.searchReplaced)
this.searchRequest = this.request(searchPath, this.didReceiveSearchResponse);
}
}
}
IF (ACTIVE_X)
objj_search.responseCallbackLock = NO;
objj_search.responseCallbackQueue = [];
objj_search.removeResponseCallbackForFilePath = function(aFilePath)
{
var queue = objj_search.responseCallbackQueue,
index = queue.length;
while (index--)
if (queue[index][3] == aFilePath)
{
queue.splice(index, 1);
return;
}
}
objj_search.serializeResponseCallback = function(aMethod, aSearch, aResponse, aFilePath)
{
var queue = objj_search.responseCallbackQueue;
queue.push([aMethod, aSearch, aResponse, aFilePath]);
if (objj_search.responseCallbackLock)
return;
objj_search.responseCallbackLock = YES;
while (queue.length)
{
var callback = queue[0];
queue.splice(0, 1);
callback[0].apply(callback[1], [callback[2]]);
}
objj_search.responseCallbackLock = NO;
}
ENDIF
objj_search.prototype.request = function(aFilePath, aMethod)
{
var search = this,
isPlist = aFilePath.substr(aFilePath.length - 6, 6) == ".plist",
request = objj_request_xmlhttp(),
response = objj_response_xmlhttp();
response.filePath = aFilePath;
request.onreadystatechange = function()
{
if (request.readyState == 4)
{
if (response.success = (request.status != 404 && request.responseText && request.responseText.length) ? YES : NO)
{
if (window.files_total)
{
if (!window.files_loaded)
window.files_loaded = 0;
window.files_loaded += request.responseText.length;
if (window.update_progress)
window.update_progress(window.files_loaded / window.files_total);
}
if (isPlist)
response.xml = objj_standardize_xml(request);
else
response.text = request.responseText;
}
if (ACTIVE_X)
objj_search.serializeResponseCallback(aMethod, search, response, aFilePath);
else
aMethod.apply(search, [response]);
}
}
objj_searches[aFilePath] = this;
if (request.overrideMimeType && isPlist)
request.overrideMimeType('text/xml');
if (OPERA && aFilePath.charAt(0) != '/')
aFilePath = OBJJ_BASE_URI + aFilePath;
try
{
// unclear whether plusses are reserved in the URI path
//request.open("GET", aFilePath.replace(/\+/g, "%2B"), YES);
request.open("GET", aFilePath, YES);
request.send("");
}
catch (anException)
{
response.success = NO;
if (ACTIVE_X)
objj_search.serializeResponseCallback(aMethod, search, response, aFilePath);
else
aMethod.apply(search, [response]);
}
return request;
}
objj_search.prototype.didReceiveSearchResponse = function(aResponse)
{
// If we do not have a bundle yet, we cannot appropriately
// handle this response, so wait.
if (!this.bundle)
{
this.cachedSearchResponse = aResponse;
return;
}
if (aResponse.success)
{
file = new objj_file();
file.path = aResponse.filePath;
file.bundle = this.bundle
file.contents = aResponse.text;
this.complete(file);
}
else if (this.includePathsIndex < OBJJ_INCLUDE_PATHS.length)
{
// Clear out the bundle since it will no longer be valid.
// FIXME: FIXME: FIXME: WARNING: Wouldn't it be cleaner to just always do this in attemptNextSearchPath?
this.bundle = NULL;
this.attemptNextSearchPath();
}
else
objj_exception_throw(new objj_exception(OBJJFileNotFoundException, "*** Could not locate file named \"" + this.filePath + "\" in search paths."));
}
objj_search.prototype.didReceiveBundleResponse = function(aResponse)
{
var bundle = new objj_bundle();
bundle.path = aResponse.filePath;
if (aResponse.success)
bundle.info = CPPropertyListCreateFromXMLData(aResponse.xml);
else
bundle.info = new objj_dictionary();
objj_bundles[aResponse.filePath] = bundle;
var executablePath = dictionary_getValue(bundle.info, "CPBundleExecutable");
if (executablePath)
{
var environment = objj_mostEligibleEnvironmentFromArray(dictionary_getValue(bundle.info, "CPBundleEnvironments"));
executablePath = environment + ".environment/" + executablePath;
this.request(DIRECTORY(aResponse.filePath) + executablePath, this.didReceiveExecutableResponse);
// FIXME: Is this the right approach?
// Request the compiled file regardless of whether our current inquiry
var directory = DIRECTORY(aResponse.filePath),
replacedFiles = dictionary_getValue(dictionary_getValue(bundle.info, "CPBundleReplacedFiles"), environment),
index = 0,
count = replacedFiles.length;
for (; index < count; ++index)
{
// Halt any forward searches of these files from taking place.
objj_searches[directory + replacedFiles[index]] = this;
if (directory + replacedFiles[index] == this.searchPath)
{
this.searchReplaced = YES;
if (!this.cachedSearchResponse && this.searchRequest)
this.searchRequest.abort();
if (ACTIVE_X)
objj_search.removeResponseCallbackForFilePath(this.searchPath);
}
}
}
this.bundle = bundle;
var observers = this.bundleObservers,
index = 0,
count = observers.length;
for(; index < count; ++index)
{
var observer = observers[index];
// Force the observer to just attempt the path all over again,
// since it may have been replaced by the executable.
// FIXME: we should be just reattempting the ones that collided.
if (observer != this)
observer.attemptNextSearchPath();
// If we have a cached response and the search has not been
// replaced by the executable, then let it proceed.
else if (this.cachedSearchResponse && !this.searchReplaced)
this.didReceiveSearchResponse(this.cachedSearchResponse);
}
this.bundleObservers = [];
}
objj_search.prototype.didReceiveExecutableResponse = function(aResponse)
{
if (!aResponse.success)
objj_exception_throw(new objj_exception(OBJJExecutableNotFoundException, "*** The specified executable could not be located at \"" + this.filePath + "\"."));
var files = objj_decompile(aResponse.text, this.bundle),
index = 0,
count = files.length,
length = this.filePath.length;
for (; index < count; ++index)
{
var file = files[index],
path = file.path;
if (this.filePath == path.substr(path.length - length))
this.complete(file);
else
objj_files[path] = file;
}
}
objj_search.prototype.complete = function(aFile)
{
var index = 0,
count = this.searchedPaths.length;
for (; index < count; ++index)
{
objj_files[this.searchedPaths[index]] = aFile;
//FIXME: uncomment this:
//delete objj_inquiries[anInquiry.searchedPaths[index]];
}
if (this.didCompleteCallback)
this.didCompleteCallback(aFile);
}
// objj_standardize_path
//
// Standardizes the input path by removing extrenenous components and resolving
// references to parent directories.
function objj_standardize_path(aPath)
{
if (aPath.indexOf("/./") != -1 && aPath.indexOf("//") != -1 && aPath.indexOf("/../") != -1)
return aPath;
var index = 0,
components = aPath.split('/');
for(;index < components.length; ++index)
if(components[index] == "..")
{
components.splice(index - 1, 2);
index -= 2;
}
else if(index != 0 && !components[index].length || components[index] == '.' || components[index] == "..")
components.splice(index--, 1);
return components.join('/');
}
IF (ACTIVE_X)
var objj_standardize_xml = function(aRequest)
{
var XMLData = new ActiveXObject("Microsoft.XMLDOM");
XMLData.loadXML(aRequest.responseText.substr(aRequest.responseText.indexOf(".dtd\">") + 6));
return XMLData;
}
ELSE
var objj_standardize_xml = function(aRequest)
{
return aRequest.responseXML;
}
ENDIF
function objj_response_xmlhttp()
{
return new Object;
}
// objj_request_xmlhttp()
//
// To be used as a browser-independent implementation of XMLHttpRequest.
// Currently known to support Safari, Firefox, IE 6/7, and Opera.
//
// Throws a primitive exception if XMLHttpRequests are not supported on
// the given browser.
IF (NATIVE_XMLHTTPREQUEST)
var objj_request_xmlhttp = function()
{
return new XMLHttpRequest();
}
ELIF (ACTIVE_X)
// DON'T try 4.0 and 5.0. Should we be trying anything other than 3.0 and 6.0?
// http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx
var MSXML_XMLHTTP_OBJECTS = [ "Microsoft.XMLHTTP", "Msxml2.XMLHTTP", "Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP.6.0" ],//"Msxml2.XMLHTTP.4.0", "Msxml2.XMLHTTP.5.0" ],
index = MSXML_XMLHTTP_OBJECTS.length;
while (index--)
{
try
{
new ActiveXObject(MSXML_XMLHTTP_OBJECTS[index]);
break;
}
catch (anException)
{
}
}
var MSXML_XMLHTTP = MSXML_XMLHTTP_OBJECTS[index];
delete index;
delete MSXML_XMLHTTP_OBJECTS;
var objj_request_xmlhttp = function()
{
return new ActiveXObject(MSXML_XMLHTTP);
}
ENDIF
var OBJJUnrecognizedFormatException = "OBJJUnrecognizedFormatException";
var STATIC_MAGIC_NUMBER = "@STATIC",
MARKER_PATH = "p",
MARKER_URI = "u",
MARKER_CODE = "c",
MARKER_BUNDLE = "b",
MARKER_TEXT = "t",
MARKER_IMPORT_STD = 'I',
MARKER_IMPORT_LOCAL = 'i';
var STATIC_EXTENSION = "sj";
function objj_decompile(aString, bundle)
{
var stream = new objj_markedStream(aString);
if (stream.magicNumber() != STATIC_MAGIC_NUMBER)
objj_exception_throw(new objj_exception(OBJJUnrecognizedFormatException, "*** Could not recognize executable code format in bundle: "+bundle));
if (stream.version() != 1.0)
objj_exception_throw(new objj_exception(OBJJUnrecognizedFormatException, "*** Could not recognize executable code format in bundle: "+bundle));
var file = NULL,
files = [],
marker;
while (marker = stream.getMarker())
{
var text = stream.getString();
switch (marker)
{
case MARKER_PATH: if (file && file.contents && file.path === file.bundle.path)
file.bundle.info = CPPropertyListCreateWithData({string:file.contents});
file = new objj_file();
file.path = DIRECTORY(bundle.path) + text;
file.bundle = bundle;
file.fragments = [];
files.push(file);
objj_files[file.path] = file;
break;
case MARKER_URI: var URI = stream.getString();
if (URI.toLowerCase().indexOf("mhtml:") === 0)
URI = "mhtml:" + DIRECTORY(window.location.href) + '/' + DIRECTORY(bundle.path) + '/' + URI.substr("mhtml:".length);
bundle._URIMap[text] = URI;
break;
case MARKER_BUNDLE: var bundlePath = DIRECTORY(bundle.path) + '/' + text;
file.bundle = objj_getBundleWithPath(bundlePath);
if (!file.bundle)
{
file.bundle = new objj_bundle();
file.bundle.path = bundlePath;
objj_setBundleForPath(file.bundle, bundlePath);
}
break;
case MARKER_TEXT: file.contents = text;
break;
case MARKER_CODE: file.fragments.push(fragment_create_code(text, bundle, file));
break;
case MARKER_IMPORT_STD: file.fragments.push(fragment_create_file(text, bundle, NO, file));
break;
case MARKER_IMPORT_LOCAL: file.fragments.push(fragment_create_file(text, bundle, YES, file));
break;
}
}
if (file && file.contents && file.path === file.bundle.path)
file.bundle.info = CPPropertyListCreateWithData({string:file.contents});
return files;
}
-616
View File
@@ -1,616 +0,0 @@
/*
* plist.js
* Objective-J
*
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
var kCFPropertyListOpenStepFormat = 1,
kCFPropertyListXMLFormat_v1_0 = 100,
kCFPropertyListBinaryFormat_v1_0 = 200,
kCFPropertyList280NorthFormat_v1_0 = -1000;
var OBJJPlistParseException = "OBJJPlistParseException",
OBJJPlistSerializeException = "OBJJPlistSerializeException";
var kCFPropertyList280NorthMagicNumber = "280NPLIST";
function objj_data()
{
this.string = "";
this._plistObject = NULL;
this.bytes = NULL;
this.base64 = NULL;
}
var objj_markedStream = function(aString)
{
var index = aString.indexOf(';');
// Grab the magic number.
this._magicNumber = aString.substr(0, index);
this._location = aString.indexOf(';', ++index);
// Grab the version number.
this._version = aString.substring(index, this._location++);
this._string = aString;
}
objj_markedStream.prototype.magicNumber = function()
{
return this._magicNumber;
}
objj_markedStream.prototype.version = function()
{
return this._version;
}
objj_markedStream.prototype.getMarker = function()
{
var string = this._string,
location = this._location;
if (location >= string.length)
return NULL;
var next = string.indexOf(';', location);
if (next < 0)
return NULL;
var marker = string.substring(location, next);
if (marker === 'e')
return NULL;
this._location = next + 1;
return marker;
}
objj_markedStream.prototype.getString = function()
{
var string = this._string,
location = this._location;
if (location >= string.length)
return NULL;
var next = string.indexOf(';', location);
if (next < 0)
return NULL;
var size = parseInt(string.substring(location, next)),
text = string.substr(next + 1, size);
this._location = next + 1 + size;
return text;
}
//
function CPPropertyListCreateData(aPlistObject, aFormat)
{
if (aFormat == kCFPropertyListXMLFormat_v1_0)
return CPPropertyListCreateXMLData(aPlistObject);
if (aFormat == kCFPropertyList280NorthFormat_v1_0)
return CPPropertyListCreate280NorthData(aPlistObject);
return NULL;
}
function CPPropertyListCreateFromData(aData, aFormat)
{
if (!aFormat)
{
// Attempt to guess the format.
if (aData instanceof objj_data)
{
var string = aData.string ? aData.string : objj_msgSend(aData, "string");
if (string.substr(0, kCFPropertyList280NorthMagicNumber.length) == kCFPropertyList280NorthMagicNumber)
aFormat = kCFPropertyList280NorthFormat_v1_0;
else
aFormat = kCFPropertyListXMLFormat_v1_0;
}
else
aFormat = kCFPropertyListXMLFormat_v1_0;
}
if (aFormat == kCFPropertyListXMLFormat_v1_0)
return CPPropertyListCreateFromXMLData(aData);
if (aFormat == kCFPropertyList280NorthFormat_v1_0)
return CPPropertyListCreateFrom280NorthData(aData);
return NULL;
}
var _CPPropertyListSerializeObject = function(aPlist, serializers)
{
var type = typeof aPlist,
valueOf = aPlist.valueOf(),
typeValueOf = typeof valueOf;
if (type != typeValueOf)
{
type = typeValueOf;
aPlist = valueOf;
}
if (type == "string")
return serializers["string"](aPlist, serializers);
else if (aPlist === true || aPlist === false)
return serializers["boolean"](aPlist, serializers);
else if (type == "number")
{
var integer = FLOOR(aPlist);
if (integer == aPlist)
return serializers["integer"](aPlist, serializers);
else
return serializers["real"](aPlist, serializers);
}
else if (aPlist.slice)
return serializers["array"](aPlist, serializers);
else
return serializers["dictionary"](aPlist, serializers);
}
// XML Format 1.0
var XML_XML = "xml",
XML_DOCUMENT = "#document",
PLIST_PLIST = "plist",
PLIST_KEY = "key",
PLIST_DICTIONARY = "dict",
PLIST_ARRAY = "array",
PLIST_STRING = "string",
PLIST_BOOLEAN_TRUE = "true",
PLIST_BOOLEAN_FALSE = "false",
PLIST_NUMBER_REAL = "real",
PLIST_NUMBER_INTEGER = "integer",
PLIST_DATA = "data";
#define NODE_NAME(anXMLNode) (String(anXMLNode.nodeName))
#define NODE_TYPE(anXMLNode) (anXMLNode.nodeType)
#define NODE_VALUE(anXMLNode) (String(anXMLNode.nodeValue))
#define FIRST_CHILD(anXMLNode) (anXMLNode.firstChild)
#define NEXT_SIBLING(anXMLNode) (anXMLNode.nextSibling)
#define PARENT_NODE(anXMLNode) (anXMLNode.parentNode)
#define DOCUMENT_ELEMENT(aDocument) (aDocument.documentElement)
#define IS_OF_TYPE(anXMLNode, aType) (NODE_NAME(anXMLNode) == aType)
#define IS_PLIST(anXMLNode) IS_OF_TYPE(anXMLNode, PLIST_PLIST)
#define IS_WHITESPACE(anXMLNode) (NODE_TYPE(anXMLNode) == 8 || NODE_TYPE(anXMLNode) == 3)
#define IS_DOCUMENTTYPE(anXMLNode) (NODE_TYPE(anXMLNode) == 10)
#define PLIST_NEXT_SIBLING(anXMLNode) while ((anXMLNode = NEXT_SIBLING(anXMLNode)) && IS_WHITESPACE(anXMLNode)) ;
#define PLIST_FIRST_CHILD(anXMLNode) anXMLNode = FIRST_CHILD(anXMLNode); if (anXMLNode != NULL && IS_WHITESPACE(anXMLNode)) PLIST_NEXT_SIBLING(anXMLNode)
// FIXME: no first child?
#define CHILD_VALUE(anXMLNode) (NODE_VALUE(FIRST_CHILD(anXMLNode)))
var _plist_traverseNextNode = function(anXMLNode, stayWithin, stack)
{
var node = anXMLNode;
PLIST_FIRST_CHILD(node);
// If this element has a child, traverse to it.
if (node)
return node;
// If not, first check if it is a container class (as opposed to a designated leaf).
// If it is, then we have to pop this container off the stack, since it is empty.
if (NODE_NAME(anXMLNode) == PLIST_ARRAY || NODE_NAME(anXMLNode) == PLIST_DICTIONARY)
stack.pop();
// If not, next check whether it has a sibling.
else
{
if (node == stayWithin)
return NULL;
node = anXMLNode;
PLIST_NEXT_SIBLING(node);
if (node)
return node;
}
// If it doesn't, start working our way back up the node tree.
node = anXMLNode;
// While we have a node and it doesn't have a sibling (and we're within our stayWithin),
// keep moving up.
while (node)
{
var next = node;
PLIST_NEXT_SIBLING(next);
// If we have a next sibling, just go to it.
if (next)
return next;
var node = PARENT_NODE(node);
// If we are being asked to move up, and our parent is the stay within, then just
if (stayWithin && node == stayWithin)
return NULL;
// Pop the stack if we have officially "moved up"
stack.pop();
}
return NULL;
}
function CPPropertyListCreateFromXMLData(XMLNodeOrData)
{
var XMLNode = XMLNodeOrData;
if (XMLNode.string)
{
if (window.ActiveXObject)
{
XMLNode = new ActiveXObject("Microsoft.XMLDOM");
XMLNode.loadXML(XMLNodeOrData.string.substr(XMLNodeOrData.string.indexOf(".dtd\">") + 6));
}
else
XMLNode = DOCUMENT_ELEMENT(new DOMParser().parseFromString(XMLNodeOrData.string, "text/xml"));
}
// Skip over DOCTYPE and so forth.
while (IS_OF_TYPE(XMLNode, XML_DOCUMENT) || IS_OF_TYPE(XMLNode, XML_XML))
PLIST_FIRST_CHILD(XMLNode);
// Skip over the DOCTYPE... see a pattern?
if (IS_DOCUMENTTYPE(XMLNode))
PLIST_NEXT_SIBLING(XMLNode);
// If this is not a PLIST, bail.
if (!IS_PLIST(XMLNode))
return NULL;
var key = "",
object = NULL,
plistObject = NULL,
plistNode = XMLNode,
containers = [],
currentContainer = NULL;
while (XMLNode = _plist_traverseNextNode(XMLNode, plistNode, containers))
{
var count = containers.length;
if (count)
currentContainer = containers[count - 1];
if (NODE_NAME(XMLNode) == PLIST_KEY)
{
key = CHILD_VALUE(XMLNode);
PLIST_NEXT_SIBLING(XMLNode);
}
switch (String(NODE_NAME(XMLNode)))
{
case PLIST_ARRAY: object = []
containers.push(object);
break;
case PLIST_DICTIONARY: object = new objj_dictionary();
containers.push(object);
break;
case PLIST_NUMBER_REAL: object = parseFloat(CHILD_VALUE(XMLNode));
break;
case PLIST_NUMBER_INTEGER: object = parseInt(CHILD_VALUE(XMLNode));
break;
case PLIST_STRING: object = _decodeHTMLComponent(FIRST_CHILD(XMLNode) ? CHILD_VALUE(XMLNode) : "");
break;
case PLIST_BOOLEAN_TRUE: object = true;
break;
case PLIST_BOOLEAN_FALSE: object = false;
break;
case PLIST_DATA: object = new objj_data();
object.bytes = FIRST_CHILD(XMLNode) ? base64_decode_to_array(CHILD_VALUE(XMLNode), true) : [];
break;
default: objj_exception_throw(new objj_exception(OBJJPlistParseException, "*** " + NODE_NAME(XMLNode) + " tag not recognized in Plist."));
}
if (!plistObject)
plistObject = object;
else if (currentContainer)
// If the container is an array...
if (currentContainer.slice)
currentContainer.push(object);
else
dictionary_setValue(currentContainer, key, object);
}
return plistObject;
}
function CPPropertyListCreateXMLData(aPlist)
{
var data = new objj_data();
data.string = "";
data.string += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
data.string += "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">";
data.string += "<plist version = \"1.0\">";
_CPPropertyListAppendXMLData(data, aPlist, "");
data.string += "</plist>";
return data;
}
// CPPropertyListCreateXMLData Helper Functions
var _CPArrayAppendXMLData = function(XMLData, anArray)
{
var i = 0,
count = anArray.length;
XMLData.string += "<array>";
for (; i < count; ++i)
_CPPropertyListAppendXMLData(XMLData, anArray[i]);
XMLData.string += "</array>";
}
var _CPDictionaryAppendXMLData = function(XMLData, aDictionary)
{
var keys = aDictionary._keys,
i = 0,
count = keys.length;
XMLData.string += "<dict>";
for (; i < count; ++i)
{
XMLData.string += "<key>" + keys[i] + "</key>";
_CPPropertyListAppendXMLData(XMLData, dictionary_getValue(aDictionary, keys[i]));
}
XMLData.string += "</dict>";
}
var _encodeHTMLComponent = function(aString)
{
return aString.replace(/&/g,'&amp;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
var _decodeHTMLComponent = function(aString)
{
return aString.replace(/&quot;/g, '"').replace(/&apos;/g, '\'').replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
}
var _CPPropertyListAppendXMLData = function(XMLData, aPlist)
{
var type = typeof aPlist,
valueOf = aPlist.valueOf(),
typeValueOf = typeof valueOf;
if (type != typeValueOf)
{
type = typeValueOf;
aPlist = valueOf;
}
if (type == "string")
XMLData.string += "<string>" + _encodeHTMLComponent(aPlist) + "</string>";
else if (aPlist === true)
XMLData.string += "<true/>";
else if (aPlist === false)
XMLData.string += "<false/>";
else if (type == "number")
{
var integer = FLOOR(aPlist);
if (integer == aPlist)
XMLData.string += "<integer>" + aPlist + "</integer>";
else
XMLData.string += "<real>" + aPlist + "</real>";
}
else if (aPlist.slice)
_CPArrayAppendXMLData(XMLData, aPlist);
else if (aPlist._keys)
_CPDictionaryAppendXMLData(XMLData, aPlist);
else
objj_exception_throw(new objj_exception(OBJJPlistSerializeException, "*** unknown plist ("+aPlist+") type: " + type));
}
// 280 North Plist Format
var ARRAY_MARKER = "A",
DICTIONARY_MARKER = "D",
FLOAT_MARKER = "f",
INTEGER_MARKER = "d",
STRING_MARKER = "S",
TRUE_MARKER = "T",
FALSE_MARKER = "F",
KEY_MARKER = "K",
END_MARKER = "E";
function CPPropertyListCreateFrom280NorthData(aData)
{
var stream = new objj_markedStream(aData.string),
marker = NULL,
key = "",
object = NULL,
plistObject = NULL,
containers = [],
currentContainer = NULL;
while (marker = stream.getMarker())
{
if (marker === END_MARKER)
{
containers.pop();
continue;
}
var count = containers.length;
if (count)
currentContainer = containers[count - 1];
if (marker === KEY_MARKER)
{
key = stream.getString();
marker = stream.getMarker();
}
switch (marker)
{
case ARRAY_MARKER: object = []
containers.push(object);
break;
case DICTIONARY_MARKER: object = new objj_dictionary();
containers.push(object);
break;
case FLOAT_MARKER: object = parseFloat(stream.getString());
break;
case INTEGER_MARKER: object = parseInt(stream.getString());
break;
case STRING_MARKER: object = stream.getString();
break;
case TRUE_MARKER: object = true;
break;
case FALSE_MARKER: object = false;
break;
default: objj_exception_throw(new objj_exception(OBJJPlistParseException, "*** " + marker + " marker not recognized in Plist."));
}
if (!plistObject)
plistObject = object;
else if (currentContainer)
// If the container is an array...
if (currentContainer.slice)
currentContainer.push(object);
else
dictionary_setValue(currentContainer, key, object);
}
return plistObject;
}
function CPPropertyListCreate280NorthData(aPlist)
{
var data = new objj_data();
data.string = kCFPropertyList280NorthMagicNumber + ";1.0;" + _CPPropertyListSerializeObject(aPlist, _CPPropertyList280NorthSerializers);
return data;
}
var _CPPropertyList280NorthSerializers = {};
_CPPropertyList280NorthSerializers["string"] = function(aString)
{
return STRING_MARKER + ';' + aString.length + ';' + aString;
}
_CPPropertyList280NorthSerializers["boolean"] = function(aBoolean)
{
return (aBoolean ? TRUE_MARKER : FALSE_MARKER) + ';';
}
_CPPropertyList280NorthSerializers["integer"] = function(anInteger)
{
var string = "" + anInteger;
return INTEGER_MARKER + ';' + string.length + ';' + string;
}
_CPPropertyList280NorthSerializers["real"] = function(aFloat)
{
var string = "" + aFloat;
return FLOAT_MARKER + ';' + string.length + ';' + string;
}
_CPPropertyList280NorthSerializers["array"] = function(anArray, serializers)
{
var index = 0,
count = anArray.length,
string = ARRAY_MARKER + ';';
for (; index < count; ++index)
string += _CPPropertyListSerializeObject(anArray[index], serializers);
return string + END_MARKER + ';';
}
_CPPropertyList280NorthSerializers["dictionary"] = function(aDictionary, serializers)
{
var keys = aDictionary._keys,
index = 0,
count = keys.length,
string = DICTIONARY_MARKER +';';
for (; index < count; ++index)
{
var key = keys[index];
string += KEY_MARKER + ';' + key.length + ';' + key;
string += _CPPropertyListSerializeObject(dictionary_getValue(aDictionary, key), serializers);
}
return string + END_MARKER + ';';
}
+104
View File
@@ -0,0 +1,104 @@
// For now just make these global.
function makeExportsGlobal()
{
for (var exportName in exports)
if (hasOwnProperty.apply(exports, [exportName]))
global[exportName] = exports[exportName];
}
function importablePath(/*String*/ aPath, /*BOOL*/ isLocal, /*String*/ aCWD)
{
aPath = FILE.normal(aPath);
if (FILE.isAbsolute(aPath))
return aPath;
if (isLocal)
aPath = FILE.normal(FILE.join(aCWD, aPath));
return aPath;
}
var cachedFileExecutersForPaths = { };
exports.fileExecuterForPath = function(/*String*/ referencePath)
{
referencePath = FILE.normal(referencePath);
var fileExecuter = cachedFileExecutersForPaths[referencePath];
if (!fileExecuter)
{
fileExecuter = function(/*String*/ aPath, /*BOOL*/ isLocal, /*BOOL*/ shouldForce)
{
aPath = importablePath(aPath, isLocal, referencePath);
var fileExecutableSearch = new FileExecutableSearch(aPath, isLocal),
fileExecutable = fileExecutableSearch.result();
if (0 && !fileExecutable.hasLoadedFileDependencies())
throw "No executable loaded for file at path " + aPath;
fileExecutable.execute(shouldForce);
}
cachedFileExecutersForPaths[referencePath] = fileExecuter;
}
return fileExecuter;
}
var cachedImportersForPaths = { };
function fileImporterForPath(/*String*/ referencePath)
{
referencePath = FILE.normal(referencePath);
var cachedImporter = cachedImportersForPaths[referencePath];
if (!cachedImporter)
{
cachedImporter = function(/*String*/ aPath, /*BOOL*/ isLocal, /*Function*/ aCallback)
{
aPath = importablePath(aPath, isLocal, referencePath);
var fileExecutableSearch = new FileExecutableSearch(aPath, isLocal);
function searchComplete(/*FileExecutableSearch*/ aFileExecutableSearch)
{
var fileExecutable = aFileExecutableSearch.result(),
fileExecuter = exports.fileExecuterForPath(referencePath),
executeAndCallback = function ()
{
fileExecuter(aPath, isLocal);
if (aCallback)
aCallback();
}
if (!fileExecutable.hasLoadedFileDependencies())
{
fileExecutable.addEventListener("dependenciesload", executeAndCallback);
fileExecutable.loadFileDependencies();
}
else
executeAndCallback();
}
if (fileExecutableSearch.isComplete())
searchComplete(fileExecutableSearch);
else
fileExecutableSearch.addEventListener("complete", function(/*Event*/ anEvent)
{
searchComplete(anEvent.fileExecutableSearch);
});
}
cachedImportersForPaths[referencePath] = cachedImporter;
}
return cachedImporter;
}
exports.fileImporterForPath = fileImporterForPath;
+381
View File
@@ -0,0 +1,381 @@
var FILE =
#ifdef COMMONJS
require("file");
#else
{
absolute: function(/*String*/ aPath)
{
aPath = FILE.normal(aPath);
if (FILE.isAbsolute(aPath))
return aPath;
return FILE.join(FILE.cwd(), aPath);
},
basename: function(/*String*/ aPath)
{
var components = FILE.split(FILE.normal(aPath));
return components[components.length - 1];
},
extension: function(/*String*/ aPath)
{
aPath = FILE.basename(aPath);
aPath = aPath.replace(/^\.*/, '');
var index = aPath.lastIndexOf(".");
return index <= 0 ? "" : aPath.substring(index);
},
cwd: function()
{
return FILE._cwd;
},
normal: function(/*String*/ aPath)
{
if (!aPath)
return "";
var components = aPath.split("/"),
results = [],
index = 0,
count = components.length,
isRoot = aPath.charAt(0) === "/";
for (; index < count; ++index)
{
var component = components[index];
// These simply remain in the current directory.
if (component === "" || component === ".")
continue;
if (component !== "..")
{
results.push(component);
continue;
}
var resultsCount = results.length;
// If we have a valid previous component, "climb" it.
if (resultsCount > 0 && results[resultsCount - 1] !== "..")
results.pop();
// If this isn't a root listing, and we are preceded by only ..'s, or
// nothing at all, then add it since it makes sense for relative paths.
else if (!isRoot && resultsCount === 0 || results[resultsCount - 1] === "..")
results.push(component);
}
return (isRoot ? "/" : "") + results.join("/");
},
dirname: function(/*String*/ aPath)
{
var aPath = FILE.normal(aPath),
components = FILE.split(aPath);
if (components.length === 2)
components.unshift("");
return FILE.join.apply(FILE, components.slice(0, components.length - 1));
},
isAbsolute: function(/*String*/ aPath)
{
return aPath.charAt(0) === "/";
},
join: function()
{
if (arguments.length === 1 && arguments[0] === "")
return "/";
return FILE.normal(Array.prototype.join.call(arguments, "/"));
},
split: function(/*String*/ aPath)
{
return FILE.normal(aPath).split("/");
}
}
var DOMBaseElement = document.getElementsByTagName("base")[0];
if (DOMBaseElement)
FILE._cwd = FILE.dirname(DOMBaseElement.getAttribute("href"));
else
FILE._cwd = FILE.dirname(window.location.pathname);
#endif
StaticResource.FileType = 0;
StaticResource.DirectoryType = 1;
StaticResource.NotFoundType = 2;
function StaticResource(/*String*/ aName, /*StaticResource*/ aParent, /*Type*/ aType, /*BOOL*/ isResolved)
{
this._parent = aParent;
this._eventDispatcher = new EventDispatcher(this);
this._name = aName;
this._isResolved = !!isResolved;
this._path = FILE.join(aParent ? aParent.path() : "", aName);
this._type = aType;
if (aParent)
aParent._children[aName] = this;
if (aType === StaticResource.DirectoryType)
this._children = { };
else if (aType === StaticResource.FileType)
this._contents = "";
}
function resolveStaticResource(/*StaticResource*/ aResource)
{
aResource._isResolved = YES;
aResource._eventDispatcher.dispatchEvent(
{
type:"resolve",
staticResource:aResource
});
}
StaticResource.prototype.resolve = function()
{
if (this.type() === StaticResource.DirectoryType)
{
var bundle = new CFBundle(this.path());
// Eat any errors.
bundle.onerror = function() { };
// The bundle will actually resolve this node.
bundle.load(NO);
}
else
{
var self = this;
function onsuccess(/*anEvent*/ anEvent)
{
self._contents = anEvent.request.responseText();
resolveStaticResource(self);
}
function onfailure()
{
self._type = StaticResource.NotFoundType;
resolveStaticResource(self);
}
new FileRequest(this.path(), onsuccess, onfailure);
}
}
StaticResource.prototype.name = function()
{
return this._name;
}
StaticResource.prototype.path = function()
{
return this._path;
}
StaticResource.prototype.contents = function()
{
return this._contents;
}
StaticResource.prototype.children = function()
{
return this._children;
}
StaticResource.prototype.type = function()
{
return this._type;
}
StaticResource.prototype.parent = function()
{
return this._parent;
}
StaticResource.prototype.isResolved = function()
{
return this._isResolved;
}
StaticResource.prototype.write = function(/*String*/ aString)
{
this._contents += aString;
}
StaticResource.prototype.resolveSubPath = function(/*String*/ aPath, /*Type*/ aType, /*Function*/ aCallback)
{
aPath = FILE.normal(aPath);
if (aPath === "/")
return aCallback(rootResource);
if (!FILE.isAbsolute(aPath))
aPath = FILE.join(this.path(), aPath);
var components = FILE.split(aPath),
index = this === rootResource ? 1 : FILE.split(this.path()).length;
resolvePathComponents(this, aType, components, index, aCallback);
}
function resolvePathComponents(/*StaticResource*/ startResource, /*Type*/aType, /*Array*/ components, /*Integer*/ index, /*Function*/ aCallback)
{
var count = components.length,
parent = startResource;
function continueResolution()
{
resolvePathComponents(parent, aType, components, index, aCallback);
}
for (; index < count; ++index)
{
var name = components[index],
child = parent._children[name];
//CPLog(index + " " + components + ":" + (childNode && childNode.isResolved()) + ":");
//CPLog(name + " of " + parentNode.name() + " " + (childNode && childNode.name()));
//CPLog(parentNode._childNodes);
// + "(" + components + ")" + " " + index + "/" + count + ":" + (childNode && childNode.name()) +">" + (childNode ? 1:0) + " " + (childNode && childNode.isResolved()));
if (!child)
{
var type = index + 1 < count || aType === StaticResource.DirectoryType ? StaticResource.DirectoryType : StaticResource.FileType;
child = new StaticResource(name, parent, type, NO);
child.resolve();
}
// If this resource is still being resolved, just wait and rerun this same method when it's ready.
if (!child.isResolved())
return child.addEventListener("resolve", continueResolution);
// If we've already determined that this file doesn't exist...
if (child.isNotFound())
return aCallback(null, new Error("File not found: " + components.join("/")));
// If we have more path components and this is not a directory...
if ((index + 1 < count) && child.type() !== StaticResource.DirectoryType)
return aCallback(null, new Error("File is not a directory: " + components.join("/")));
parent = child;
}
return aCallback(parent);
}
StaticResource.prototype.addEventListener = function(/*String*/ anEventName, /*Function*/ anEventListener)
{
this._eventDispatcher.addEventListener(anEventName, anEventListener);
}
StaticResource.prototype.removeEventListener = function(/*String*/ anEventName, /*Function*/ anEventListener)
{
this._eventDispatcher.removeEventListener(anEventName, anEventListener);
}
StaticResource.prototype.isNotFound = function()
{
return this.type() === StaticResource.NotFoundType;
}
StaticResource.prototype.toString = function(/*BOOL*/ includeNotFounds)
{
if (this.isNotFound())
return "<file not found: " + this.name() + ">";
var string = this.parent() ? this.name() : "/",
type = this.type();
if (type === StaticResource.DirectoryType)
{
var children = this._children;
for (var name in children)
if (children.hasOwnProperty(name))
{
var child = children[name];
if (includeNotFounds || !child.isNotFound())
string += "\n\t" + children[name].toString(includeNotFounds).split('\n').join("\n\t");
}
}
return string;
}
StaticResource.prototype.nodeAtSubPath = function(/*String*/ aPath, /*BOOL*/ shouldResolveAsDirectories)
{
aPath = FILE.normal(aPath);
var components = FILE.split(FILE.isAbsolute(aPath) ? aPath : FILE.join(this.path(), aPath)),
index = 1,
count = components.length,
parent = rootResource;
for (; index < count; ++index)
{
var name = components[index];
if (hasOwnProperty.call(parent._children, name))
parent = parent._children[name];
else if (shouldResolveAsDirectories)
parent = new StaticResource(name, parent, StaticResource.DirectoryType, YES);
else
throw NULL;
}
return parent;
}
StaticResource.resolveStandardNodeAtPath = function(/*String*/ aPath, /*Function*/ aCallback)
{
var includePaths = exports.includePaths(),
resolveStandardNodeAtPath = function(/*String*/ aPath, /*int*/ anIndex)
{
var searchPath = FILE.absolute(FILE.join(includePaths[anIndex], FILE.normal(aPath)));
rootResource.resolveSubPath(searchPath, StaticResource.FileType, function(/*StaticResource*/ aStaticResource)
{
if (!aStaticResource)
{
if (anIndex + 1< includePaths.length)
resolveStandardNodeAtPath(aPath, anIndex + 1);
else
aCallback(NULL);
return;
}
aCallback(aStaticResource);
});
};
resolveStandardNodeAtPath(aPath, 0);
}
exports.includePaths = function()
{
return global.OBJJ_INCLUDE_PATHS || ["Frameworks", "Frameworks/Debug"];
}
exports.StaticResource = StaticResource;
File renamed without changes.
@@ -187,9 +187,10 @@ if (!this.JSON) {
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
var cx = new RegExp('/[\\u0000\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/g');
var escapable = new RegExp('/[\\\\\\"\\x00-\\x1f\\x7f-\\x9f\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/g');
var gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
@@ -1,12 +1,12 @@
// sprintf:
var _sprintfFormatRegex = new RegExp("([^%]+|%[\\+\\-\\ \\#0]*[0-9\\*]*(.[0-9\\*]+)?[hlL]?[cbBdieEfgGosuxXpn%@])", "g");
var _sprintfTagRegex = new RegExp("(%)([\\+\\-\\ \\#0]*)([0-9\\*]*)((.[0-9\\*]+)?)([hlL]?)([cbBdieEfgGosuxXpn%@])");
var formatRegex = new RegExp("([^%]+|%[\\+\\-\\ \\#0]*[0-9\\*]*(.[0-9\\*]+)?[hlL]?[cbBdieEfgGosuxXpn%@])", "g");
var tagRegex = new RegExp("(%)([\\+\\-\\ \\#0]*)([0-9\\*]*)((.[0-9\\*]+)?)([hlL]?)([cbBdieEfgGosuxXpn%@])");
function sprintf(format)
exports.sprintf = function(format)
{
var format = arguments[0],
tokens = format.match(_sprintfFormatRegex),
tokens = format.match(formatRegex),
index = 0,
result = "",
arg = 1;
@@ -26,7 +26,7 @@ function sprintf(format)
}
else
{
var subtokens = t.match(_sprintfTagRegex);
var subtokens = t.match(tagRegex);
if (subtokens.length != 8 || subtokens[0] != t)
{
return result;
@@ -77,7 +77,7 @@ function sprintf(format)
{
var number = String(Math.abs(Math.floor(num)));
subresult = _sprintf_justify(sign, "", number, "", width, leftJustify, padZeros)
subresult = justify(sign, "", number, "", width, leftJustify, padZeros)
}
if (specifier == "f")
@@ -85,7 +85,7 @@ function sprintf(format)
var number = String((precision != null) ? Math.abs(num).toFixed(precision) : Math.abs(num));
var suffix = (flags.indexOf("#") >= 0 && number.indexOf(".") < 0) ? "." : "";
subresult = _sprintf_justify(sign, "", number, suffix, width, leftJustify, padZeros);
subresult = justify(sign, "", number, suffix, width, leftJustify, padZeros);
}
if (specifier == "e" || specifier == "E")
@@ -93,7 +93,7 @@ function sprintf(format)
var number = String(Math.abs(num).toExponential(precision != null ? precision : 21));
var suffix = (flags.indexOf("#") >= 0 && number.indexOf(".") < 0) ? "." : "";
subresult = _sprintf_justify(sign, "", number, suffix, width, leftJustify, padZeros);
subresult = justify(sign, "", number, suffix, width, leftJustify, padZeros);
}
if (specifier == "x" || specifier == "X")
@@ -101,7 +101,7 @@ function sprintf(format)
var number = String(Math.abs(num).toString(16));
var prefix = (flags.indexOf("#") >= 0 && num != 0) ? "0x" : "";
subresult = _sprintf_justify(sign, prefix, number, "", width, leftJustify, padZeros);
subresult = justify(sign, prefix, number, "", width, leftJustify, padZeros);
}
if (specifier == "b" || specifier == "B")
@@ -109,7 +109,7 @@ function sprintf(format)
var number = String(Math.abs(num).toString(2));
var prefix = (flags.indexOf("#") >= 0 && num != 0) ? "0b" : "";
subresult = _sprintf_justify(sign, prefix, number, "", width, leftJustify, padZeros);
subresult = justify(sign, prefix, number, "", width, leftJustify, padZeros);
}
if (specifier == "o")
@@ -117,7 +117,7 @@ function sprintf(format)
var number = String(Math.abs(num).toString(8));
var prefix = (flags.indexOf("#") >= 0 && num != 0) ? "0" : "";
subresult = _sprintf_justify(sign, prefix, number, "", width, leftJustify, padZeros);
subresult = justify(sign, prefix, number, "", width, leftJustify, padZeros);
}
if (RegExp("[A-Z]").test(specifier))
@@ -141,7 +141,7 @@ function sprintf(format)
subresult = "";
}
subresult = _sprintf_justify("", "", subresult, "", width, leftJustify, false);
subresult = justify("", "", subresult, "", width, leftJustify, false);
}
result += subresult;
@@ -150,121 +150,23 @@ function sprintf(format)
return result;
}
var _sprintf_justify = function(sign, prefix, string, suffix, width, leftJustify, padZeros)
function justify(sign, prefix, string, suffix, width, leftJustify, padZeros)
{
var length = (sign.length + prefix.length + string.length + suffix.length);
if (leftJustify)
{
return sign + prefix + string + suffix + _sprintf_pad(width - length, " ");
return sign + prefix + string + suffix + pad(width - length, " ");
}
else
{
if (padZeros)
return sign + prefix + _sprintf_pad(width - length, "0") + string + suffix;
return sign + prefix + pad(width - length, "0") + string + suffix;
else
return _sprintf_pad(width - length, " ") + sign + prefix + string + suffix;
return pad(width - length, " ") + sign + prefix + string + suffix;
}
}
var _sprintf_pad = function(n, ch)
function pad(n, ch)
{
return Array(MAX(0,n)+1).join(ch);
}
// Base64 encoding and decoding
var base64_map_to = [
"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
"0","1","2","3","4","5","6","7","8","9","+","/","="],
base64_map_from = [];
for (var i = 0; i < base64_map_to.length; i++)
base64_map_from[base64_map_to[i].charCodeAt(0)] = i;
function base64_decode_to_array(input, strip)
{
if (strip)
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
var pad = (input[input.length-1] == "=" ? 1 : 0) + (input[input.length-2] == "=" ? 1 : 0),
length = input.length,
output = [];
var i = 0;
while (i < length)
{
var bits = (base64_map_from[input.charCodeAt(i++)] << 18) |
(base64_map_from[input.charCodeAt(i++)] << 12) |
(base64_map_from[input.charCodeAt(i++)] << 6) |
(base64_map_from[input.charCodeAt(i++)]);
output.push((bits & 0xFF0000) >> 16);
output.push((bits & 0xFF00) >> 8);
output.push(bits & 0xFF);
}
// strip "=" padding from end
if (pad > 0)
return output.slice(0, -1 * pad);
return output;
}
function base64_encode_array(input)
{
var pad = (3 - (input.length % 3)) % 3,
length = input.length + pad,
output = [];
// pad with nulls
if (pad > 0) input.push(0);
if (pad > 1) input.push(0);
var i = 0;
while (i < length)
{
var bits = (input[i++] << 16) |
(input[i++] << 8) |
(input[i++]);
output.push(base64_map_to[(bits & 0xFC0000) >> 18]);
output.push(base64_map_to[(bits & 0x3F000) >> 12]);
output.push(base64_map_to[(bits & 0xFC0) >> 6]);
output.push(base64_map_to[bits & 0x3F]);
}
// pad with "=" and revert array to previous state
if (pad > 0)
{
output[output.length-1] = "=";
input.pop();
}
if (pad > 1)
{
output[output.length-2] = "=";
input.pop();
}
return output.join("");
}
function base64_decode_to_string(input, strip)
{
return bytes_to_string(base64_decode_to_array(input, strip));
}
function bytes_to_string(bytes)
{
// This is relatively efficient, I think:
return String.fromCharCode.apply(null, bytes);
}
function base64_encode_string(input)
{
var temp = [];
for (var i = 0; i < input.length; i++)
temp.push(input.charCodeAt(i));
return base64_encode_array(temp);
}
+14 -54
View File
@@ -4,79 +4,39 @@
@import <Foundation/CPKeyedArchiver.j>
@import <Foundation/CPNumber.j>
var expectedString = "280NPLIST;1.0;D;K;4;key4f;3;8.8K;4;key3f;3;9.9K;4;key2F;K;4;key1S;22;Some random charactersE;"
@implementation CPDataTest : OJTestCase
{
CPData plist_data;
}
-(void)setUp
{
string_data = [[CPData alloc] initWithString:@"CPData Test"];
// Plist helpers
keys = [@"key1", @"key2", @"key3", @"key4"];
objects = [@"Some random characters", NO, 9.9, 8.8];
dict = [CPDictionary dictionaryWithObjects:objects forKeys:keys];
var keys = [@"key1", @"key2", @"key3", @"key4"];
var objects = [@"Some random characters", NO, 9.9, 8.8];
var dict = [CPDictionary dictionaryWithObjects:objects forKeys:keys];
plist_data = [[CPData alloc] initWithPlistObject:dict];
plist_data = [[CPData alloc] initWithSerializedPlistObject:dict];
}
-(void)testStringLength
-(void)testLength
{
var data = [[CPData alloc] initWithString:@"CPData Test"];
[self assert:[data length] equals:11];
var data_cm = [CPData dataWithString:@"CPData Test"];
[self assert:[data_cm length] equals:11];
}
-(void)testPlistLength
{
var data = [[CPData alloc] initWithPlistObject:dict];
[self assert:[data length] equals:93];
var data_cm = [CPData dataWithPlistObject:dict];
[self assert:[data length] equals:93];
}
-(void)testDescription
{
[self assert:[string_data description] equals:[string_data string]];
}
-(void)testString
{
[self assert:[string_data string] equals:@"CPData Test"];
[plist_data length] === expectedString.length
}
-(void)testStringFromPlist
{
[self assert:[plist_data string] equals:"280NPLIST;1.0;D;K;4;key4f;3;8.8K;4;key3f;3;9.9K;4;key2F;K;4;key1S;22;Some random charactersE;"];
[self assert:[plist_data encodedString] equals:expectedString];
}
-(void)testPlistObject
{
[self assert:[[plist_data plistObject] objectForKey:@"key1"] equals:@"Some random characters"];
[self assert:[[plist_data plistObject] objectForKey:@"key2"] equals:[CPNumber numberWithBool:NO]];
[self assert:[[plist_data plistObject] objectForKey:@"key3"] equals:[CPNumber numberWithDouble:9.9]];
[self assert:[[plist_data plistObject] objectForKey:@"key4"] equals:[CPNumber numberWithDouble:8.8]];
[self assert:[plist_data plistObject] equals:dict];
}
-(void)testSetPlistObject
{
var data = [[CPData alloc] init];
[data setPlistObject:dict];
[self assert:[data plistObject] equals:dict];
}
-(void)testSetString
{
var data = [[CPData alloc] init];
[data setString:@"CPData Test"];
[self assert:[data string] equals:@"CPData Test"];
[self assert:[[plist_data serializedPlistObject] objectForKey:@"key1"] equals:@"Some random characters"];
[self assert:[[plist_data serializedPlistObject] objectForKey:@"key2"] equals:[CPNumber numberWithBool:NO]];
[self assert:[[plist_data serializedPlistObject] objectForKey:@"key3"] equals:[CPNumber numberWithDouble:9.9]];
[self assert:[[plist_data serializedPlistObject] objectForKey:@"key4"] equals:[CPNumber numberWithDouble:8.8]];
}
@end
+8
View File
@@ -25,6 +25,14 @@
[self assert:middle equals:[middle laterDate:past] message:"laterDate incorrect"];
}
- (void)testEquals
{
var now = [CPDate date];
[self assert:now equals:now];
[self assertFalse:[now isEqual:[CPNull null]]];
[self assertFalse:[now isEqual:nil]];
}
- (void)testInitWithString
{
var tests = [
Loaded 100 of 137 files, more files were not shown because too many files have changed in this diff. Show more