diff --git a/AppKit/CPSplitView.j b/AppKit/CPSplitView.j index fc9ac630a..b044cbe9a 100644 --- a/AppKit/CPSplitView.j +++ b/AppKit/CPSplitView.j @@ -49,21 +49,22 @@ var CPSplitViewHorizontalImage = nil, CPArray _DOMDividerElements; CPString _dividerImagePath; int _drawingDivider; + + BOOL _needsResizeSubviews; } /* @ignore */ -//+ (void)initialize -//{ -// if (self != [CPSplitView class]) -// return; -// -// var bundle = [CPBundle bundleForClass:self]; -// -// CPSplitViewHorizontalImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSplitView/CPSplitViewHorizontal.png"] size:CPSizeMake(5.0, 10.0)]; -// CPSplitViewVerticalImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSplitView/CPSplitViewVertical.png"] size:CPSizeMake(10.0, 5.0)]; -//} ++ (void)initialize +{ + if (self != [CPSplitView class]) + return; + + var bundle = [CPBundle bundleForClass:self]; + CPSplitViewHorizontalImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSplitView/CPSplitViewHorizontal.png"] size:CPSizeMake(5.0, 10.0)]; + CPSplitViewVerticalImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSplitView/CPSplitViewVertical.png"] size:CPSizeMake(10.0, 5.0)]; +} - (id)initWithFrame:(CGRect)aFrame { @@ -89,20 +90,45 @@ var CPSplitViewHorizontalImage = nil, return _isVertical; } -- (void)setVertical:(BOOL)flag +- (void)setVertical:(BOOL)shouldBeVertical { - [self _setVertical:flag]; + if (![self _setVertical:shouldBeVertical]) + return; - [self adjustSubviews]; + // Just re-adjust evenly. + var frame = [self frame], + dividerThickness = [self dividerThickness]; + + [self _postNotificationWillResize]; + + var eachSize = ROUND((frame.size[_sizeComponent] - dividerThickness * (_subviews.length - 1)) / _subviews.length), + index = 0, + count = _subviews.length; + + if ([self isVertical]) + for (; index < count; ++index) + [_subviews[index] setFrame:CGRectMake(ROUND((eachSize + dividerThickness) * index), 0, eachSize, frame.size.height)]; + else + for (; index < count; ++index) + [_subviews[index] setFrame:CGRectMake(0, ROUND((eachSize + dividerThickness) * index), frame.size.width, eachSize)]; + + [self setNeedsDisplay:YES]; + + [self _postNotificationDidResize]; + } -- (void)_setVertical:(BOOL)flag +- (BOOL)_setVertical:(BOOL)shouldBeVertical { - _isVertical = flag; + var changed = (_isVertical != shouldBeVertical); - _originComponent = [self isVertical] ? "x" : "y"; - _sizeComponent = [self isVertical] ? "width" : "height"; - _dividerImagePath = [self isVertical] ? [CPSplitViewVerticalImage filename] : [CPSplitViewHorizontalImage filename]; + _isVertical = shouldBeVertical; + + _originComponent = [self isVertical] ? "x" : "y"; + _sizeComponent = [self isVertical] ? "width" : "height"; + _dividerImagePath = [self isVertical] ? [CPSplitViewVerticalImage filename] : [CPSplitViewHorizontalImage filename]; + + return changed; } - (BOOL)isPaneSplitter @@ -124,32 +150,10 @@ var CPSplitViewHorizontalImage = nil, [self setNeedsDisplay:YES]; } -- (void)didAddSubview:(CPView)subview +- (void)didAddSubview:(CPView)aSubview { - [self adjustSubviews]; -} - -- (void)adjustSubviews -{ - var frame = [self frame], - dividerThickness = [self dividerThickness]; - - [self _postNotificationWillResize]; - - var eachSize = ROUND((frame.size[_sizeComponent] - dividerThickness * (_subviews.length - 1)) / _subviews.length), - index = 0, - count = _subviews.length; - - if ([self isVertical]) - for (; index < count; ++index) - [_subviews[index] setFrame:CGRectMake(ROUND((eachSize + dividerThickness) * index), 0, eachSize, frame.size.height)]; - else - for (; index < count; ++index) - [_subviews[index] setFrame:CGRectMake(0, ROUND((eachSize + dividerThickness) * index), frame.size.width, eachSize)]; - - [self setNeedsDisplay:YES]; - - [self _postNotificationDidResize]; + _needsResizeSubviews = YES; +// [self adjustSubviews]; } - (BOOL)isSubviewCollapsed:(CPView)subview @@ -219,6 +223,39 @@ var CPSplitViewHorizontalImage = nil, #endif } +- (void)viewWillDraw +{ + [self _adjustSubviewsWithCalculatedSize]; +} + +- (void)_adjustSubviewsWithCalculatedSize +{ + if (!_needsResizeSubviews) + return; + + _needsResizeSubviews = NO; + + var subviews = [self subviews], + count = subviews.length, + oldSize = CGSizeMakeZero(); + + if ([self isVertical]) + { + oldSize.width += [self dividerThickness] * (count - 1); + oldSize.height = CGRectGetHeight([self frame]); + } + else + { + oldSize.width = CGRectGetWidth([self frame]); + oldSize.height += [self dividerThickness] * (count - 1); + } + + while (count--) + oldSize[_sizeComponent] += [subviews[count] frame].size[_sizeComponent]; + + [self resizeSubviewsWithOldSize:oldSize]; +} + - (BOOL)cursorAtPoint:(CPPoint)aPoint hitDividerAtIndex:(int)anIndex { var frame = [_subviews[anIndex] frame], @@ -354,6 +391,8 @@ var CPSplitViewHorizontalImage = nil, - (void)setPosition:(float)position ofDividerAtIndex:(int)dividerIndex { + [self _adjustSubviewsWithCalculatedSize]; + // not sure where this should override other positions? if ([_delegate respondsToSelector:@selector(splitView:constrainSplitPosition:ofSubviewAt:)]) position = [_delegate splitView:self constrainSplitPosition:position ofSubviewAt:dividerIndex]; @@ -387,13 +426,22 @@ var CPSplitViewHorizontalImage = nil, frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness]; frameB.origin[_originComponent] = realPosition + [self dividerThickness]; - [_subviews[dividerIndex+1] setFrame:frameB]; + [_subviews[dividerIndex + 1] setFrame:frameB]; + + [self setNeedsDisplay:YES]; +} + +- (void)setFrameSize:(CGSize)aSize +{ + [self _adjustSubviewsWithCalculatedSize]; + + [super setFrameSize:aSize]; [self setNeedsDisplay:YES]; } - (void)resizeSubviewsWithOldSize:(CPSize)oldSize -{ +{ if ([_delegate respondsToSelector:@selector(splitView:resizeSubviewsWithOldSize:)]) { [_delegate splitView:self resizeSubviewsWithOldSize:oldSize]; @@ -422,8 +470,6 @@ var CPSplitViewHorizontalImage = nil, [view setFrame:newFrame]; } - - [self setNeedsDisplay:YES]; [self _postNotificationDidResize]; } @@ -505,8 +551,3 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey", } @end - -// FIXME: once +initialize is fixed for superclasses, remove this and uncomment +initialize -var bundle = [CPBundle bundleForClass:CPSplitView]; -CPSplitViewHorizontalImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSplitView/CPSplitViewHorizontal.png"] size:CPSizeMake(5.0, 10.0)]; -CPSplitViewVerticalImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSplitView/CPSplitViewVertical.png"] size:CPSizeMake(10.0, 5.0)]; diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index da3d9fdd2..fbb63ca66 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -105,6 +105,7 @@ var _CPTextFieldSquareBezelColor = nil; BOOL _isSelectable; id _value; + id _placeholderString; CPLineBreakMode _lineBreakMode; #if PLATFORM(DOM) @@ -144,7 +145,8 @@ var _CPTextFieldSquareBezelColor = nil; if (self) { _value = @""; - + _placeholderString = @""; + #if PLATFORM(DOM) _DOMTextElement = document.createElement("div"); _DOMTextElement.style.position = "absolute"; @@ -167,8 +169,7 @@ var _CPTextFieldSquareBezelColor = nil; // Setting the Bezel Style /* Sets whether the textfield will have a bezeled border. - @param shouldBeBezeled YES means the textfield - will draw a bezeled border + @param shouldBeBezeled YES means the textfield will draw a bezeled border */ - (void)setBezeled:(BOOL)shouldBeBezeled { @@ -181,8 +182,7 @@ var _CPTextFieldSquareBezelColor = nil; } /* - Returns YES if the textfield draws a - bezeled border. + Returns YES if the textfield draws a bezeled border. */ - (BOOL)isBezeled { @@ -213,8 +213,7 @@ var _CPTextFieldSquareBezelColor = nil; /* Sets whether the textfield will have a border drawn. - @param shouldBeBordered YES makes the - textfield draw a border + @param shouldBeBordered YES makes the textfield draw a border */ - (void)setBordered:(BOOL)shouldBeBordered { @@ -227,8 +226,7 @@ var _CPTextFieldSquareBezelColor = nil; } /* - Returns YES if the textfield has - a border. + Returns YES if the textfield has a border. */ - (BOOL)isBordered { @@ -264,11 +262,13 @@ var _CPTextFieldSquareBezelColor = nil; [self setBackgroundColor:nil]; } +/* @ignore */ - (BOOL)acceptsFirstResponder { return _isEditable; } +/* @ignore */ - (BOOL)becomeFirstResponder { var string = [self stringValue]; @@ -283,12 +283,12 @@ var _CPTextFieldSquareBezelColor = nil; element.style.font = _DOMElement.style.font; element.style.zIndex = 1000; element.style.width = CGRectGetWidth([self bounds]) - 3.0 + "px"; -// element.style.left = _DOMTextElement.style.left; -// element.style.top = _DOMTextElement.style.top; + //element.style.left = _DOMTextElement.style.left; + //element.style.top = _DOMTextElement.style.top; _DOMElement.appendChild(element); window.setTimeout(function() { element.focus(); }, 0.0); -// element.onblur = function() { objj_debug_print_backtrace(); } + //element.onblur = function() { objj_debug_print_backtrace(); } //element.select(); element.onkeypress = function(aDOMEvent) @@ -309,12 +309,17 @@ var _CPTextFieldSquareBezelColor = nil; } }; + // If current value is the placeholder value, remove it to allow user to update. + if ([_value lowercaseString] == [[self placeholderString] lowercaseString]) + [self setStringValue:@""]; + [[CPDOMWindowBridge sharedDOMWindowBridge] _propagateCurrentDOMEvent:YES]; #endif return YES; } +/* @ignore */ - (BOOL)resignFirstResponder { #if PLATFORM(DOM) @@ -322,19 +327,25 @@ var _CPTextFieldSquareBezelColor = nil; _DOMElement.removeChild(element); [self setStringValue:element.value]; -#endif + // If textfield has no value, then display the placeholderValue + if (!_value) + [self setStringValue:[self placeholderString]]; + +#endif return YES; } +/* + Sets whether or not the receiver text field can be edited +*/ - (void)setEditable:(BOOL)shouldBeEditable { _isEditable = shouldBeEditable; } /* - Returns YES if the textfield is currently - editable by the user. + Returns YES if the textfield is currently editable by the user. */ - (BOOL)isEditable { @@ -351,8 +362,7 @@ var _CPTextFieldSquareBezelColor = nil; } /* - Returns YES if the field's text is - selectable by the user. + Returns YES if the field's text is selectable by the user. */ - (BOOL)isSelectable { @@ -360,8 +370,7 @@ var _CPTextFieldSquareBezelColor = nil; } /* - Sets whether the field's text is selectable - by the user. + Sets whether the field's text is selectable by the user. @param aFlag YES makes the text selectable */ - (void)setSelectable:(BOOL)aFlag @@ -457,6 +466,23 @@ var _CPTextFieldSquareBezelColor = nil; #endif } +/* + Returns the receiver's placeholder string +*/ +- (CPString)placeholderString +{ + return _placeholderString; +} + +/* + Sets a placeholder string for the receiver. The placeholder is displayed until editing begins, + and after editing ends, if the text field has an empty string value +*/ +-(void)setPlaceholderString:(CPString)aStringValue +{ + _placeholderString = aStringValue; +} + /* Adjusts the text field's size in the application. */ @@ -533,10 +559,8 @@ var CPTextFieldIsSelectableKey = @"CPTextFieldIsSelectableKey", } /* - Encodes the data of this textfield into the - provided coder. - @param aCoder the coder into which the data - will be written + Encodes the data of this textfield into the provided coder. + @param aCoder the coder into which the data will be written */ - (void)encodeWithCoder:(CPCoder)aCoder { diff --git a/AppKit/CPView.j b/AppKit/CPView.j index c6ff80a1c..8451ea6d9 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -37,13 +37,47 @@ import "CPGraphicsContext.j" #include "CoreGraphics/CGGeometry.h" #include "Platform/DOM/CPDOMDisplayServer.h" - +/* + @global + @group CPViewAutoresizingMasks + The default resizingMask, the view will not resize or reposition itself. +*/ CPViewNotSizable = 0; +/* + @global + @group CPViewAutoresizingMasks + Allow for flexible space on the left hand side of the view. +*/ CPViewMinXMargin = 1; +/* + @global + @group CPViewAutoresizingMasks + The view should grow and shrink horizontally with its parent view. +*/ CPViewWidthSizable = 2; +/* + @global + @group CPViewAutoresizingMasks + Allow for flexible space to the right hand side of the view. +*/ CPViewMaxXMargin = 4; +/* + @global + @group CPViewAutoresizingMasks + Allow for flexible space above the view. +*/ CPViewMinYMargin = 8; +/* + @global + @group CPViewAutoresizingMasks + The view should grow and shrink vertically with its parent view. +*/ CPViewHeightSizable = 16; +/* + @global + @group CPViewAutoresizingMasks + Allow for flexible space below the view. +*/ CPViewMaxYMargin = 32; CPViewBoundsDidChangeNotification = @"CPViewBoundsDidChangeNotification"; @@ -139,11 +173,6 @@ var DOMElementPrototype = nil, */ + (void)initialize { -#if PLATFORM(DOM) - if ([self instanceMethodForSelector:@selector(drawRect:)] != [CPView instanceMethodForSelector:@selector(drawRect:)]) - CustomDrawRectViews[[self hash]] = YES; -#endif - if (self != [CPView class]) return; @@ -1346,7 +1375,16 @@ setBoundsOrigin: - (void)setNeedsDisplayInRect:(CPRect)aRect { #if PLATFORM(DOM) - if (!CustomDrawRectViews[[[self class] hash]]) + var hash = [[self class] hash], + hasCustomDrawRect = CustomDrawRectViews[hash]; + + if (!hasCustomDrawRect && typeof hasCustomDrawRect === "undefined") + { + hasCustomDrawRect = [self methodForSelector:@selector(drawRect:)] != [CPView instanceMethodForSelector:@selector(drawRect:)]; + CustomDrawRectViews[hash] = hasCustomDrawRect; + } + + if (!hasCustomDrawRect) return; #endif @@ -1397,6 +1435,8 @@ setBoundsOrigin: */ - (void)displayRect:(CPRect)aRect { + [self viewWillDraw]; + [self displayRectIgnoringOpacity:aRect inContext:nil]; _dirtyRect = NULL; @@ -1412,6 +1452,10 @@ setBoundsOrigin: [self unlockFocus]; } +- (void)viewWillDraw +{ +} + /* Locks focus on the receiver, so drawing commands apply to it. */ diff --git a/AppKit/Cib/CPCib.j b/AppKit/Cib/CPCib.j index ee27f538d..05ab20eb4 100644 --- a/AppKit/Cib/CPCib.j +++ b/AppKit/Cib/CPCib.j @@ -24,8 +24,8 @@ import import import -import "CPCustomView.j" import "_CPCibCustomObject.j" +import "_CPCibCustomView.j" import "_CPCibKeyedUnarchiver.j" import "_CPCibObjectData.j" import "_CPCibWindowTemplate.j" diff --git a/AppKit/Cib/CPCustomView.j b/AppKit/Cib/_CPCibCustomView.j similarity index 100% rename from AppKit/Cib/CPCustomView.j rename to AppKit/Cib/_CPCibCustomView.j diff --git a/Foundation/CPString.j b/Foundation/CPString.j index 691a9ee1b..d98b64a42 100644 --- a/Foundation/CPString.j +++ b/Foundation/CPString.j @@ -128,14 +128,15 @@ var CPStringHashes = new objj_dictionary(); { if (!format) [CPException raise:CPInvalidArgumentException - reason:"stringWithString: the format can't be 'nil'"]; + reason:"initWithFormat: the format can't be 'nil'"]; self = sprintf.apply(this, Array.prototype.slice.call(arguments, 2)); return self; } /* - Creates a new string using C printf-style formatting. First argument should be a constant format string, like ' "float val = %f" ', remaining arguments should be the variables to print the values of, comma-separated. + Creates a new string using C printf-style formatting. First argument should be a constant format string, + like ' "float val = %f" ', remaining arguments should be the variables to print the values of, comma-separated. @param format the format to be used, printf-style @return the initialized CPString */ @@ -143,7 +144,7 @@ var CPStringHashes = new objj_dictionary(); { if (!format) [CPException raise:CPInvalidArgumentException - reason:"stringWithString: the format can't be 'nil'"]; + reason:"initWithFormat: the format can't be 'nil'"]; return sprintf.apply(this, Array.prototype.slice.call(arguments, 2)); } @@ -174,6 +175,21 @@ var CPStringHashes = new objj_dictionary(); } // Combining strings + +/* + Returns a string made by appending to the reciever a string constructed from a given format + string and the floowing arguments + @param format the format string in printf-style. + @return the initialized CPString +*/ +- (CPString)stringByAppendingFormat:(CPString)format, ... +{ + if (!format) + [CPException raise:CPInvalidArgumentException reason:"initWithFormat: the format can't be 'nil'"]; + + return self + sprintf.apply(this, Array.prototype.slice.call(arguments, 2)); +} + /* Creates a new CPString from the concatenation of the receiver and the specified string. @param aString the string to append to the receiver @@ -214,6 +230,7 @@ var CPStringHashes = new objj_dictionary(); if (difference) string += substring.substr(difference + substring.length); } +//Dividing Strings /* Tokenizes the receiver string using the specified delimiter. For example, if the receiver is: @@ -261,6 +278,7 @@ var CPStringHashes = new objj_dictionary(); } // Finding characters and substrings + /* Finds the range of characters in the receiver where the specified string exists. If the string does not exist in the receiver, the range length will be 0. @@ -269,9 +287,7 @@ var CPStringHashes = new objj_dictionary(); */ - (CPRange)rangeOfString:(CPString)aString { - var location = indexOf(aString); - - return CPMakeRange(location, location == CPNotFound ? 0 : aString.length); + return [self rangeOfString:aString options:0]; } /* @@ -279,13 +295,13 @@ var CPStringHashes = new objj_dictionary(); where the specified string exists. The search is subject to the options specified in the specified mask which can be a combination of: -
-CPCaseInsensitiveSearch
-CPLiteralSearch
-CPBackwardsSearch
-CPAnchoredSearch
-CPNumericSearch
-
+
+    CPCaseInsensitiveSearch
+    CPLiteralSearch
+    CPBackwardsSearch
+    CPAnchoredSearch
+    CPNumericSearch
+    
@param aString the string to search for @param aMask the options to use in the search @return the range of characters in the receiver. If the string was not found, @@ -293,23 +309,78 @@ CPNumericSearch */ - (CPRange)rangeOfString:(CPString)aString options:(int)aMask { - var string = self, + return [self rangeOfString:aString options:aMask range:nil]; +} + +/* + Finds the range of characters in the receiver + where the specified string exists in the given range + of the receiver.The search is subject to the options specified in the + specified mask which can be a combination of: +
+    CPCaseInsensitiveSearch
+    CPLiteralSearch
+    CPBackwardsSearch
+    CPAnchoredSearch
+    CPNumericSearch
+    
+ @param aString the string to search for + @param aMask the options to use in the search + @param aRange the range of the receiver in which to search for + @return the range of characters in the receiver. If the string was not found, + the length of the range will be 0. +*/ +- (CPRange)rangeOfString:(CPString)aString options:(int)aMask range:(CPrange)aRange +{ + var string = (aRange == nil) ? self : [self substringWithRange:aRange], location = CPNotFound; - + if (aMask & CPCaseInsensitiveSearch) { string = string.toLowerCase(); aString = aString.toLowerCase(); } - - if (CPBackwardsSearch) location = lastIndexOf(aString, aMask & CPAnchoredSearch ? length - aString.length : 0); - else if (aMask & CPAnchoredSearch) location = substr(0, aString.length).indexOf(aString) != CPNotFound ? 0 : CPNotFound; - else location = indexOf(aString); - + + if (aMask & CPBackwardsSearch) + location = string.lastIndexOf(aString, aMask & CPAnchoredSearch ? length - aString.length : 0); + else if (aMask & CPAnchoredSearch) + location = string.substr(0, aString.length).indexOf(aString) != CPNotFound ? 0 : CPNotFound; + else + location = string.indexOf(aString); + return CPMakeRange(location, location == CPNotFound ? 0 : aString.length); } +//Replacing Substrings + +/* + Returns a new string in which all occurrences of a target string in the reciever are replaced by + another given string. + @param target The string to replace. + @param replacement the string with which to replace the
target
+*/
+
+- (CPString)stringByReplacingOccurrencesOfString:(CPString)target withString:(CPString)replacement
+{
+    return self.replace(new RegExp(target, "g"), replacement);
+}
+
+/*
+- (CPString)stringByReplacingOccurrencesOfString:(CPString)target withString:(CPString)replacement options:(int)options range:(CPRange)searchRange
+{
+    //TODO :Vijay implement the method
+
+}
+
+- (CPString)stringByReplacingCharactersInRange:(CPRange)range withString:(CPString)replacement
+{
+    //TODO :Vijay implement the method
+}
+*/
+
+
 // Identifying and comparing strings
