Browse files

Merge pull request #602 from facebook/development

Release Three20 v1.0.6
  • Loading branch information...
2 parents 726841e + 8076676 commit 4aed866d0a17aea6e82bb73c5e4482733d0f7395 @jwang jwang committed Jul 15, 2011
Showing with 5,915 additions and 1,343 deletions.
  1. +18 −0 samples/Style/TTCSSStyleSheets/Classes/SampleCSSStyleSheet.h
  2. +36 −0 samples/Style/TTCSSStyleSheets/Classes/SampleCSSStyleSheet.m
  3. +0 −2 samples/Style/TTCSSStyleSheets/Classes/StyleSheetViewController.h
  4. +45 −23 samples/Style/TTCSSStyleSheets/Classes/StyleSheetViewController.m
  5. +1 −1 samples/Style/TTCSSStyleSheets/Headers/TTCSSStyleSheets_Prefix.pch
  6. +34 −3 samples/Style/TTCSSStyleSheets/Resources/stylesheet.css
  7. +6 −0 samples/Style/TTCSSStyleSheets/TTCSSStyleSheets.xcodeproj/project.pbxproj
  8. +9 −0 samples/TTCatalog/Classes/ImageTest1Controller.m
  9. +48 −14 samples/TTCatalog/Classes/StyleTestController.m
  10. +1 −0 samples/TTCatalog/Classes/StyledTextTestController.m
  11. BIN src/Three20.bundle/cs.lproj/Localizable.strings
  12. BIN src/Three20.bundle/he.lproj/Localizable.strings
  13. +0 −6 src/Three20/Headers/Three20.h
  14. +0 −2 src/Three20/Three20.xcodeproj/project.pbxproj
  15. +15 −0 src/Three20Core/Headers/NSDataAdditions.h
  16. +5 −0 src/Three20Core/Headers/NSStringAdditions.h
  17. +75 −0 src/Three20Core/Headers/Three20.h
  18. +2 −0 src/Three20Core/Headers/Three20Core.h
  19. +33 −0 src/Three20Core/Headers/Three20Version.h
  20. +104 −0 src/Three20Core/Sources/NSDataAdditions.m
  21. +53 −34 src/Three20Core/Sources/NSDateAdditions.m
  22. +10 −0 src/Three20Core/Sources/NSStringAdditions.m
  23. +2 −1 src/Three20Core/Sources/TTExtensionAuthor.m
  24. +2 −1 src/Three20Core/Sources/TTExtensionInfo.m
  25. +64 −0 src/Three20Core/Sources/Three20.m
  26. +23 −0 src/Three20Core/Sources/Three20Version.m
  27. +16 −3 src/Three20Core/Three20Core.xcodeproj/project.pbxproj
  28. +23 −0 src/Three20Core/UnitTests/CoreGlobalTests.m
  29. +1 −1 src/Three20Network/Headers/TTErrorCodes.h
  30. +47 −2 src/Three20Network/Headers/TTURLRequest.h
  31. +14 −0 src/Three20Network/Headers/TTURLRequestQueue.h
  32. +13 −0 src/Three20Network/Headers/TTURLResponse.h
  33. +127 −0 src/Three20Network/NetworkRequestTimeoutTests.m
  34. +1 −1 src/Three20Network/Sources/TTErrorCodes.m
  35. +53 −13 src/Three20Network/Sources/TTRequestLoader.m
  36. +4 −2 src/Three20Network/Sources/TTURLCache.m
  37. +57 −17 src/Three20Network/Sources/TTURLRequest.m
  38. +12 −3 src/Three20Network/Sources/TTURLRequestQueue.m
  39. +2 −1 src/Three20Network/Sources/TTUserInfo.m
  40. +375 −9 src/Three20Network/Three20Network.xcodeproj/project.pbxproj
  41. +5 −0 src/Three20Style/Headers/TTDefaultStyleSheet.h
  42. +24 −2 src/Three20Style/Headers/TTSpeechBubbleShape.h
  43. +3 −0 src/Three20Style/Headers/TTStyledLayout.h
  44. +6 −0 src/Three20Style/Headers/TTStyledText.h
  45. +2 −1 src/Three20Style/Sources/TTBevelBorderStyle.m
  46. +2 −1 src/Three20Style/Sources/TTBlendStyle.m
  47. +2 −1 src/Three20Style/Sources/TTBoxStyle.m
  48. +25 −0 src/Three20Style/Sources/TTDefaultStyleSheet.m
  49. +8 −2 src/Three20Style/Sources/TTFourBorderStyle.m
  50. +2 −1 src/Three20Style/Sources/TTGridLayout.m
  51. +2 −1 src/Three20Style/Sources/TTHighlightBorderStyle.m
  52. +2 −1 src/Three20Style/Sources/TTImageStyle.m
  53. +2 −1 src/Three20Style/Sources/TTInsetStyle.m
  54. +2 −1 src/Three20Style/Sources/TTLinearGradientBorderStyle.m
  55. +2 −1 src/Three20Style/Sources/TTShadowStyle.m
  56. +2 −1 src/Three20Style/Sources/TTSolidBorderStyle.m
  57. +67 −24 src/Three20Style/Sources/TTSpeechBubbleShape.m
  58. +4 −2 src/Three20Style/Sources/TTStyle.m
  59. +2 −1 src/Three20Style/Sources/TTStyleContext.m
  60. +2 −1 src/Three20Style/Sources/TTStyleSheet.m
  61. +11 −7 src/Three20Style/Sources/TTStyledBoxFrame.m
  62. +8 −4 src/Three20Style/Sources/TTStyledButtonNode.m
  63. +6 −3 src/Three20Style/Sources/TTStyledElement.m
  64. +2 −1 src/Three20Style/Sources/TTStyledFrame.m
  65. +2 −1 src/Three20Style/Sources/TTStyledImageFrame.m
  66. +4 −2 src/Three20Style/Sources/TTStyledImageNode.m
  67. +50 −7 src/Three20Style/Sources/TTStyledLayout.m
  68. +8 −4 src/Three20Style/Sources/TTStyledLinkNode.m
  69. +4 −2 src/Three20Style/Sources/TTStyledNode.m
  70. +12 −1 src/Three20Style/Sources/TTStyledText.m
  71. +2 −1 src/Three20Style/Sources/TTStyledTextFrame.m
  72. +4 −2 src/Three20Style/Sources/TTStyledTextNode.m
  73. +34 −13 src/Three20Style/Sources/TTStyledTextParser.m
  74. +2 −1 src/Three20Style/Sources/TTTextStyle.m
  75. +0 −2 src/Three20Style/Three20Style.xcodeproj/project.pbxproj
  76. +2 −0 src/Three20UI/Headers/TTLauncherItem.h
  77. +2 −0 src/Three20UI/Headers/TTLauncherView.h
  78. +1 −1 src/Three20UI/Headers/TTStyledTextLabel.h
  79. +7 −0 src/Three20UI/Headers/TTTableViewController.h
  80. +14 −6 src/Three20UI/Headers/TTWebController.h
  81. +1 −1 src/Three20UI/Headers/Three20UI.h
  82. +8 −4 src/Three20UI/Sources/TTActionSheetController.m
  83. +8 −4 src/Three20UI/Sources/TTActivityLabel.m
  84. +8 −4 src/Three20UI/Sources/TTAlertViewController.m
  85. +2 −1 src/Three20UI/Sources/TTButton.m
  86. +2 −1 src/Three20UI/Sources/TTButtonBar.m
  87. +2 −1 src/Three20UI/Sources/TTButtonContent.m
  88. +4 −2 src/Three20UI/Sources/TTErrorView.m
  89. +2 −1 src/Three20UI/Sources/TTExtensionInfoController.m
  90. +2 −1 src/Three20UI/Sources/TTExtensionsController.m
  91. +2 −1 src/Three20UI/Sources/TTImageView.m
  92. +4 −2 src/Three20UI/Sources/TTLabel.m
  93. +4 −2 src/Three20UI/Sources/TTLauncherButton.m
  94. +8 −3 src/Three20UI/Sources/TTLauncherItem.m
  95. +7 −2 src/Three20UI/Sources/TTLauncherView.m
  96. +2 −1 src/Three20UI/Sources/TTLink.m
  97. +2 −1 src/Three20UI/Sources/TTListDataSource.m
  98. +4 −2 src/Three20UI/Sources/TTMessageController.m
  99. +2 −1 src/Three20UI/Sources/TTMessageField.m
  100. +4 −2 src/Three20UI/Sources/TTModelViewController.m
  101. +1 −1 src/Three20UI/Sources/TTNavigatorWindow.m
  102. +2 −1 src/Three20UI/Sources/TTPageControl.m
  103. +12 −2 src/Three20UI/Sources/TTPhotoView.m
  104. +9 −10 src/Three20UI/Sources/TTPhotoViewController.m
  105. +2 −1 src/Three20UI/Sources/TTPickerTextField.m
  106. +2 −1 src/Three20UI/Sources/TTPickerViewCell.m
  107. +4 −2 src/Three20UI/Sources/TTPopupViewController.m
  108. +4 −2 src/Three20UI/Sources/TTPostController.m
  109. +4 −2 src/Three20UI/Sources/TTRecursiveProgress.m
  110. +2 −1 src/Three20UI/Sources/TTScrollView.m
  111. +2 −1 src/Three20UI/Sources/TTSearchBar.m
  112. +2 −1 src/Three20UI/Sources/TTSearchDisplayController.m
  113. +4 −3 src/Three20UI/Sources/TTSearchTextField.m
  114. +2 −1 src/Three20UI/Sources/TTSearchTextFieldInternal.m
  115. +2 −1 src/Three20UI/Sources/TTSearchlightLabel.m
  116. +2 −1 src/Three20UI/Sources/TTSectionedDataSource.m
  117. +2 −1 src/Three20UI/Sources/TTSplitViewController.m
  118. +11 −1 src/Three20UI/Sources/TTStyledTextLabel.m
  119. +2 −1 src/Three20UI/Sources/TTStyledTextTableCell.m
  120. +7 −4 src/Three20UI/Sources/TTStyledTextTableItemCell.m
  121. +2 −1 src/Three20UI/Sources/TTTab.m
  122. +2 −1 src/Three20UI/Sources/TTTabBar.m
  123. +2 −1 src/Three20UI/Sources/TTTabGrid.m
  124. +2 −1 src/Three20UI/Sources/TTTabItem.m
  125. +4 −1 src/Three20UI/Sources/TTTabStrip.m
  126. +2 −1 src/Three20UI/Sources/TTTableActivityItemCell.m
  127. +2 −1 src/Three20UI/Sources/TTTableCaptionItem.m
  128. +4 −1 src/Three20UI/Sources/TTTableCaptionItemCell.m
  129. +9 −2 src/Three20UI/Sources/TTTableControlCell.m
  130. +2 −1 src/Three20UI/Sources/TTTableControlItem.m
  131. +2 −1 src/Three20UI/Sources/TTTableFlushViewCell.m
  132. +2 −1 src/Three20UI/Sources/TTTableHeaderView.m
  133. +2 −1 src/Three20UI/Sources/TTTableImageItem.m
  134. +4 −3 src/Three20UI/Sources/TTTableImageItemCell.m
  135. +2 −1 src/Three20UI/Sources/TTTableItem.m
  136. +2 −1 src/Three20UI/Sources/TTTableLinkedItem.m
  137. +2 −1 src/Three20UI/Sources/TTTableMessageItem.m
  138. +5 −1 src/Three20UI/Sources/TTTableMessageItemCell.m
  139. +3 −1 src/Three20UI/Sources/TTTableMoreButtonCell.m
  140. +4 −1 src/Three20UI/Sources/TTTableRightCaptionItemCell.m
  141. +4 −2 src/Three20UI/Sources/TTTableStyledTextItem.m
  142. +4 −1 src/Three20UI/Sources/TTTableSubtextItemCell.m
  143. +2 −1 src/Three20UI/Sources/TTTableSubtitleItem.m
  144. +4 −1 src/Three20UI/Sources/TTTableSubtitleItemCell.m
  145. +2 −1 src/Three20UI/Sources/TTTableTextItem.m
  146. +3 −1 src/Three20UI/Sources/TTTableTextItemCell.m
  147. +2 −1 src/Three20UI/Sources/TTTableView.m
  148. +2 −0 src/Three20UI/Sources/TTTableViewCell.m
  149. +33 −7 src/Three20UI/Sources/TTTableViewController.m
  150. +2 −1 src/Three20UI/Sources/TTTableViewDelegate.m
  151. +2 −1 src/Three20UI/Sources/TTTableViewDragRefreshDelegate.m
  152. +2 −1 src/Three20UI/Sources/TTTableViewItem.m
  153. +2 −1 src/Three20UI/Sources/TTTableViewNetworkEnabledDelegate.m
  154. +6 −3 src/Three20UI/Sources/TTTextBarController.m
  155. +2 −1 src/Three20UI/Sources/TTTextEditor.m
  156. +2 −1 src/Three20UI/Sources/TTTextEditorInternal.m
  157. +3 −1 src/Three20UI/Sources/TTThumbView.m
  158. +2 −1 src/Three20UI/Sources/TTThumbsDataSource.m
  159. +2 −1 src/Three20UI/Sources/TTThumbsTableViewCell.m
  160. +6 −3 src/Three20UI/Sources/TTThumbsViewController.m
  161. +2 −1 src/Three20UI/Sources/TTView.m
  162. +4 −2 src/Three20UI/Sources/TTViewController.m
  163. +24 −3 src/Three20UI/Sources/TTWebController.m
  164. +2 −1 src/Three20UI/Sources/TTYouTubeView.m
  165. +4 −2 src/Three20UI/Sources/UIViewAdditions.m
  166. +0 −2 src/Three20UI/Three20UI.xcodeproj/project.pbxproj
  167. +10 −0 src/Three20UICommon/Headers/TTGlobalUICommon.h
  168. +4 −2 src/Three20UICommon/Sources/TTBaseViewController.m
  169. +29 −1 src/Three20UICommon/Sources/TTGlobalUICommon.m
  170. +0 −2 src/Three20UICommon/Three20UICommon.xcodeproj/project.pbxproj
  171. +4 −1 src/Three20UINavigator/Sources/TTBaseNavigator.m
  172. +1 −1 src/Three20UINavigator/Sources/TTGlobalNavigatorMetrics.m
  173. +4 −2 src/Three20UINavigator/Sources/TTURLAction.m
  174. +4 −2 src/Three20UINavigator/Sources/TTURLGeneratorPattern.m
  175. +6 −3 src/Three20UINavigator/Sources/TTURLNavigatorPattern.m
  176. +2 −1 src/Three20UINavigator/Sources/TTURLPattern.m
  177. +2 −1 src/Three20UINavigator/Sources/TTURLSelector.m
  178. +2 −1 src/Three20UINavigator/Sources/TTURLWildcard.m
  179. +2 −1 src/Three20UINavigator/Sources/UIViewController+TTNavigator.m
  180. +0 −2 src/Three20UINavigator/Three20UINavigator.xcodeproj/project.pbxproj
  181. +45 −0 src/extThree20CSSStyle/Headers/TTCSSGlobalStyle.h
  182. +5 −0 src/extThree20CSSStyle/Headers/TTCSSStyleSheet.h
  183. +28 −0 src/extThree20CSSStyle/Headers/TTShadowStyleAdditions.h
  184. +55 −0 src/extThree20CSSStyle/Headers/TTTextStyleAdditions.h
  185. +27 −0 src/extThree20CSSStyle/Headers/UILabelAdditions.h
  186. +23 −0 src/extThree20CSSStyle/Headers/extThree20CSSStyle+Additions.h
  187. +1 −0 src/extThree20CSSStyle/Headers/extThree20CSSStyle.h
  188. +2 −9 src/extThree20CSSStyle/README.mdown
  189. +2 −1 src/extThree20CSSStyle/Sources/TTCSSParser.m
  190. +23 −7 src/extThree20CSSStyle/Sources/TTCSSStyleSheet.m
  191. +0 −5 src/extThree20CSSStyle/Sources/TTDefaultCSSStyleSheet.h
  192. +2 −8 src/extThree20CSSStyle/Sources/TTDefaultCSSStyleSheet.m
  193. +63 −0 src/extThree20CSSStyle/Sources/TTShadowStyleAdditions.m
  194. +130 −0 src/extThree20CSSStyle/Sources/TTTextStyleAdditions.m
  195. +73 −0 src/extThree20CSSStyle/Sources/UILabelAdditions.m
  196. +50 −0 src/extThree20CSSStyle/extThree20CSSStyle.xcodeproj/project.pbxproj
  197. +3 −0 src/extThree20JSON/Source/TTURLJSONResponse.m
  198. +61 −2 src/extThree20JSON/Vendors/JSON/Changes.markdown
  199. +14 −0 src/extThree20JSON/Vendors/JSON/Credits.markdown
  200. +28 −24 src/extThree20JSON/Vendors/JSON/JSON.h
  201. +61 −0 src/extThree20JSON/Vendors/JSON/NSObject+JSON.h
  202. +60 −0 src/extThree20JSON/Vendors/JSON/NSObject+JSON.m
  203. 0 src/extThree20JSON/Vendors/JSON/Readme.markdown
  204. +47 −20 src/extThree20JSON/Vendors/JSON/SBJsonParser.h
  205. +69 −465 src/extThree20JSON/Vendors/JSON/SBJsonParser.m
  206. +136 −0 src/extThree20JSON/Vendors/JSON/SBJsonStreamParser.h
  207. +317 −0 src/extThree20JSON/Vendors/JSON/SBJsonStreamParser.m
  208. +88 −0 src/extThree20JSON/Vendors/JSON/SBJsonStreamParserAdapter.h
  209. +175 −0 src/extThree20JSON/Vendors/JSON/SBJsonStreamParserAdapter.m
  210. +89 −0 src/extThree20JSON/Vendors/JSON/SBJsonStreamParserState.h
  211. +370 −0 src/extThree20JSON/Vendors/JSON/SBJsonStreamParserState.m
  212. +163 −0 src/extThree20JSON/Vendors/JSON/SBJsonStreamWriter.h
  213. +372 −0 src/extThree20JSON/Vendors/JSON/SBJsonStreamWriter.m
  214. +75 −0 src/extThree20JSON/Vendors/JSON/SBJsonStreamWriterState.h
  215. +132 −0 src/extThree20JSON/Vendors/JSON/SBJsonStreamWriterState.m
  216. +70 −0 src/extThree20JSON/Vendors/JSON/SBJsonTokeniser.h
  217. +508 −0 src/extThree20JSON/Vendors/JSON/SBJsonTokeniser.m
  218. +52 −47 src/extThree20JSON/Vendors/JSON/SBJsonWriter.h
  219. +58 −195 src/extThree20JSON/Vendors/JSON/SBJsonWriter.m
  220. +32 −0 src/extThree20JSON/Vendors/YAJL/GHKit/GHNSBundle+Utils.h
  221. +33 −0 src/extThree20JSON/Vendors/YAJL/GHKit/GHNSBundle+Utils.m
  222. +62 −0 src/extThree20JSON/Vendors/YAJL/NSBundle+YAJL.h
  223. +52 −0 src/extThree20JSON/Vendors/YAJL/NSBundle+YAJL.m
  224. +0 −1 src/extThree20JSON/Vendors/YAJL/NSObject+YAJL.m
  225. +47 −151 src/extThree20JSON/Vendors/YAJL/README.md
  226. +5 −1 src/extThree20JSON/Vendors/YAJL/YAJL.h
  227. +24 −0 src/extThree20JSON/Vendors/YAJL/YAJLDocument.h
  228. +9 −1 src/extThree20JSON/Vendors/YAJL/YAJLDocument.m
  229. +80 −2 src/extThree20JSON/extThree20JSON.xcodeproj/project.pbxproj
  230. +14 −6 src/scripts/Pbxproj.py
