mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-11-13 02:08:55 +00:00
Merge branch 'loader' into jake
This commit is contained in:
commit
80b252a744
137 files changed
+6916
-8096
No files matched your search
@@ -4,3 +4,4 @@ Build
|
||||
Demos
|
||||
./Aristo
|
||||
WebSite
|
||||
.push-package
|
||||
+2
-2
@@ -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();
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[nil]
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null]]
|
||||
forKeys:[@"bezel-color"]];
|
||||
}
|
||||
|
||||
|
||||
+105
-16
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -189,6 +189,11 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)draggingDestination
|
||||
{
|
||||
return _draggingDestination;
|
||||
}
|
||||
|
||||
- (CGPoint)draggingLocation
|
||||
{
|
||||
return _draggingLocation
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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"]];
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
@@ -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
|
||||
@@ -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.");
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -58,3 +58,12 @@ var CPNullSharedNull = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPNull (CPFastEnumeration)
|
||||
|
||||
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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"]]));
|
||||
|
||||
@@ -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();
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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,'&').replace(/"/g, '"').replace(/'/g, ''').replace(/</g,'<').replace(/>/g,'>');
|
||||
}
|
||||
|
||||
function decodeHTMLComponent(/*String*/ aString)
|
||||
{
|
||||
return aString.replace(/"/g, '"').replace(/'/g, '\'').replace(/</g,'<').replace(/>/g,'>').replace(/&/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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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" });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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" });
|
||||
}
|
||||
@@ -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";
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
#define DEPENDENCY_LOGGING 0
|
||||
#define EXECUTION_LOGGING 0
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
@@ -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]);
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,'&').replace(/"/g, '"').replace(/'/g, ''').replace(/</g,'<').replace(/>/g,'>');
|
||||
}
|
||||
|
||||
var _decodeHTMLComponent = function(aString)
|
||||
{
|
||||
return aString.replace(/"/g, '"').replace(/'/g, '\'').replace(/</g,'<').replace(/>/g,'>').replace(/&/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 + ';';
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
Reference in new issue
Block a user