+
 /*
     Compares the receiver to the specified string.
     @param aString the string with which to compare
@@ -433,7 +504,18 @@ CPNumericSearch
 */
 - (double)doubleValue
 {
-    return eval(self);
+    return parseFloat(self, 10);
+}
+/*
+    Returns YES on encountering one of "Y", "y", "T", "t", or 
+    a digit 1-9. Returns NO otherwise. This method skips the initial 
+    whitespace characters, +,- followed by Zeroes.
+*/
+
+- (BOOL)boolValue
+{
+    var replaceRegExp = new RegExp("^\\s*[\\+,\\-]*0*");
+    return RegExp("^[Y,y,t,T,1-9]").test(self.replace(replaceRegExp, ''));
 }
 
 /*
@@ -441,7 +523,7 @@ CPNumericSearch
 */
 - (float)floatValue
 {
-    return eval(self);
+    return parseFloat(self, 10);
 }
 
 /*
@@ -449,12 +531,12 @@ CPNumericSearch
 */
 - (int)intValue
 {
-    return parseInt(self);
+    return parseInt(self, 10);
 }
 
 /*
     Returns an the path components of this string. This
-    method assumes that the string's contents is a '/'
+    method assumes that the string's content is a '/'
     separated file system path.
 */
 - (CPArray)pathComponents