View
18 samples/Style/TTCSSStyleSheets/Classes/SampleCSSStyleSheet.h
@@ -0,0 +1,18 @@
+//
+// Copyright 2009-2011 Facebook
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+@interface SampleCSSStyleSheet : TTDefaultCSSStyleSheet {}
+@end
View
36 samples/Style/TTCSSStyleSheets/Classes/SampleCSSStyleSheet.m
@@ -0,0 +1,36 @@
+//
+// Copyright 2009-2011 Facebook
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "SampleCSSStyleSheet.h"
+
+@implementation SampleCSSStyleSheet
+
+- (TTStyle *)h3:(UIControlState)state {
+ return
+ [TTSolidFillStyle styleWithColor:TTCSSSTATE(@"h3", backgroundColor, state) next:
+ [TTTextStyle styleWithCssSelector:@"h3" forState:state next:
+ nil]];
+}
+
+- (TTStyle *)h4:(UIControlState)state {
+ return
+ [TTSolidFillStyle styleWithColor:TTCSSSTATE(@"h4text", backgroundColor, state) next:
+ [TTShadowStyle styleWithCssSelector:@"h4shadow" forState:state next:
+ [TTTextStyle styleWithCssSelector:@"h4text" forState:state next:
+ nil]]];
+}
+
+@end
View
2 samples/Style/TTCSSStyleSheets/Classes/StyleSheetViewController.h
@@ -16,8 +16,6 @@
@interface StyleSheetViewController : TTViewController {
@private
- TTCSSStyleSheet* _styleSheet;
-
BOOL _loadedSuccessfully;
}
View
68 samples/Style/TTCSSStyleSheets/Classes/StyleSheetViewController.m
@@ -16,6 +16,8 @@
#import "StyleSheetViewController.h"
+#import "SampleCSSStyleSheet.h"
+
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -25,26 +27,19 @@ @implementation StyleSheetViewController
///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
- if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
- _styleSheet = [[TTCSSStyleSheet alloc] init];
-
+ self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
+ if (self) {
+ SampleCSSStyleSheet *_styleSheet = [[[SampleCSSStyleSheet alloc] init] autorelease];
_loadedSuccessfully = [_styleSheet
- loadFromFilename:TTPathForBundleResource(@"stylesheet.css")];
+ addStyleSheetFromDisk:TTPathForBundleResource(@"stylesheet.css")];
+ [TTStyleSheet setGlobalStyleSheet:_styleSheet];
}
return self;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-- (void)dealloc {
- TT_RELEASE_SAFELY(_styleSheet);
-
- [super dealloc];
-}
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)loadView {
[super loadView];
@@ -55,23 +50,50 @@ - (void)loadView {
}
self.title = @"Three20 CSS extension";
+ self.view.backgroundColor = TTCSS(@"body", backgroundColor);
- self.view.backgroundColor = [_styleSheet backgroundColorWithCssSelector: @"body"
- forState: UIControlStateNormal];
-
+ // Using helper macro
UILabel* headerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
headerLabel.text = @"Header text";
- headerLabel.font = [_styleSheet fontWithCssSelector:@"h1" forState:UIControlStateNormal];
- headerLabel.textColor = [_styleSheet colorWithCssSelector:@"h1" forState:UIControlStateNormal];
- headerLabel.backgroundColor = [_styleSheet backgroundColorWithCssSelector: @"h1"
- forState: UIControlStateNormal];
- headerLabel.shadowColor = [_styleSheet textShadowColorWithCssSelector: @"h1"
- forState: UIControlStateNormal];
- headerLabel.shadowOffset = [_styleSheet textShadowOffsetWithCssSelector: @"h1"
- forState: UIControlStateNormal];
+ headerLabel.font = TTCSS(@"h1", font);
+ headerLabel.textColor = TTCSS(@"h1", color);
+ headerLabel.backgroundColor = TTCSS(@"h1", backgroundColor);
+ headerLabel.shadowColor = TTCSS(@"h1", shadowColor);
+ headerLabel.shadowOffset = TTCSS(@"h1", shadowOffset);
[headerLabel sizeToFit];
[self.view addSubview:headerLabel];
+
+ // Using UILabel addition
+ UILabel* headerLabel2 = [[UILabel alloc] initWithFrame:CGRectZero];
+ headerLabel2.text = @"Header 2 text";
+ [headerLabel2 applyCssSelector:@"h2"];
+ [headerLabel2 sizeToFit];
+ CGFloat top = headerLabel.frame.size.height;
+ CGRect frame = headerLabel2.frame;
+ frame.origin.y = top;
+ headerLabel2.frame = frame;
+ [self.view addSubview:headerLabel2];
+
+ // Using TTTextStyle addition
+ TTButton* headerLabel3 = [TTButton buttonWithStyle:@"h3:" title:@"Header 3 text"];
+ [headerLabel3 sizeToFit];
+ top += headerLabel2.frame.size.height;
+ frame = headerLabel3.frame;
+ frame.origin.y = top;
+ headerLabel3.frame = frame;
+ [self.view addSubview:headerLabel3];
+
+ // Using TTTextStyle + TTShadowStyle addition
+ TTButton* headerLabel4 = [TTButton buttonWithStyle:@"h4:" title:@"Header 4 text"];
+ [headerLabel4 sizeToFit];
+ top += headerLabel2.frame.size.height;
+ frame = headerLabel4.frame;
+ frame.origin.y = top;
+ headerLabel4.frame = frame;
+ [self.view addSubview:headerLabel4];
+
TT_RELEASE_SAFELY(headerLabel);
+ TT_RELEASE_SAFELY(headerLabel2);
}
View
2 samples/Style/TTCSSStyleSheets/Headers/TTCSSStyleSheets_Prefix.pch
@@ -6,6 +6,6 @@
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "Three20/Three20.h"
- #import "extThree20CSSStyle/extThree20CSSStyle.h"
+ #import "extThree20CSSStyle/extThree20CSSStyle+Additions.h"
#import "Atlas.h"
#endif
View
37 samples/Style/TTCSSStyleSheets/Resources/stylesheet.css
@@ -15,13 +15,44 @@
*/
body {
- background-color: #111;
+ background-color: #114;
}
h1 {
font-weight: bold;
font-size: 50pt;
- color: #666;
+ color: #FF6;
background-color: transparent;
- text-shadow: 1px 1px 1px #999; /* blur amount (3rd value) doesn't do anything */
+ text-shadow: 2px 2px 0px #F99;
}
+
+h2 {
+ font-size: 45pt;
+ color: white;
+ background-color: transparent;
+ text-shadow: 0px 1px 3px #9BF;
+}
+
+h3, h3:hover {
+ font-size: 35pt;
+ font-weight: bold;
+ color: white;
+ background-color: transparent;
+ text-shadow: 3px -3px 3px #99F;
+}
+
+h3:hover {
+ color: #99F;
+ text-shadow: 3px 3px 3px white;
+}
+
+h4text, h4text:hover {
+ color: white;
+ font-size: 35pt;
+ background-color: transparent;
+}
+
+h4text:hover { color: gray; }
+
+h4shadow { text-shadow: 3px 3px 4px rgba(0, 255, 0, .5); }
+h4shadow:hover { text-shadow: 0px 0px 4px green; }
View
6 samples/Style/TTCSSStyleSheets/TTCSSStyleSheets.xcodeproj/project.pbxproj
@@ -28,6 +28,7 @@
6E850FAE11B176F10071A4FD /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 6E850FAC11B176F10071A4FD /* Default.png */; };
6E850FAF11B176F10071A4FD /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 6E850FAD11B176F10071A4FD /* Icon.png */; };
6E850FB811B1795F0071A4FD /* Atlas.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E850FB711B1795F0071A4FD /* Atlas.m */; };
+ 90C3A1C1132BF66B00AC06A2 /* SampleCSSStyleSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 90C3A1C0132BF66B00AC06A2 /* SampleCSSStyleSheet.m */; };
EB383B6510BBF62B0000B2D2 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB383B6410BBF62B0000B2D2 /* QuartzCore.framework */; };
/* End PBXBuildFile section */
@@ -234,6 +235,8 @@
6E850FB711B1795F0071A4FD /* Atlas.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Atlas.m; sourceTree = "<group>"; };
6E8513D111B19B080071A4FD /* TTCSSStyleSheets_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TTCSSStyleSheets_Prefix.pch; path = Headers/TTCSSStyleSheets_Prefix.pch; sourceTree = "<group>"; };
6E8513D211B19B0E0071A4FD /* TTCSSStyleSheets-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "TTCSSStyleSheets-Info.plist"; sourceTree = "<group>"; };
+ 90C3A1BF132BF66B00AC06A2 /* SampleCSSStyleSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SampleCSSStyleSheet.h; sourceTree = "<group>"; };
+ 90C3A1C0132BF66B00AC06A2 /* SampleCSSStyleSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SampleCSSStyleSheet.m; sourceTree = "<group>"; };
EB383B6410BBF62B0000B2D2 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
@@ -268,6 +271,8 @@
1D3623250D0F684500981E51 /* AppDelegate.m */,
6E850FB611B1795F0071A4FD /* Atlas.h */,
6E850FB711B1795F0071A4FD /* Atlas.m */,
+ 90C3A1BF132BF66B00AC06A2 /* SampleCSSStyleSheet.h */,
+ 90C3A1C0132BF66B00AC06A2 /* SampleCSSStyleSheet.m */,
);
path = Classes;
sourceTree = "<group>";
@@ -680,6 +685,7 @@
1D3623260D0F684500981E51 /* AppDelegate.m in Sources */,
6E850FB811B1795F0071A4FD /* Atlas.m in Sources */,
6E036BF811B38F3C0025E8EE /* StyleSheetViewController.m in Sources */,
+ 90C3A1C1132BF66B00AC06A2 /* SampleCSSStyleSheet.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
9 samples/TTCatalog/Classes/ImageTest1Controller.m
@@ -3,6 +3,8 @@
@implementation ImageTest1Controller
+static NSString * kDataUrlImage = @"data:image/png;base64,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";
+
- (void)loadView {
self.view = [[[UIView alloc] init] autorelease];
self.view.backgroundColor = [UIColor whiteColor];
@@ -12,6 +14,13 @@ - (void)loadView {
imageView.autoresizesToImage = YES;
imageView.urlPath = @"http://farm4.static.flickr.com/3163/3110335722_7a906f9d8b_m.jpg";
[self.view addSubview:imageView];
+
+ TTImageView* dataImageView = [[[TTImageView alloc] initWithFrame:CGRectMake(130, 200, 0, 0)]
+ autorelease];
+ dataImageView.autoresizesToImage = YES;
+ dataImageView.urlPath = kDataUrlImage;
+ [self.view addSubview:dataImageView];
+
}
- (void)dealloc {
View
62 samples/TTCatalog/Classes/StyleTestController.m
@@ -45,20 +45,49 @@ - (void)loadView {
[TTSolidFillStyle styleWithColor:[UIColor whiteColor] next:
[TTSolidBorderStyle styleWithColor:black width:1 next:nil]]],
- // SpeechBubble
- [TTShapeStyle styleWithShape:[TTSpeechBubbleShape shapeWithRadius:5 pointLocation:60
- pointAngle:90
- pointSize:CGSizeMake(20,10)] next:
- [TTSolidFillStyle styleWithColor:[UIColor whiteColor] next:
- [TTSolidBorderStyle styleWithColor:black width:1 next:nil]]],
-
- // SpeechBubble
- [TTShapeStyle styleWithShape:[TTSpeechBubbleShape shapeWithRadius:5 pointLocation:290
- pointAngle:270
- pointSize:CGSizeMake(20,10)] next:
- [TTSolidFillStyle styleWithColor:[UIColor whiteColor] next:
- [TTSolidBorderStyle styleWithColor:black width:1 next:nil]]],
-
+ // SpeechBubble with pointer left of the centre on the top edge
+ // Locations for top edge are 45 on the left, 90 in the centre, 134.999 on the right
+ [TTShapeStyle styleWithShape:[TTSpeechBubbleShape shapeWithRadius:5
+ pointLocation:60
+ pointAngle:90
+ pointSize:CGSizeMake(20,10)] next:
+ [TTSolidFillStyle styleWithColor:[UIColor whiteColor] next:
+ [TTSolidBorderStyle styleWithColor:black width:1 next:nil]]],
+
+ // SpeechBubble with pointer on the extreme left on the bottom edge
+ // Locations for bottom edge are 225 on the left, 270 in the centre, 314.999 on the left
+ [TTShapeStyle styleWithShape:[TTSpeechBubbleShape shapeWithRadius:5
+ pointLocation:314
+ pointAngle:270
+ pointSize:CGSizeMake(20,10)] next:
+ [TTSolidFillStyle styleWithColor:[UIColor whiteColor] next:
+ [TTSolidBorderStyle styleWithColor:black width:1 next:nil]]],
+
+ // SpeechBubble with pointer on the bottom of the left edge
+ // Locations for left edge are 315 on the bottom, 0 in the centre, 44.999 on top
+ [TTShapeStyle styleWithShape:[TTSpeechBubbleShape shapeWithRadius:5
+ pointLocation:315
+ pointAngle:0
+ pointSize:CGSizeMake(10,20)] next:
+ [TTSolidFillStyle styleWithColor:[UIColor whiteColor] next:
+ [TTSolidBorderStyle styleWithColor:black width:1 next:nil]]],
+
+ // SpeechBubble with pointer on the centre of the left edge
+ // Locations for left edge are 315 on the bottom, 0 in the centre, 44.999 on top
+ [TTShapeStyle styleWithShape:[TTSpeechBubbleShape shapeWithRadius:5 pointLocation:0
+ pointAngle:0
+ pointSize:CGSizeMake(20,10)] next:
+ [TTSolidFillStyle styleWithColor:[UIColor whiteColor] next:
+ [TTSolidBorderStyle styleWithColor:black width:1 next:nil]]],
+
+ // SpeechBubble with pointer on the bottom of the right hand edge
+ // Locations for right edge are 135 on top, 180 in the middle, 314.999 on the bottom
+ [TTShapeStyle styleWithShape:[TTSpeechBubbleShape shapeWithRadius:5 pointLocation:224
+ pointAngle:180
+ pointSize:CGSizeMake(15,15)] next:
+ [TTSolidFillStyle styleWithColor:[UIColor whiteColor] next:
+ [TTSolidBorderStyle styleWithColor:black width:1 next:nil]]],
+
// Drop shadow
[TTShapeStyle styleWithShape:[TTRoundedRectangleShape shapeWithRadius:10] next:
[TTShadowStyle styleWithColor:RGBACOLOR(0,0,0,0.5) blur:5 offset:CGSizeMake(2, 2) next:
@@ -121,6 +150,11 @@ - (void)loadView {
[TTLinearGradientFillStyle styleWithColor1:RGBCOLOR(0, 180, 231)
color2:RGBCOLOR(0, 0, 255) next:nil]],
+ // simple bottom only border
+ [TTShapeStyle styleWithShape:[TTRectangleShape shape] next:
+ [TTSolidFillStyle styleWithColor:RGBCOLOR(255, 255, 255) next:
+ [TTFourBorderStyle styleWithTop:nil right:nil bottom:black left:nil width:5 next:nil]]],
+
nil];
CGFloat padding = 10;
View
1 samples/TTCatalog/Classes/StyledTextTestController.m
@@ -114,6 +114,7 @@ - (void)loadView {
label1.text = [TTStyledText textFromXHTML:kText lineBreaks:YES URLs:YES];
label1.contentInset = UIEdgeInsetsMake(10, 10, 10, 10);
//label1.backgroundColor = [UIColor grayColor];
+ //label1.textAlignment = UITextAlignmentCenter;
[label1 sizeToFit];
[self.view addSubview:label1];
}
View
BIN src/Three20.bundle/cs.lproj/Localizable.strings
Binary file not shown.
View
BIN src/Three20.bundle/he.lproj/Localizable.strings
Binary file not shown.
View
6 src/Three20/Headers/Three20.h
@@ -14,12 +14,6 @@
// limitations under the License.
//
-/*! \mainpage Three20 API Documentation
- *
- * Generated from Three20 Release <a href="http://three20.info/roadmap/1.0.5">1.0.5</a>.
- *
- */
-
// Core
#import "Three20Core/Three20Core.h"
View
2 src/Three20/Three20.xcodeproj/project.pbxproj
@@ -828,7 +828,6 @@
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
- GCC_PREFIX_HEADER = "$(SRCROOT)/../common/Xcode324iOS41Fix.pch";
GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
PREBINDING = NO;
PRODUCT_NAME = "$(BASE_PRODUCT_NAME)";
@@ -846,7 +845,6 @@
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
- GCC_PREFIX_HEADER = "$(SRCROOT)/../common/Xcode324iOS41Fix.pch";
PREBINDING = NO;
PRODUCT_NAME = "$(BASE_PRODUCT_NAME)";
SDKROOT = iphoneos;
View
15 src/Three20Core/Headers/NSDataAdditions.h
@@ -32,4 +32,19 @@
*/
@property (nonatomic, readonly) NSString* sha1Hash;
+
+/**
+ * Create an NSData from a base64 encoded representation
+ *
+ * @return the NSData object
+ */
++ (id)dataWithBase64EncodedString:(NSString *)string; // Padding '=' characters are optional. Whitespace is ignored.
+
+/**
+ * Marshal the data into a base64 encoded representation
+ *
+ * @return the base64 encoded string
+ */
+- (NSString *)base64Encoding;
+
@end
View
5 src/Three20Core/Headers/NSStringAdditions.h
@@ -69,6 +69,11 @@
- (NSString*)stringByAddingQueryDictionary:(NSDictionary*)query;
/**
+ * Returns a URL Encoded String
+ */
+- (NSString*)urlEncoded;
+
+/**
* Returns a string with all HTML tags removed.
*/
- (NSString*)stringByRemovingHTMLTags;
View
75 src/Three20Core/Headers/Three20.h
@@ -0,0 +1,75 @@
+//
+// Copyright 2009-2011 Facebook
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ * General-purpose information about the Three20 ecosystem.
+ *
+ * This information is present in the core because Three20 versioning is done across all of
+ * the primary Three20 modules.
+ *
+ * This is the only object in the Three20 ecosystem that doesn't follow the standard TT* prefix.
+ * This is by design. [Three20 version] is much clearer than [TTVersion version].
+ */
+@interface Three20 : NSObject
+
+
+#pragma mark -
+#pragma mark General Purpose Version Information
+
+/**
+ * @see Three20Version
+ */
++ (NSString*)version;
+
+
+#pragma mark -
+#pragma mark Version Breakdown
+
+/**
+ * Major release number.
+ *
+ * Major releases involve large structural changes that will break compatibility
+ * with older versions.
+ */
++ (NSInteger)majorVersion;
+
+/**
+ * Minor release number.
+ *
+ * Minor releases involve minimal structural changes that might break compatibility
+ * with older versions but should only involve minimal effort to transition to.
+ */
++ (NSInteger)minorVersion;
+
+/**
+ * Bugfix release number.
+ *
+ * Bugfix releases involve no structural modifications, but may introduce new code and
+ * fix existing bugs.
+ */
++ (NSInteger)bugfixVersion;
+
+/**
+ * Hotfix release number.
+ *
+ * Hotfix releases fix crashing bugs and compilation errors that may have slipped through the
+ * release process.
+ */
++ (NSInteger)hotfixVersion;
+
+@end
View
2 src/Three20Core/Headers/Three20Core.h
@@ -19,6 +19,8 @@
// - Global
#import "Three20Core/TTCorePreprocessorMacros.h"
+#import "Three20Core/Three20.h"
+#import "Three20Core/Three20Version.h"
#import "Three20Core/TTGlobalCore.h"
#import "Three20Core/TTGlobalCoreLocale.h"
#import "Three20Core/TTGlobalCorePaths.h"
View
33 src/Three20Core/Headers/Three20Version.h
@@ -0,0 +1,33 @@
+//
+// Copyright 2009-2011 Facebook
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ * Expressed in MAJOR.MINOR.BUGFIX(.HOTFIX) notation.
+ *
+ * For example, 1.0.5.1 is:
+ * - the first major release,
+ * - with no minor updates,
+ * - with 5 bugfix patches,
+ * - and 1 hotfix patch.
+ *
+ * The .HOTFIX version will only be present if hotfixVersion is > 0.
+ *
+ * Check out the versionStringCompare: addition to NSString if you need to compare Three20
+ * versions. You will need to import Three20+Additions.h in order to use it.
+ */
+extern NSString* const Three20Version;
View
104 src/Three20Core/Sources/NSDataAdditions.m
@@ -59,4 +59,108 @@ - (NSString*)sha1Hash {
];
}
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// base64 code found on http://www.cocoadev.com/index.pl?BaseSixtyFour
+// where the poster released it to public domain
+// style not exactly congruous with normal three20 style, but kept mostly intact with the original
+static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
++ (NSData*)dataWithBase64EncodedString:(NSString *)string;
+{
+ if ([string length] == 0)
+ return [NSData data];
+
+ static char *decodingTable = NULL;
+ if (decodingTable == NULL)
+ {
+ decodingTable = malloc(256);
+ if (decodingTable == NULL)
+ return nil;
+ memset(decodingTable, CHAR_MAX, 256);
+ NSUInteger i;
+ for (i = 0; i < 64; i++)
+ decodingTable[(short)encodingTable[i]] = i;
+ }
+
+ const char *characters = [string cStringUsingEncoding:NSASCIIStringEncoding];
+ if (characters == NULL) // Not an ASCII string!
+ return nil;
+ char *bytes = malloc((([string length] + 3) / 4) * 3);
+ if (bytes == NULL)
+ return nil;
+ NSUInteger length = 0;
+
+ NSUInteger i = 0;
+ while (YES)
+ {
+ char buffer[4];
+ short bufferLength;
+ for (bufferLength = 0; bufferLength < 4; i++)
+ {
+ if (characters[i] == '\0')
+ break;
+ if (isspace(characters[i]) || characters[i] == '=')
+ continue;
+ buffer[bufferLength] = decodingTable[(short)characters[i]];
+ if (buffer[bufferLength++] == CHAR_MAX) // Illegal character!
+ {
+ free(bytes);
+ return nil;
+ }
+ }
+
+ if (bufferLength == 0)
+ break;
+ if (bufferLength == 1) // At least two characters are needed to produce one byte!
+ {
+ free(bytes);
+ return nil;
+ }
+
+ // Decode the characters in the buffer to bytes.
+ bytes[length++] = (buffer[0] << 2) | (buffer[1] >> 4);
+ if (bufferLength > 2)
+ bytes[length++] = (buffer[1] << 4) | (buffer[2] >> 2);
+ if (bufferLength > 3)
+ bytes[length++] = (buffer[2] << 6) | buffer[3];
+ }
+
+ realloc(bytes, length);
+ return [NSData dataWithBytesNoCopy:bytes length:length];
+}
+
+- (NSString *)base64Encoding;
+{
+ if ([self length] == 0)
+ return @"";
+
+ char *characters = malloc((([self length] + 2) / 3) * 4);
+ if (characters == NULL)
+ return nil;
+ NSUInteger length = 0;
+
+ NSUInteger i = 0;
+ while (i < [self length])
+ {
+ char buffer[3] = {0,0,0};
+ short bufferLength = 0;
+ while (bufferLength < 3 && i < [self length])
+ buffer[bufferLength++] = ((char *)[self bytes])[i++];
+
+ // Encode the bytes in the buffer to four characters, including padding "=" characters if necessary.
+ characters[length++] = encodingTable[(buffer[0] & 0xFC) >> 2];
+ characters[length++] = encodingTable[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xF0) >> 4)];
+ if (bufferLength > 1)
+ characters[length++] = encodingTable[((buffer[1] & 0x0F) << 2) | ((buffer[2] & 0xC0) >> 6)];
+ else characters[length++] = '=';
+ if (bufferLength > 2)
+ characters[length++] = encodingTable[buffer[2] & 0x3F];
+ else characters[length++] = '=';
+ }
+
+ return [[[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES] autorelease];
+}
+// end recycled base64 code
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
@end
View
87 src/Three20Core/Sources/NSDateAdditions.m
@@ -40,14 +40,7 @@ @implementation NSDate (TTCategory)
///////////////////////////////////////////////////////////////////////////////////////////////////
+ (NSDate*)dateWithToday {
- NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
- formatter.dateFormat = @"yyyy-d-M";
-
- NSString* formattedTime = [formatter stringFromDate:[NSDate date]];
- NSDate* date = [formatter dateFromString:formattedTime];
- TT_RELEASE_SAFELY(formatter);
-
- return date;
+ return [[NSDate date] dateAtMidnight];
}
@@ -59,14 +52,11 @@ + (NSDate*)dateWithToday {
///////////////////////////////////////////////////////////////////////////////////////////////////
- (NSDate*)dateAtMidnight {
- NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
- formatter.dateFormat = @"yyyy-d-M";
-
- NSString* formattedTime = [formatter stringFromDate:self];
- NSDate* date = [formatter dateFromString:formattedTime];
- TT_RELEASE_SAFELY(formatter);
-
- return date;
+ NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
+ NSDateComponents *comps = [gregorian components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit) fromDate:[NSDate date]];
+ NSDate *midnight = [gregorian dateFromComponents:comps];
+ [gregorian release];
+ return midnight;
}
@@ -152,30 +142,59 @@ - (NSString*)formatDateTime {
///////////////////////////////////////////////////////////////////////////////////////////////////
- (NSString*)formatRelativeTime {
- NSTimeInterval elapsed = abs([self timeIntervalSinceNow]);
- if (elapsed <= 1) {
- return TTLocalizedString(@"just a moment ago", @"");
+ NSTimeInterval elapsed = [self timeIntervalSinceNow];
+ if (elapsed > 0) {
+ if (elapsed <= 1) {
+ return TTLocalizedString(@"in just a moment", @"");
+
+ } else if (elapsed < TT_MINUTE) {
+ int seconds = (int)(elapsed);
+ return [NSString stringWithFormat:TTLocalizedString(@"in %d seconds", @""), seconds];
+
+ } else if (elapsed < 2*TT_MINUTE) {
+ return TTLocalizedString(@"in about a minute", @"");
+
+ } else if (elapsed < TT_HOUR) {
+ int mins = (int)(elapsed/TT_MINUTE);
+ return [NSString stringWithFormat:TTLocalizedString(@"in %d minutes", @""), mins];
+
+ } else if (elapsed < TT_HOUR*1.5) {
+ return TTLocalizedString(@"in about an hour", @"");
+
+ } else if (elapsed < TT_DAY) {
+ int hours = (int)((elapsed+TT_HOUR/2)/TT_HOUR);
+ return [NSString stringWithFormat:TTLocalizedString(@"in %d hours", @""), hours];
+
+ } else {
+ return [self formatDateTime];
+ }
+ } else {
+ elapsed = -elapsed;
+
+ if (elapsed <= 1) {
+ return TTLocalizedString(@"just a moment ago", @"");
- } else if (elapsed < TT_MINUTE) {
- int seconds = (int)(elapsed);
- return [NSString stringWithFormat:TTLocalizedString(@"%d seconds ago", @""), seconds];
+ } else if (elapsed < TT_MINUTE) {
+ int seconds = (int)(elapsed);
+ return [NSString stringWithFormat:TTLocalizedString(@"%d seconds ago", @""), seconds];
- } else if (elapsed < 2*TT_MINUTE) {
- return TTLocalizedString(@"about a minute ago", @"");
+ } else if (elapsed < 2*TT_MINUTE) {
+ return TTLocalizedString(@"about a minute ago", @"");
- } else if (elapsed < TT_HOUR) {
- int mins = (int)(elapsed/TT_MINUTE);
- return [NSString stringWithFormat:TTLocalizedString(@"%d minutes ago", @""), mins];
+ } else if (elapsed < TT_HOUR) {
+ int mins = (int)(elapsed/TT_MINUTE);
+ return [NSString stringWithFormat:TTLocalizedString(@"%d minutes ago", @""), mins];
- } else if (elapsed < TT_HOUR*1.5) {
- return TTLocalizedString(@"about an hour ago", @"");
+ } else if (elapsed < TT_HOUR*1.5) {
+ return TTLocalizedString(@"about an hour ago", @"");
- } else if (elapsed < TT_DAY) {
- int hours = (int)((elapsed+TT_HOUR/2)/TT_HOUR);
- return [NSString stringWithFormat:TTLocalizedString(@"%d hours ago", @""), hours];
+ } else if (elapsed < TT_DAY) {
+ int hours = (int)((elapsed+TT_HOUR/2)/TT_HOUR);
+ return [NSString stringWithFormat:TTLocalizedString(@"%d hours ago", @""), hours];
- } else {
- return [self formatDateTime];
+ } else {
+ return [self formatDateTime];
+ }
}
}
View
10 src/Three20Core/Sources/NSStringAdditions.m
@@ -141,6 +141,16 @@ - (NSString*)stringByAddingQueryDictionary:(NSDictionary*)query {
}
}
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (id)urlEncoded {
+ CFStringRef cfUrlEncodedString = CFURLCreateStringByAddingPercentEscapes(NULL,
+ (CFStringRef)self,
+ NULL, (CFStringRef)@"!*’();:@&=$,/?%#[]",
+ kCFStringEncodingUTF8);
+ NSString *urlEncoded = [NSString stringWithString:(NSString *)cfUrlEncodedString];
+ CFRelease(cfUrlEncodedString);
+ return urlEncoded;
+}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (NSComparisonResult)versionStringCompare:(NSString *)other {
View
3 src/Three20Core/Sources/TTExtensionAuthor.m
@@ -57,7 +57,8 @@ - (id)initWithName: (NSString*)name
github: (NSString*)github
twitter: (NSString*)twitter
website: (NSString*)website {
- if (self = [super init]) {
+ self = [super init];
+ if (self) {
self.name = name;
self.github = github;
self.twitter = twitter;
View
3 src/Three20Core/Sources/TTExtensionInfo.m
@@ -39,7 +39,8 @@ @implementation TTExtensionInfo
///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)init {
- if (self = [super init]) {
+ self = [super init];
+ if (self) {
self.version = @"No version provided.";
self.description = @"No description provided.";
self.copyright = @"No copyright provided.";
View
64 src/Three20Core/Sources/Three20.m
@@ -0,0 +1,64 @@
+//
+// Copyright 2009-2011 Facebook
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "Three20Core/Three20.h"
+
+#import "Three20Core/Three20Version.h"
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+@implementation Three20
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (NSInteger)majorVersion {
+ return [[[Three20Version componentsSeparatedByString:@"."] objectAtIndex:0] intValue];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (NSInteger)minorVersion {
+ return [[[Three20Version componentsSeparatedByString:@"."] objectAtIndex:1] intValue];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (NSInteger)bugfixVersion {
+ return [[[Three20Version componentsSeparatedByString:@"."] objectAtIndex:2] intValue];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (NSInteger)hotfixVersion {
+ NSArray* components = [Three20Version componentsSeparatedByString:@"."];
+ if ([components count] > 3) {
+ return [[components objectAtIndex:3] intValue];
+
+ } else {
+ return 0;
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (NSString*)version {
+ return Three20Version;
+}
+
+
+@end
View
23 src/Three20Core/Sources/Three20Version.m
@@ -0,0 +1,23 @@
+//
+// Copyright 2009-2011 Facebook
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "Three20Core/Three20Version.h"
+
+/*! \mainpage Three20 API Documentation
+ *
+ * Generated from Three20 Release <a href="http://three20.info/roadmap/1.0.5">1.0.5</a>.
+ */
+NSString* const Three20Version = @"1.0.5";
View
19 src/Three20Core/Three20Core.xcodeproj/project.pbxproj
@@ -7,11 +7,15 @@
objects = {
/* Begin PBXBuildFile section */
+ 660E7375135A560A00531398 /* Three20Version.h in Headers */ = {isa = PBXBuildFile; fileRef = 660E7374135A560A00531398 /* Three20Version.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 66A0530A132EB47900132434 /* Three20.m in Sources */ = {isa = PBXBuildFile; fileRef = 66A05309132EB47900132434 /* Three20.m */; };
+ 66A0530C132EB47F00132434 /* Three20.h in Headers */ = {isa = PBXBuildFile; fileRef = 66A0530B132EB47F00132434 /* Three20.h */; settings = {ATTRIBUTES = (Public, ); }; };
66ADC9091290B23A00855386 /* TTExtensionInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 66ADC9071290B23A00855386 /* TTExtensionInfo.m */; };
66ADC90F1290B24D00855386 /* TTExtensionInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 66ADC90E1290B24D00855386 /* TTExtensionInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
66ADCE681291BC1E00855386 /* TTExtensionInfoPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 66ADCE661291BC1E00855386 /* TTExtensionInfoPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
66ADCE871291BEAE00855386 /* TTExtensionAuthor.m in Sources */ = {isa = PBXBuildFile; fileRef = 66ADCE811291BEAE00855386 /* TTExtensionAuthor.m */; };
66ADCE8B1291BEBB00855386 /* TTExtensionAuthor.h in Headers */ = {isa = PBXBuildFile; fileRef = 66ADCE881291BEBB00855386 /* TTExtensionAuthor.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 66CE68FB135B320F00E127E2 /* Three20Version.m in Sources */ = {isa = PBXBuildFile; fileRef = 66CE68FA135B320F00E127E2 /* Three20Version.m */; };
66ECA257128DFE28006C78C2 /* TTExtensionLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 66ECA251128DFE28006C78C2 /* TTExtensionLoader.m */; };
66ECA25B128DFE34006C78C2 /* TTExtensionLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 66ECA258128DFE34006C78C2 /* TTExtensionLoader.h */; settings = {ATTRIBUTES = (Public, ); }; };
6E178E811183C8E5003B099E /* TTGlobalCore.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E178E7B1183C8E5003B099E /* TTGlobalCore.m */; };
@@ -63,11 +67,15 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
+ 660E7374135A560A00531398 /* Three20Version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Three20Version.h; path = Headers/Three20Version.h; sourceTree = "<group>"; };
+ 66A05309132EB47900132434 /* Three20.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Three20.m; path = Sources/Three20.m; sourceTree = "<group>"; };
+ 66A0530B132EB47F00132434 /* Three20.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Three20.h; path = Headers/Three20.h; sourceTree = "<group>"; };
66ADC9071290B23A00855386 /* TTExtensionInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TTExtensionInfo.m; path = Sources/TTExtensionInfo.m; sourceTree = "<group>"; };
66ADC90E1290B24D00855386 /* TTExtensionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TTExtensionInfo.h; path = Headers/TTExtensionInfo.h; sourceTree = "<group>"; };
66ADCE661291BC1E00855386 /* TTExtensionInfoPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TTExtensionInfoPrivate.h; path = Headers/TTExtensionInfoPrivate.h; sourceTree = "<group>"; };
66ADCE811291BEAE00855386 /* TTExtensionAuthor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TTExtensionAuthor.m; path = Sources/TTExtensionAuthor.m; sourceTree = "<group>"; };
66ADCE881291BEBB00855386 /* TTExtensionAuthor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TTExtensionAuthor.h; path = Headers/TTExtensionAuthor.h; sourceTree = "<group>"; };
+ 66CE68FA135B320F00E127E2 /* Three20Version.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Three20Version.m; path = Sources/Three20Version.m; sourceTree = "<group>"; };
66ECA251128DFE28006C78C2 /* TTExtensionLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TTExtensionLoader.m; path = Sources/TTExtensionLoader.m; sourceTree = "<group>"; };
66ECA258128DFE34006C78C2 /* TTExtensionLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TTExtensionLoader.h; path = Headers/TTExtensionLoader.h; sourceTree = "<group>"; };
6E178E751183C8AE003B099E /* Three20Core_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Three20Core_Prefix.pch; path = Headers/Three20Core_Prefix.pch; sourceTree = "<group>"; };
@@ -224,6 +232,10 @@
6ED117D21183BDBF0096AEBF /* Global */ = {
isa = PBXGroup;
children = (
+ 660E7374135A560A00531398 /* Three20Version.h */,
+ 66CE68FA135B320F00E127E2 /* Three20Version.m */,
+ 66A0530B132EB47F00132434 /* Three20.h */,
+ 66A05309132EB47900132434 /* Three20.m */,
6E178E771183C8D3003B099E /* TTCorePreprocessorMacros.h */,
6E178E781183C8DA003B099E /* TTGlobalCore.h */,
6E178E7B1183C8E5003B099E /* TTGlobalCore.m */,
@@ -334,6 +346,8 @@
66ADC90F1290B24D00855386 /* TTExtensionInfo.h in Headers */,
66ADCE681291BC1E00855386 /* TTExtensionInfoPrivate.h in Headers */,
66ADCE8B1291BEBB00855386 /* TTExtensionAuthor.h in Headers */,
+ 66A0530C132EB47F00132434 /* Three20.h in Headers */,
+ 660E7375135A560A00531398 /* Three20Version.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -483,6 +497,8 @@
66ECA257128DFE28006C78C2 /* TTExtensionLoader.m in Sources */,
66ADC9091290B23A00855386 /* TTExtensionInfo.m in Sources */,
66ADCE871291BEAE00855386 /* TTExtensionAuthor.m in Sources */,
+ 66A0530A132EB47900132434 /* Three20.m in Sources */,
+ 66CE68FB135B320F00E127E2 /* Three20Version.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -546,7 +562,6 @@
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = NO;
- GCC_PREFIX_HEADER = "";
GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
PREBINDING = NO;
SDKROOT = iphoneos;
@@ -616,7 +631,6 @@
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
- GCC_PREFIX_HEADER = "$(SRCROOT)/../common/Xcode324iOS41Fix.pch";
GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
PREBINDING = NO;
SDKROOT = iphoneos;
@@ -632,7 +646,6 @@
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
- GCC_PREFIX_HEADER = "$(SRCROOT)/../common/Xcode324iOS41Fix.pch";
PREBINDING = NO;
SDKROOT = iphoneos;
ZERO_LINK = NO;
View
23 src/Three20Core/UnitTests/CoreGlobalTests.m
@@ -19,6 +19,8 @@
#import <SenTestingKit/SenTestingKit.h>
// Core
+#import "Three20Core/Three20.h"
+#import "Three20Core/Three20Version.h"
#import "Three20Core/TTCorePreprocessorMacros.h"
#import "Three20Core/TTGlobalCorePaths.h"
#import "Three20Core/TTGlobalCore.h"
@@ -50,6 +52,27 @@ - (void)testSuccess {
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
+#pragma mark Versioning
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)testThree20Versioning {
+ STAssertTrue([[Three20 version] isEqualToString:Three20Version],
+ @"The latest version has not been updated correctly.");
+ STAssertEquals([Three20 majorVersion], 1,
+ @"The latest major version has not been updated correctly.");
+ STAssertEquals([Three20 minorVersion], 0,
+ @"The latest minor version has not been updated correctly.");
+ STAssertEquals([Three20 bugfixVersion], 5,
+ @"The latest bugfix version has not been updated correctly.");
+ STAssertEquals([Three20 hotfixVersion], 0,
+ @"The latest hotfix version has not been updated correctly.");
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
#pragma mark Macros
View
2 src/Three20Network/Headers/TTErrorCodes.h
@@ -18,4 +18,4 @@
extern NSString* const kTTNetworkErrorDomain;
extern NSInteger const kTTNetworkErrorCodeInvalidImage;
-
+extern NSString* const kTTErrorResponseDataKey;
View
49 src/Three20Network/Headers/TTURLRequest.h
@@ -22,6 +22,14 @@
// Core
#import "Three20Core/TTCorePreprocessorMacros.h" // For __TTDEPRECATED_METHOD
+/**
+ * A constant to improve code readabillity, when using negative numbers for
+ * timeoutInterval.
+ *
+ * @see timeoutInterval
+ */
+extern const NSTimeInterval TTURLRequestUseQueueTimeout;
+
@protocol TTURLRequestDelegate;
@protocol TTURLResponse;
@@ -54,6 +62,8 @@
NSInteger _totalBytesLoaded;
NSInteger _totalBytesExpected;
+
+ NSTimeInterval _timeoutInterval;
NSInteger _totalBytesDownloaded;
NSInteger _totalContentLength;
@@ -64,6 +74,7 @@
BOOL _shouldHandleCookies;
BOOL _respondedFromCache;
BOOL _filterPasswordLogging;
+ BOOL _multiPartForm;
NSMutableArray* _delegates;
}
@@ -174,12 +185,12 @@
@property (nonatomic) BOOL shouldHandleCookies;
/**
- * The number of bytes loaded by this request.
+ * The number of request body bytes already uploaded by this request.
*/
@property (nonatomic) NSInteger totalBytesLoaded;
/**
- * The number of expected bytes from this request.
+ * The total number of request body bytes expected to be uploaded for this request.
*/
@property (nonatomic) NSInteger totalBytesExpected;
@@ -194,6 +205,35 @@
@property (nonatomic) NSInteger totalContentLength;
/**
+ * The timeout to use for the request.
+ *
+ * If a negative value is set the request uses
+ * the defaultTimeout of the TTURLRequestQueue. <b>This differs from behaviour of
+ * NSURLRequest.</b> Given a negative timeoutInterval NSURLRequest always fails.
+ *
+ * You should use the TTURLRequestUseQueueTimeout constant to improve
+ * code readabillity, instead of negative numbers.
+ *
+ * The default value is TTURLRequestUseQueueTimeout
+ *
+ * @par from NSURLRequest.h:
+ *
+ * The timeout interval specifies the limit on the idle
+ * interval alloted to a request in the process of loading. The "idle
+ * interval" is defined as the period of time that has passed since the
+ * last instance of load activity occurred for a request that is in the
+ * process of loading. Hence, when an instance of load activity occurs
+ * (e.g. bytes are received from the network for a request), the idle
+ * interval for a request is reset to 0. If the idle interval ever
+ * becomes greater than or equal to the timeout interval, the request
+ * is considered to have timed out. This timeout interval is measured
+ * in seconds.
+ *
+ * @see TTURLRequestQueue::defaultTimeout
+ */
+@property (nonatomic) NSTimeInterval timeoutInterval;
+
+/**
* Whether or not the request was loaded from the cache.
*
* This is only valid after the request has completed.
@@ -217,6 +257,11 @@
*/
@property (nonatomic, readonly) NSMutableArray* delegates;
+/**
+ * Determine whether to construct a multipart form or to instead encode the http body as the W3C default
+ * of application/x-www-form-urlencoded
+ */
+@property (nonatomic, assign) BOOL multiPartForm;
+ (TTURLRequest*)request;
View
14 src/Three20Network/Headers/TTURLRequestQueue.h
@@ -32,6 +32,8 @@
NSString* _userAgent;
CGFloat _imageCompressionQuality;
+
+ NSTimeInterval _defaultTimeout;
BOOL _suspended;
}
@@ -72,6 +74,18 @@
*/
@property (nonatomic) CGFloat imageCompressionQuality;
+
+/**
+ * The default Timeout used for all TTURLRequests.
+ *
+ * This timeout is applied to all requests that have a negative timeout set.
+ *
+ * The default value is defined as kTimeout in TTURLRequestQueue.m
+ *
+ * @see TTURLRequest::timeoutInterval
+ */
+@property (nonatomic) NSTimeInterval defaultTimeout;
+
/**
* Get the shared cache singleton used across the application.
*/
View
13 src/Three20Network/Headers/TTURLResponse.h
@@ -45,4 +45,17 @@
- (NSError*)request:(TTURLRequest*)request processResponse:(NSHTTPURLResponse*)response
data:(id)data;
+@optional
+/**
+ * Processes the data from a unsuccessful request to construct a custom NSError object.
+ *
+ * @param request The request this response is bound to.
+ * @param response The response object, useful for getting the status code.
+ * @param data The data received from the TTURLRequest.
+ * @return NSError to construct for this response.
+ *
+ * @optional
+ */
+- (NSError*)request:(TTURLRequest*)request processErrorResponse:(NSHTTPURLResponse*)response
+ data:(id)data;
@end
View
127 src/Three20Network/NetworkRequestTimeoutTests.m
@@ -0,0 +1,127 @@
+//
+// Copyright 2009-2011 Facebook
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// See: http://developer.apple.com/iphone/library/documentation/Xcode/Conceptual/iphone_development/905-A-Unit-Test_Result_Macro_Reference/unit-test_results.html#//apple_ref/doc/uid/TP40007959-CH21-SW2
+// for unit test macros.
+
+// See Also: http://developer.apple.com/iphone/library/documentation/Xcode/Conceptual/iphone_development/135-Unit_Testing_Applications/unit_testing_applications.html
+
+#import <SenTestingKit/SenTestingKit.h>
+
+// Network
+#import "Three20Network/TTURLRequest.h"
+#import "Three20Network/TTURLRequestQueue.h"
+
+// Core
+#import "Three20Core/TTGlobalCorePaths.h"
+
+// duplicate constant for testing declared in Three20Network/TTURLRequestQueue.h
+static const NSTimeInterval kTimeout = 300.0;
+
+/**
+ * Unit tests for configurable request timeouts.
+ *
+ */
+
+@interface NetworkRequestTimeout : SenTestCase {
+}
+
+@end
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+@implementation NetworkRequestTimeout
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+#pragma mark TTURLRequest
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)testTTURLRequest_timeoutIntervalAccess {
+ STAssertEqualsWithAccuracy([[[[TTURLRequest alloc] init] autorelease] timeoutInterval],
+ (NSTimeInterval)TTURLRequestUseDefaultTimeout,
+ 0.1,
+ @"default timeout should be set on initialization");
+
+ TTURLRequest * request = [[TTURLRequest alloc] init];
+ request.timeoutInterval = 20.0;
+ STAssertEqualsWithAccuracy(request.timeoutInterval,(NSTimeInterval)20.0,0.1,
+ @"should return the previously set timeout");
+
+ TT_RELEASE_SAFELY(request);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)testTTURLRequestQueue_timeoutIntervalAccess {
+ STAssertEqualsWithAccuracy([[[[TTURLRequestQueue alloc] init] autorelease] defaultTimeout],
+ (NSTimeInterval)kTimeout,
+ 0.1,
+ @"default timeout should be set on initialization");
+
+ TTURLRequestQueue * queue = [[TTURLRequestQueue alloc] init];
+ queue.defaultTimeout = 20.0;
+ STAssertEqualsWithAccuracy(queue.defaultTimeout,(NSTimeInterval)20.0,0.1,
+ @"should return the previously set timeout");
+
+ TT_RELEASE_SAFELY(queue);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)testTTURLRequestQueue_timeoutIntervalUsage {
+
+ TTURLRequestQueue* queue = [[TTURLRequestQueue alloc] init];
+
+ TTURLRequest* request = [[TTURLRequest alloc] init];
+ request.urlPath = @"http://www.three20.info";
+
+ NSURL* url = [NSURL URLWithString:request.urlPath];
+
+ NSURLRequest* urlRequest = nil;
+
+ urlRequest = [queue createNSURLRequest:request URL:url];
+
+ STAssertNotNil(urlRequest,@"request queue didn't return an NSURLRequest");
+ STAssertEqualsWithAccuracy([urlRequest timeoutInterval],kTimeout,0.1,@"wrong timeoutInterval set");
+
+ queue.defaultTimeout = 48.5;
+
+ urlRequest = [queue createNSURLRequest:request URL:url];
+
+ STAssertNotNil(urlRequest,@"request queue didn't return an NSURLRequest");
+ STAssertEqualsWithAccuracy([urlRequest timeoutInterval],48.5,0.1,@"wrong timeoutInterval set");
+
+ request.timeoutInterval = 5.3;
+
+ urlRequest = [queue createNSURLRequest:request URL:url];
+
+ STAssertNotNil(urlRequest,@"request queue didn't return an NSURLRequest");
+ STAssertEqualsWithAccuracy([urlRequest timeoutInterval],5.3,0.1,@"wrong timeoutInterval set");
+
+ request.timeoutInterval = -17;
+
+ urlRequest = [queue createNSURLRequest:request URL:url];
+
+ STAssertNotNil(urlRequest,@"request queue didn't return an NSURLRequest");
+ STAssertEqualsWithAccuracy([urlRequest timeoutInterval],48.5,0.1,@"wrong timeoutInterval set");
+}
+
+@end
View
2 src/Three20Network/Sources/TTErrorCodes.m
@@ -18,4 +18,4 @@
NSString* const kTTNetworkErrorDomain = @"three20.network";
NSInteger const kTTNetworkErrorCodeInvalidImage = 100;
-
+NSString* const kTTErrorResponseDataKey = @"responsedata";
View
66 src/Three20Network/Sources/TTRequestLoader.m
@@ -16,6 +16,9 @@
#import "Three20Network/private/TTRequestLoader.h"
+//Global
+#import "Three20Network/TTErrorCodes.h"
+
// Network
#import "Three20Network/TTGlobalNetwork.h"
#import "Three20Network/TTURLRequest.h"
@@ -27,6 +30,7 @@
#import "Three20Network/private/TTURLRequestQueueInternal.h"
// Core
+#import "Three20Core/NSDataAdditions.h"
#import "Three20Core/NSObjectAdditions.h"
#import "Three20Core/TTDebug.h"
#import "Three20Core/TTDebugFlags.h"
@@ -48,7 +52,8 @@ @implementation TTRequestLoader
///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)initForRequest:(TTURLRequest*)request queue:(TTURLRequestQueue*)queue {
- if (self = [super init]) {
+ self = [super init];
+ if (self) {
_urlPath = [request.urlPath copy];
_queue = queue;
_cacheKey = [request.cacheKey retain];
@@ -81,10 +86,37 @@ - (void)dealloc {
#pragma mark -
#pragma mark Private
+//////////////////////////////////////////////////////////////////////////////////////////////////
+// This method not called from outside,
+// used as a separate entry point for performSelector outside connectToURL below
+- (void)deliverDataResponse:(NSURL*)URL {
+ // http://tools.ietf.org/html/rfc2397
+ NSArray * dataSplit = [[URL resourceSpecifier] componentsSeparatedByString:@","];
+ if([dataSplit count]!=2) {
+ TTDCONDITIONLOG(TTDFLAG_URLREQUEST, @"UNRECOGNIZED data: URL %@", self.urlPath);
+ return;
+ }
+ if([[dataSplit objectAtIndex:0] rangeOfString:@"base64"].location == NSNotFound) {
+ // Strictly speaking, to be really conformant need to interpret %xx hex encoded entities.
+ // The [NSString dataUsingEncoding] doesn't do that correctly, but most documents don't use that.
+ // Skip for now.
+ _responseData = [[[dataSplit objectAtIndex:1] dataUsingEncoding:NSASCIIStringEncoding] retain];
+ } else {
+ _responseData = [[NSData dataWithBase64EncodedString:[dataSplit objectAtIndex:1]] retain];
+ }
+
+ [_queue performSelector:@selector(loader:didLoadResponse:data:) withObject:self
+ withObject:_response withObject:_responseData];
+}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)connectToURL:(NSURL*)URL {
TTDCONDITIONLOG(TTDFLAG_URLREQUEST, @"Connecting to %@", _urlPath);
+ // If this is a data: url, we can decode right here ... after a delay to get out of calling thread
+ if([[URL scheme] isEqualToString:@"data"]) {
+ [self performSelector:@selector(deliverDataResponse:) withObject:URL afterDelay:0.1];
+ return;
+ }
TTNetworkRequestStarted();
TTURLRequest* request = _requests.count == 1 ? [_requests objectAtIndex:0] : nil;
@@ -208,7 +240,24 @@ - (BOOL)cancel:(TTURLRequest*)request {
///////////////////////////////////////////////////////////////////////////////////////////////////
- (NSError*)processResponse:(NSHTTPURLResponse*)response data:(id)data {
for (TTURLRequest* request in _requests) {
- NSError* error = [request.response request:request processResponse:response data:data];
+ NSError* error = nil;
+ // We need to accept valid HTTP status codes, not only 200.
+ if (!response
+ || (response.statusCode >= 200 && response.statusCode < 300)
+ || response.statusCode == 304) {
+ error = [request.response request:request processResponse:response data:data];
+ } else {
+ if ([request.response respondsToSelector:@selector(request:processErrorResponse:data:)]) {
+ error = [request.response request:request processErrorResponse:response data:data];
+ }
+ // Supply an NSError object if request.response's
+ // request:processErrorResponse:data: does not return one.
+ if (!error) {
+ TTDCONDITIONLOG(TTDFLAG_URLREQUEST, @" FAILED LOADING (%d) %@", _response.statusCode, _urlPath);
+ NSDictionary* userInfo = [NSDictionary dictionaryWithObject:data forKey:kTTErrorResponseDataKey];
+ error = [NSError errorWithDomain:NSURLErrorDomain code:_response.statusCode userInfo:userInfo];
+ }
+ }
if (error) {
return error;
}
@@ -334,19 +383,10 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
TTDCONDITIONLOG(TTDFLAG_ETAGS, @"Response status code: %d", _response.statusCode);
- // We need to accept valid HTTP status codes, not only 200.
- if (_response.statusCode >= 200 && _response.statusCode < 300) {
- [_queue loader:self didLoadResponse:_response data:_responseData];
-
- } else if (_response.statusCode == 304) {
+ if (_response.statusCode == 304) {
[_queue loader:self didLoadUnmodifiedResponse:_response];
-
} else {
- TTDCONDITIONLOG(TTDFLAG_URLREQUEST, @" FAILED LOADING (%d) %@",
- _response.statusCode, _urlPath);
- NSError* error = [NSError errorWithDomain:NSURLErrorDomain code:_response.statusCode
- userInfo:nil];
- [_queue loader:self didFailLoadWithError:error];
+ [_queue loader:self didLoadResponse:_response data:_responseData];
}
TT_RELEASE_SAFELY(_responseData);
View
6 src/Three20Network/Sources/TTURLCache.m
@@ -62,7 +62,8 @@ @implementation TTURLCache
///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)initWithName:(NSString*)name {
- if (self == [super init]) {
+ self = [super init];
+ if (self) {
_name = [name copy];
_cachePath = [[TTURLCache cachePathWithName:name] retain];
_invalidationAge = TT_DEFAULT_CACHE_INVALIDATION_AGE;
@@ -85,7 +86,8 @@ - (id)initWithName:(NSString*)name {
///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)init {
- if (self = [self initWithName:kDefaultCacheName]) {
+ self = [self initWithName:kDefaultCacheName];
+ if (self) {
}
return self;
View
74 src/Three20Network/Sources/TTURLRequest.m
@@ -16,6 +16,7 @@
#import "Three20Network/TTURLRequest.h"
+
// Network
#import "Three20Network/TTGlobalNetwork.h"
#import "Three20Network/TTURLResponse.h"
@@ -28,7 +29,7 @@
#import "Three20Core/NSStringAdditions.h"
static NSString* kStringBoundary = @"3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f";
-
+const NSTimeInterval TTURLRequestUseDefaultTimeout = -1.0;
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -58,12 +59,15 @@ @implementation TTURLRequest
@synthesize totalBytesDownloaded = _totalBytesDownloaded;
@synthesize totalContentLength = _totalContentLength;
+@synthesize timeoutInterval = _timeoutInterval;
+
@synthesize userInfo = _userInfo;
@synthesize isLoading = _isLoading;
@synthesize shouldHandleCookies = _shouldHandleCookies;
@synthesize respondedFromCache = _respondedFromCache;
@synthesize filterPasswordLogging = _filterPasswordLogging;
+@synthesize multiPartForm = _multiPartForm;
@synthesize delegates = _delegates;
@@ -82,7 +86,8 @@ + (TTURLRequest*)requestWithURL:(NSString*)URL delegate:(id /*<TTURLRequestDeleg
///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)initWithURL:(NSString*)URL delegate:(id /*<TTURLRequestDelegate>*/)delegate {
- if (self = [self init]) {
+ self = [self init];
+ if (self) {
_urlPath = [URL retain];
if (nil != delegate) {
[_delegates addObject:delegate];
@@ -94,12 +99,15 @@ - (id)initWithURL:(NSString*)URL delegate:(id /*<TTURLRequestDelegate>*/)delegat
///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)init {
- if (self = [super init]) {
+ self = [super init];
+ if (self) {
_delegates = TTCreateNonRetainingArray();
_cachePolicy = TTURLRequestCachePolicyDefault;
_cacheExpirationAge = TT_DEFAULT_CACHE_EXPIRATION_AGE;
_shouldHandleCookies = YES;
_charsetForMultipart = NSUTF8StringEncoding;
+ _multiPartForm = YES;
+ _timeoutInterval = TTURLRequestUseDefaultTimeout;
}
return self;
}
@@ -152,12 +160,27 @@ - (NSString*)generateCacheKey {
}
}
+//////////////////////////////////////////////////////////////////////////////////////////////////
+- (NSData *)generateNonMultipartPostBody {
+ NSMutableArray *paramsArray = [NSMutableArray array];
+ for (id key in [_parameters keyEnumerator]) {
+ NSString *value = [_parameters valueForKey:key];
+ if ([key isKindOfClass:[NSString class]] && [value isKindOfClass:[NSString class]]) {
+ [paramsArray addObject:[NSString stringWithFormat:@"%@=%@",
+ key,
+ [[value stringByReplacingOccurrencesOfString:@" " withString:@"+"] urlEncoded]]];
+ }
+ }
+ NSString *stringBody = [paramsArray componentsJoinedByString:@"&"];
+ return [stringBody dataUsingEncoding:NSUTF8StringEncoding];
+}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)appendImageData:(NSData*)data
withName:(NSString*)name
toBody:(NSMutableData*)body {
- NSString *beginLine = [NSString stringWithFormat:@"\r\n--%@\r\n", kStringBoundary];
+ NSString *beginLine = [NSString stringWithFormat:@"--%@\r\n", kStringBoundary];
+ NSString *endLine = @"\r\n";
[body appendData:[beginLine dataUsingEncoding:NSUTF8StringEncoding]];