@@ -472,6 +554,11 @@ CPNumericSearch
     return substr(lastIndexOf('.') + 1);
 }
 
+/*
+    Returns the last component of this string.
+    This method assumes that the string's content is a '/'
+    separated file system path.
+*/
 - (CPString)lastPathComponent
 {
     var components = [self pathComponents];
@@ -484,8 +571,8 @@ CPNumericSearch
 */
 - (CPString)stringByDeletingLastPathComponent
 {
-    // FIMXE: this is wrong: a/a/ returns a/a/.
-    return substr(0, lastIndexOf('/')+1);  
+    // FIXME: this is wrong: a/a/ returns a/a/.
+    return substr(0, lastIndexOf('/') + 1);
 }
 
 - (CPString)stringByStandardizingPath
@@ -509,11 +596,11 @@ String.prototype.isa = CPString;
 var sprintfFormatRegex = new RegExp("([^%]+|%[\\+\\-\\ \\#0]*[0-9\\*]*(.[0-9\\*]+)?[hlL]?[cdieEfgGosuxXpn%])", "g");
 var sprintfTagRegex = new RegExp("(%)([\\+\\-\\ \\#0]*)([0-9\\*]*)((.[0-9\\*]+)?)([hlL]?)([cdieEfgGosuxXpn%])");
 
-/**
+/*
   Creates a new string using C printf-style formatting. First argument should be a constant format string, like ' "float val = %f" ', remaining arguments should be the variables to print the values of, comma-separated.
   @param format the format to be used, printf-style
   @return the initialized CPString
-  */
+*/
 function sprintf(format)
 {
     var format = arguments[0],
diff --git a/Objective-J/plist.js b/Objective-J/plist.js
index d03ede527..59f0f8515 100644
--- a/Objective-J/plist.js
+++ b/Objective-J/plist.js
@@ -340,7 +340,7 @@ function CPPropertyListCreateFromXMLData(XMLNodeOrData)
     if (XMLNode.string)
     {
 #if RHINO
-        XMLNode = DOCUMENT_ELEMENT(Packages.javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
+        XMLNode = DOCUMENT_ELEMENT(_documentBuilder.parse(
             new Packages.org.xml.sax.InputSource(new Packages.java.io.StringReader(XMLNode.string))));
 #else
         if (window.ActiveXObject)
diff --git a/Tests/Foundation/CPStringTest.j b/Tests/Foundation/CPStringTest.j
new file mode 100644
index 000000000..289663cdc
--- /dev/null
+++ b/Tests/Foundation/CPStringTest.j
@@ -0,0 +1,72 @@
+import 
+
+@implementation CPStringTest : OJTestCase
+
+
+- (void)testStringByReplacingOccurrencesOfStringWithString
+{
+    var expectedString = @"hello world. A new world!";
+    var dummyString = @"hello woold. A new woold!";
+    var actualString = [dummyString stringByReplacingOccurrencesOfString:@"woold" withString:@"world"];
+    [self assertTrue:(expectedString === actualString) 
+             message:"stringByAppendingFormat: expected:" + expectedString + " actual:" + actualString];
+    
+    
+    
+}
+- (void)testStringByAppendingFormat
+{
+    var format = @"%d X %d = %d";
+    var expectedString = "2 X 3 = 6";
+    var dummyString = @"";
+    var actualString = [dummyString stringByAppendingFormat:format ,2 ,3 ,6];
+    [self assertTrue:(expectedString === actualString) 
+             message:"stringByAppendingFormat: expected:" + expectedString + " actual:" + actualString];
+    
+}
+- (void) testBoolValue
+{
+    var testString = @"  090";
+    [self assertTrue:[testString boolValue] message:"boolValue for the string " + testString +  " should return true"];
+    
+    testString = @"  YES";
+    [self assertTrue:[testString boolValue] message:"boolValue for the string " + testString +  " should return true"];
+    
+    testString = @"  true";
+    [self assertTrue:[testString boolValue] message:"boolValue for the string " + testString +  " should return true"];
+    
+    testString = @"  True";
+    [self assertTrue:[testString boolValue] message:"boolValue for the string " + testString +  " should return true"];
+
+    testString = @"  tTR";
+    [self assertTrue:[testString boolValue] message:"boolValue for the string " + testString +  " should return true"];
+
+    testString = @"  +98";
+    [self assertTrue:[testString boolValue] message:"boolValue for the string " + testString +  " should return true"];
+
+    testString = @"  -98";
+    [self assertTrue:[testString boolValue] message:"boolValue for the string " + testString +  " should return true"];
+
+    testString = @"  +08";
+    [self assertTrue:[testString boolValue] message:"boolValue for the string " + testString +  " should return true"];
+
+    testString = @"  -98";
+    [self assertTrue:[testString boolValue] message:"boolValue for the string " + testString +  " should return true"];
+
+    testString = @"  NO";
+    [self assertFalse:[testString boolValue] message:"boolValue for the string " + testString +  " should return false"];
+    
+    testString = @"  -N00";
+    [self assertFalse:[testString boolValue] message:"boolValue for the string " + testString +  " should return false"];
+    
+    testString = @"  00";
+    [self assertFalse:[testString boolValue] message:"boolValue for the string " + testString +  " should return false"];
+    
+    testString = @"  -00";
+    [self assertFalse:[testString boolValue] message:"boolValue for the string " + testString +  " should return false"];
+    
+}
+
+
+
+@end
diff --git a/Tools/Utilities/bridge.js b/Tools/Utilities/bridge.js
index bf55fb76f..9c3540c51 100644
--- a/Tools/Utilities/bridge.js
+++ b/Tools/Utilities/bridge.js
@@ -107,11 +107,11 @@ if (typeof readFile == "undefined") {
         	var f = new Packages.java.io.File(path);
 	
 	        if (!f.canRead()) {
-	            //alert("can't read: " + f.path)
+	            alert("can't read: " + f.path)
 	            return "";
 	        }
 	
-	        //alert("reading: " + f.getAbsolutePath());
+	        alert("reading: " + f.getAbsolutePath());
 	
         	var fis = new Packages.java.io.FileInputStream(f);
         	
@@ -119,12 +119,11 @@ if (typeof readFile == "undefined") {
         	fis.read(b);
         	
         	fis.close();
-	
-            //return String(new Packages.java.lang.String(b));
+
             if (characterCoding)
-                return new Packages.java.lang.String(b, characterCoding);
+                return String(new Packages.java.lang.String(b, characterCoding));
             else
-                return new Packages.java.lang.String(b);
+                return String(new Packages.java.lang.String(b));
         }
     }
     else {
@@ -283,9 +282,25 @@ if (typeof Packages != "undefined") {
 		}
 	};
 
-    var xhr_builder = Packages.javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder();
-    xhr_builder.setErrorHandler(function(exception, methodName) {
-    	//print("xml error!");
+    var _documentBuilderFactory = Packages.javax.xml.parsers.DocumentBuilderFactory.newInstance();
+    // setValidating to false doesn't seem to prevent it from downloading the DTD, but lets do it anyway
+    _documentBuilderFactory.setValidating(false);
+    
+    _documentBuilder = _documentBuilderFactory.newDocumentBuilder();
+    // prevent the Java XML parser from downloading the plist DTD from Apple every time we parse a plist
+    _documentBuilder.setEntityResolver(new Packages.org.xml.sax.EntityResolver({
+        resolveEntity: function(publicId, systemId) {
+            //Packages.java.lang.System.out.println("publicId=" + publicId + " systemId=" + systemId);
+            
+            // TODO: return a local copy of the DTD?
+            if (String(systemId) == "http://www.apple.com/DTDs/PropertyList-1.0.dtd")
+                return new Packages.org.xml.sax.InputSource(new Packages.java.io.StringReader(""));
+                
+            return null;
+        } 
+    }));
+    // throw an exception on error
+    _documentBuilder.setErrorHandler(function(exception, methodName) {
     	throw exception;
     });
 
@@ -372,7 +387,7 @@ if (typeof Packages != "undefined") {
     }
     
     parseXMLString = function(string) {
-        return (Packages.javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
+        return (_documentBuilder.parse(
             new Packages.org.xml.sax.InputSource(
                 new Packages.java.io.StringReader(string))).getDocumentElement());
     }
@@ -435,23 +450,23 @@ XMLHttpRequest.prototype.send = function(body) {
 	
 	try {
 		this.responseText = readFile(this.url);
-		alert("xhr: " + this.url);
+		alert("xhr response:  " + this.url + " (length="+this.responseText.length+")");
 	} catch (e) {
-	    alert("read exception: " + this.url);
+	    alert("xhr exception: " + this.url);
     	this.responseText = "";
 		this.responseXML = null;
 	}    
 	
 	if (this.responseText.length > 0) {
 		try {
-			this.responseXML = xhr_builder.parse(new Packages.org.xml.sax.InputSource(new Packages.java.io.StringReader(this.responseText)));
+			this.responseXML = _documentBuilder.parse(new Packages.org.xml.sax.InputSource(new Packages.java.io.StringReader(this.responseText)));
 		} catch (e) {
 			this.responseXML = null;
 		}
 	    this.status = 200;
 	}
 	else {
-	    alert("empty file: " + this.url);
+	    alert("xhr empty:     " + this.url);
 	    this.status = 404;
 	}
 	
diff --git a/Tools/nib2cib/NSCustomView.j b/Tools/nib2cib/NSCustomView.j
index 6a1362497..b6bc5c598 100644
--- a/Tools/nib2cib/NSCustomView.j
+++ b/Tools/nib2cib/NSCustomView.j
@@ -20,7 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-import 
+import 
 
 import "NSView.j"