├── .covio.yml
├── .gitignore
├── .travis.yml
├── Interpreter.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcshareddata
│ └── xcschemes
│ └── Node.xcscheme
├── Interpreter.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── WorkspaceSettings.xcsettings
├── NodelikeDemo
├── Base.lproj
│ └── Main.storyboard
├── CSNotificationView.h
├── CSNotificationView.m
├── CSNotificationView.xcassets
│ ├── CSNotificationView_checkmarkIcon.imageset
│ │ ├── CSNotificationView_checkmarkIcon.png
│ │ ├── CSNotificationView_checkmarkIcon@2x.png
│ │ └── Contents.json
│ └── CSNotificationView_exclamationMarkIcon.imageset
│ │ ├── CSNotificationView_exclamationMarkIcon.png
│ │ ├── CSNotificationView_exclamationMarkIcon@2x.png
│ │ └── Contents.json
├── CYRLayoutManager.h
├── CYRLayoutManager.m
├── CYRTextStorage.h
├── CYRTextStorage.m
├── CYRTextView.h
├── CYRTextView.m
├── CYRToken.h
├── CYRToken.m
├── FHSegmentedViewController.h
├── FHSegmentedViewController.m
├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-60@2x.png
│ │ ├── Icon-76.png
│ │ ├── Icon-76@2x.png
│ │ ├── Icon-Small-1.png
│ │ ├── Icon-Small.png
│ │ ├── Icon-Small@2x-1.png
│ │ ├── Icon-Small@2x.png
│ │ ├── Icon-Spotlight-40.png
│ │ ├── Icon-Spotlight-40@2x-1.png
│ │ └── Icon-Spotlight-40@2x.png
│ ├── KOKeyboard
│ │ ├── hal-black.imageset
│ │ │ ├── Contents.json
│ │ │ ├── hal-black.png
│ │ │ └── hal-black@2x.png
│ │ ├── hal-blue.imageset
│ │ │ ├── Contents.json
│ │ │ ├── hal-blue.png
│ │ │ └── hal-blue@2x.png
│ │ └── hal-white.imageset
│ │ │ ├── Contents.json
│ │ │ ├── hal-white.png
│ │ │ └── hal-white@2x.png
│ ├── LaunchImage.launchimage
│ │ ├── Contents.json
│ │ ├── launch-pad-land.png
│ │ ├── launch-pad-land@2x.png
│ │ ├── launch-pad.png
│ │ ├── launch-pad@2x.png
│ │ ├── launch-phone-r4-1.png
│ │ └── launch-phone@2x.png
│ ├── bookmarks.imageset
│ │ ├── Contents.json
│ │ ├── bookmarks.png
│ │ └── bookmarks@2x.png
│ └── info.imageset
│ │ ├── Contents.json
│ │ ├── info.png
│ │ └── info@2x.png
├── Interpreter-Info.plist
├── Interpreter-Prefix.pch
├── LaunchScreen.xib
├── NLAppDelegate.h
├── NLAppDelegate.m
├── NLColor.h
├── NLColor.m
├── NLConsoleViewController.h
├── NLConsoleViewController.m
├── NLDocumentationViewController.h
├── NLDocumentationViewController.m
├── NLEditorViewController.h
├── NLEditorViewController.m
├── NLMasterViewController.h
├── NLMasterViewController.m
├── NLTextView.h
├── NLTextView.m
├── PBWebViewController.h
├── PBWebViewController.m
├── SEJSONViewController.h
├── SEJSONViewController.m
├── Syntax.plist
├── Vendor
│ └── KOKeyboard
│ │ ├── KOKeyboardRow.h
│ │ ├── KOKeyboardRow.m
│ │ ├── KOSwipeButton.h
│ │ └── KOSwipeButton.m
├── en.lproj
│ └── InfoPlist.strings
└── main.m
├── Podfile
├── README.md
├── demo.png
└── node_modules
└── examples
├── index.js
└── node_modules
├── example01
└── index.js
├── example02
└── index.js
├── example03
└── index.js
└── example04
└── index.js
/.covio.yml:
--------------------------------------------------------------------------------
1 | violations:
2 | sloccount: sloccount Nodelike
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | xcuserdata
3 |
4 | *.xccheckout
5 | build
6 |
7 | Podfile.lock
8 | Pods/
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | xcode_sdk: iphonesimulator
3 | xcode_scheme: Node
4 | xcode_workspace: Interpreter.xcworkspace
5 | rvm: 1.9.3
6 | before_install: gem install cocoapods
7 | notifications:
8 | flowdock: 803358c5edc46b50866b8e588b4c374b
9 | webhooks:
10 | urls:
11 | - https://webhooks.gitter.im/e/fa1f3636231a3e89e7fd
12 | on_success: change
13 | on_failure: always
14 | on_start: false
15 | hipchat:
16 | secure: aWO9pLQ74SvlXTUMgXrIrezP5VQZdJE2gNgfmmOoK6S6qUiRALJi0wSF4njv1WFf9ZLWaWr8b7Z7Gs4ZeF+rhI7/xGw7YdQaJYkiQ/yo0QdUhn5NTgzJo8CMyremNJx/qcK0+FbwsttIpB7kYWW9XuFGUrmHGojX5Lx1pYnFbZk=
17 |
--------------------------------------------------------------------------------
/Interpreter.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Interpreter.xcodeproj/xcshareddata/xcschemes/Node.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
51 |
52 |
58 |
59 |
60 |
61 |
62 |
63 |
69 |
70 |
76 |
77 |
78 |
79 |
81 |
82 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/Interpreter.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Interpreter.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/NodelikeDemo/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/NodelikeDemo/CSNotificationView.h:
--------------------------------------------------------------------------------
1 | //
2 | // CSNotificationView.h
3 | // CSNotificationView
4 | //
5 | // Created by Christian Schwarz on 01.09.13.
6 | // Copyright (c) 2013 Christian Schwarz. Check LICENSE.md.
7 | //
8 |
9 | #import
10 |
11 | static CGFloat const kCSNotificationViewHeight = 50.0f;
12 | static CGFloat const kCSNotificationViewSymbolViewSidelength = 44.0f;
13 | static NSTimeInterval const kCSNotificationViewDefaultShowDuration = 2.0;
14 |
15 | typedef enum {
16 | CSNotificationViewStyleSuccess,
17 | CSNotificationViewStyleError,
18 | } CSNotificationViewStyle;
19 |
20 | @interface CSNotificationView : UIView
21 |
22 | #pragma mark + quick presentation
23 |
24 | + (void)showInViewController:(UIViewController*)viewController
25 | style:(CSNotificationViewStyle)style
26 | message:(NSString*)message;
27 |
28 | + (void)showInViewController:(UIViewController*)viewController
29 | tintColor:(UIColor*)tintColor
30 | image:(UIImage*)image
31 | message:(NSString*)message
32 | duration:(NSTimeInterval)duration;
33 |
34 | #pragma mark + creators
35 |
36 | + (CSNotificationView*)notificationViewWithParentViewController:(UIViewController*)viewController
37 | tintColor:(UIColor*)tintColor
38 | image:(UIImage*)image
39 | message:(NSString*)message;
40 |
41 | #pragma mark - initialization
42 |
43 | - (instancetype)initWithParentViewController:(UIViewController*)viewController;
44 |
45 | #pragma mark - presentation
46 |
47 | - (void)setVisible:(BOOL)showing animated:(BOOL)animated completion:(void (^)())completion;
48 | - (void)dismissWithStyle:(CSNotificationViewStyle)style message:(NSString*)message duration:(NSTimeInterval)duration animated:(BOOL)animated;
49 | @property (readonly, nonatomic, getter = isShowing) BOOL visible;
50 |
51 | #pragma mark - visible properties
52 |
53 | /**
54 | The image property should be used for setting the image displayed in imageView
55 | Only the alpha value will be used and then be tinted to a 'legible' color
56 | */
57 | @property (nonatomic, strong) UIImage* image;
58 |
59 | @property (nonatomic, strong) UIColor* tintColor;
60 |
61 | @property (nonatomic, getter = isShowingActivity) BOOL showingActivity;
62 |
63 | @end
64 |
--------------------------------------------------------------------------------
/NodelikeDemo/CSNotificationView.m:
--------------------------------------------------------------------------------
1 | //
2 | // CSNotificationView.m
3 | // CSNotificationView
4 | //
5 | // Created by Christian Schwarz on 01.09.13.
6 | // Copyright (c) 2013 Christian Schwarz. Check LICENSE.md.
7 | //
8 |
9 | #import "CSNotificationView.h"
10 |
11 | static NSInteger const kCSNotificationViewEmptySymbolViewTag = 666;
12 |
13 | @interface CSNotificationView ()
14 |
15 | #pragma mark - blur effect
16 | @property (nonatomic, strong) UIToolbar *toolbar;
17 | @property (nonatomic, strong) CALayer *blurLayer;
18 |
19 | #pragma mark - presentation
20 | @property (nonatomic, weak) UIViewController* parentViewController;
21 | @property (nonatomic, weak) UINavigationController* parentNavigationController;
22 | @property (nonatomic, getter = isVisible) BOOL visible;
23 |
24 | #pragma mark - content views
25 | @property (nonatomic, strong, readonly) UIView* symbolView; // is updated by -(void)updateSymbolView
26 | @property (nonatomic, strong) UILabel* textLabel;
27 | @property (nonatomic, strong) UIColor* contentColor;
28 |
29 | @end
30 |
31 | @implementation CSNotificationView
32 |
33 | #pragma mark + quick presentation
34 |
35 | + (void)showInViewController:(UIViewController*)viewController
36 | tintColor:(UIColor*)tintColor
37 | image:(UIImage*)image
38 | message:(NSString*)message
39 | duration:(NSTimeInterval)duration
40 | {
41 | NSAssert(message, @"'message' must not be nil.");
42 |
43 | __block CSNotificationView* note = [[CSNotificationView alloc] initWithParentViewController:viewController];
44 | note.tintColor = tintColor;
45 | note.image = image;
46 | note.textLabel.text = message;
47 |
48 | void (^completion)() = ^{[note setVisible:NO animated:YES completion:nil];};
49 | [note setVisible:YES animated:YES completion:^{
50 | double delayInSeconds = duration;
51 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
52 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
53 | completion();
54 | });
55 | }];
56 |
57 | }
58 |
59 | + (void)showInViewController:(UIViewController *)viewController
60 | style:(CSNotificationViewStyle)style
61 | message:(NSString *)message
62 | {
63 |
64 |
65 | [CSNotificationView showInViewController:viewController
66 | tintColor:[CSNotificationView blurTintColorForStyle:style]
67 | image:[CSNotificationView imageForStyle:style]
68 | message:message
69 | duration:kCSNotificationViewDefaultShowDuration];
70 | }
71 |
72 | #pragma mark + creators
73 |
74 | + (CSNotificationView*)notificationViewWithParentViewController:(UIViewController*)viewController
75 | tintColor:(UIColor*)tintColor
76 | image:(UIImage*)image
77 | message:(NSString*)message
78 | {
79 | NSParameterAssert(viewController);
80 |
81 | CSNotificationView* note = [[CSNotificationView alloc] initWithParentViewController:viewController];
82 | note.tintColor = tintColor;
83 | note.image = image;
84 | note.textLabel.text = message;
85 |
86 | return note;
87 | }
88 |
89 | #pragma mark - lifecycle
90 |
91 | - (instancetype)initWithParentViewController:(UIViewController*)viewController
92 | {
93 | self = [super initWithFrame:CGRectZero];
94 | if (self) {
95 |
96 | //Blur | thanks to https://github.com/JagCesar/iOS-blur for providing this under the WTFPL-license!
97 | {
98 | [self setToolbar:[[UIToolbar alloc] initWithFrame:[self bounds]]];
99 | [self setBlurLayer:[[self toolbar] layer]];
100 |
101 | UIView *blurView = [UIView new];
102 | [blurView setUserInteractionEnabled:NO];
103 | [blurView.layer addSublayer:[self blurLayer]];
104 | [blurView setTranslatesAutoresizingMaskIntoConstraints:NO];
105 | [blurView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
106 | [self insertSubview:blurView atIndex:0];
107 |
108 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[blurView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(blurView)]];
109 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(-1)-[blurView]-(-1)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(blurView)]];
110 |
111 | [self setBackgroundColor:[UIColor clearColor]];
112 | }
113 |
114 | //Parent view
115 | {
116 | self.parentViewController = viewController;
117 |
118 | NSAssert(!([self.parentViewController isKindOfClass:[UITableViewController class]] && !self.parentViewController.navigationController), @"Due to a bug in iOS 7.0.1|2|3 UITableViewController, CSNotificationView cannot present in UITableViewController without a parent UINavigationController");
119 |
120 | if (self.parentViewController.navigationController) {
121 | self.parentNavigationController = self.parentViewController.navigationController;
122 | }
123 | if ([self.parentViewController isKindOfClass:[UINavigationController class]]) {
124 | self.parentNavigationController = (UINavigationController*)self.parentViewController;
125 | }
126 |
127 | }
128 |
129 | //Content views
130 | {
131 | //textLabel
132 | {
133 | _textLabel = [[UILabel alloc] init];
134 |
135 | UIFontDescriptor* textLabelFontDescriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleBody];
136 | _textLabel.font = [UIFont fontWithDescriptor:textLabelFontDescriptor size:17.0f];
137 | _textLabel.minimumScaleFactor = 0.6;
138 | _textLabel.lineBreakMode = NSLineBreakByTruncatingTail;
139 | _textLabel.adjustsFontSizeToFitWidth = YES;
140 |
141 | _textLabel.numberOfLines = 2;
142 | _textLabel.textColor = [UIColor whiteColor];
143 | _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
144 | [self addSubview:_textLabel];
145 | }
146 | //symbolView
147 | {
148 | [self updateSymbolView];
149 | }
150 | }
151 |
152 | }
153 | return self;
154 | }
155 |
156 | #pragma mark - layout
157 |
158 | - (void)updateConstraints
159 | {
160 | [self removeConstraints:self.constraints];
161 |
162 | CGFloat symbolViewWidth = self.symbolView.tag != kCSNotificationViewEmptySymbolViewTag ?
163 | kCSNotificationViewSymbolViewSidelength : 0.0f;
164 | CGFloat symbolViewHeight = kCSNotificationViewSymbolViewSidelength;
165 |
166 | NSDictionary* metrics =
167 | @{@"symbolViewWidth": [NSNumber numberWithFloat:symbolViewWidth],
168 | @"symbolViewHeight":[NSNumber numberWithFloat:symbolViewHeight]};
169 |
170 | [self addConstraints:[NSLayoutConstraint
171 | constraintsWithVisualFormat:@"H:|-(4)-[_symbolView(symbolViewWidth)]-(5)-[_textLabel]-(10)-|"
172 | options:0
173 | metrics:metrics
174 | views:NSDictionaryOfVariableBindings(_textLabel, _symbolView)]];
175 |
176 | [self addConstraints:[NSLayoutConstraint
177 | constraintsWithVisualFormat:@"V:[_symbolView(symbolViewHeight)]"
178 | options:0
179 | metrics:metrics
180 | views:NSDictionaryOfVariableBindings(_symbolView)]];
181 |
182 | CGFloat topInset = CGRectGetHeight(self.frame) - 4;
183 |
184 | [self addConstraint:[NSLayoutConstraint
185 | constraintWithItem:_symbolView
186 | attribute:NSLayoutAttributeBottom
187 | relatedBy:NSLayoutRelationEqual
188 | toItem:self
189 | attribute:NSLayoutAttributeBottom
190 | multiplier:0.0f constant:topInset]];
191 |
192 | [self addConstraint:[NSLayoutConstraint
193 | constraintWithItem:_textLabel
194 | attribute:NSLayoutAttributeCenterY
195 | relatedBy:NSLayoutRelationEqual
196 | toItem:_symbolView
197 | attribute:NSLayoutAttributeCenterY
198 | multiplier:1.0f constant:0]];
199 |
200 | [super updateConstraints];
201 | }
202 |
203 | - (void)setFrame:(CGRect)frame
204 | {
205 | [super setFrame:frame];
206 | self.blurLayer.frame = self.bounds;
207 | }
208 |
209 | #pragma mark - tint color
210 |
211 | - (void)setTintColor:(UIColor *)tintColor
212 | {
213 | _tintColor = tintColor;
214 | //Use 0.6 alpha value for translucency blur in UIToolbar
215 | [self.toolbar setBarTintColor:[tintColor colorWithAlphaComponent:0.6]];
216 | self.contentColor = [self legibleTextColorForBlurTintColor:tintColor];
217 | }
218 |
219 | #pragma mark - presentation
220 |
221 | - (void)setVisible:(BOOL)visible animated:(BOOL)animated completion:(void (^)())completion
222 | {
223 | if (_visible != visible) {
224 |
225 | NSTimeInterval animationDuration = animated ? 0.4 : 0.0;
226 | CGRect startFrame = visible ? [self hiddenFrame]:[self visibleFrame];
227 | CGRect endFrame = visible ? [self visibleFrame] : [self hiddenFrame];
228 |
229 | if (!self.superview) {
230 | self.frame = startFrame;
231 |
232 | if (self.parentNavigationController) {
233 | for (UIView* view in self.parentNavigationController.view.subviews) {
234 | if ([view isKindOfClass:[UINavigationBar class]]) {
235 | [self.parentNavigationController.view insertSubview:self belowSubview:view];
236 | }
237 | }
238 | } else {
239 | [self.parentViewController.view addSubview:self];
240 | }
241 |
242 | }
243 |
244 | __block typeof(self) weakself = self;
245 | [UIView animateWithDuration:animationDuration animations:^{
246 | [weakself setFrame:endFrame];
247 | } completion:^(BOOL finished) {
248 | if (!visible) {
249 | [weakself removeFromSuperview];
250 | }
251 | if (completion) {
252 | completion();
253 | }
254 | }];
255 |
256 | _visible = visible;
257 | } else if (completion) {
258 | completion();
259 | }
260 | }
261 |
262 | - (void)dismissWithStyle:(CSNotificationViewStyle)style message:(NSString *)message duration:(NSTimeInterval)duration animated:(BOOL)animated
263 | {
264 | NSParameterAssert(message);
265 |
266 | __block typeof(self) weakself = self;
267 | [UIView animateWithDuration:0.1 animations:^{
268 |
269 | weakself.showingActivity = NO;
270 | weakself.image = [CSNotificationView imageForStyle:style];
271 | weakself.textLabel.text = message;
272 | weakself.tintColor = [CSNotificationView blurTintColorForStyle:style];
273 |
274 | } completion:^(BOOL finished) {
275 | double delayInSeconds = 2.0;
276 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
277 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
278 | [weakself setVisible:NO animated:animated completion:nil];
279 | });
280 | }];
281 | }
282 |
283 | #pragma mark - frame calculation
284 |
285 | //Workaround as there is a bug: sometimes, when accessing topLayoutGuide, it will render contentSize of UITableViewControllers to be {0, 0}
286 | - (CGFloat)topLayoutGuideLengthCalculation
287 | {
288 | CGFloat top = CGRectGetHeight([[UIApplication sharedApplication] statusBarFrame]);
289 | if (self.parentNavigationController) {
290 |
291 | for (UIView* view in self.parentNavigationController.view.subviews) {
292 | if ([view isKindOfClass:[UINavigationBar class]]) {
293 | top += CGRectGetHeight(view.frame);
294 | break;
295 | }
296 | }
297 | }
298 | return top;
299 | }
300 |
301 | - (CGRect)visibleFrame
302 | {
303 | UIViewController* viewController = self.parentViewController;
304 |
305 | CGFloat topLayoutGuideLength = [self topLayoutGuideLengthCalculation];
306 |
307 | CGRect displayFrame = CGRectMake(0, 0, CGRectGetWidth(viewController.view.frame),
308 | kCSNotificationViewHeight + topLayoutGuideLength);
309 |
310 | return displayFrame;
311 | }
312 |
313 | - (CGRect)hiddenFrame
314 | {
315 | UIViewController* viewController = self.parentViewController;
316 |
317 | CGFloat topLayoutGuideLength = [self topLayoutGuideLengthCalculation];
318 |
319 | CGRect offscreenFrame = CGRectMake(0, -kCSNotificationViewHeight - topLayoutGuideLength,
320 | CGRectGetWidth(viewController.view.frame),
321 | kCSNotificationViewHeight + topLayoutGuideLength);
322 |
323 | return offscreenFrame;
324 | }
325 |
326 | #pragma mark - symbol view
327 |
328 | - (void)updateSymbolView
329 | {
330 | [self.symbolView removeFromSuperview];
331 |
332 | if (self.isShowingActivity) {
333 | UIActivityIndicatorView* indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
334 | indicator.color = self.contentColor;
335 | [indicator startAnimating];
336 | _symbolView = indicator;
337 | } else if (self.image) {
338 | //Generate UIImageView for symbolView
339 | UIImageView* imageView = [[UIImageView alloc] init];
340 | imageView.opaque = NO;
341 | imageView.backgroundColor = [UIColor clearColor];
342 | imageView.translatesAutoresizingMaskIntoConstraints = NO;
343 | imageView.contentMode = UIViewContentModeCenter;
344 | imageView.image = [self imageFromAlphaChannelOfImage:self.image replacementColor:self.contentColor];
345 | _symbolView = imageView;
346 | } else {
347 | _symbolView = [[UIView alloc] initWithFrame:CGRectZero];
348 | _symbolView.tag = kCSNotificationViewEmptySymbolViewTag;
349 | }
350 | _symbolView.translatesAutoresizingMaskIntoConstraints = NO;
351 | [self addSubview:_symbolView];
352 | [self setNeedsUpdateConstraints];
353 |
354 | }
355 |
356 | #pragma mark -- image
357 |
358 | - (void)setImage:(UIImage *)image
359 | {
360 | if (![_image isEqual:image]) {
361 | _image = image;
362 | [self updateSymbolView];
363 | }
364 | }
365 |
366 | #pragma mark -- activity
367 |
368 | - (void)setShowingActivity:(BOOL)showingActivity
369 | {
370 | if (_showingActivity != showingActivity) {
371 | _showingActivity = showingActivity;
372 | [self updateSymbolView];
373 | }
374 | }
375 |
376 |
377 | #pragma mark - content color
378 |
379 | - (void)setContentColor:(UIColor *)contentColor
380 | {
381 | if (![_contentColor isEqual:contentColor]) {
382 | _contentColor = contentColor;
383 | self.textLabel.textColor = _contentColor;
384 | [self updateSymbolView];
385 | }
386 | }
387 |
388 | #pragma mark helpers
389 |
390 | - (UIColor*)legibleTextColorForBlurTintColor:(UIColor*)blurTintColor
391 | {
392 | CGFloat r, g, b, a;
393 | BOOL couldConvert = [blurTintColor getRed:&r green:&g blue:&b alpha:&a];
394 |
395 | UIColor* textColor = [UIColor whiteColor];
396 |
397 | CGFloat average = (r+g+b)/3.0; //Not considering alpha here, transperency is added by toolbar
398 | if (couldConvert && average > 0.65) //0.65 is mostly gut-feeling
399 | {
400 | textColor = [[UIColor alloc] initWithWhite:0.2 alpha:1.0];
401 | }
402 |
403 | return textColor;
404 | }
405 |
406 | - (UIImage*)imageFromAlphaChannelOfImage:(UIImage*)image replacementColor:(UIColor*)tintColor
407 | {
408 | if (!image) return nil;
409 | NSParameterAssert([tintColor isKindOfClass:[UIColor class]]);
410 |
411 | //Credits: https://gist.github.com/omz/1102091
412 | CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
413 | UIGraphicsBeginImageContextWithOptions(rect.size, NO, image.scale);
414 | CGContextRef c = UIGraphicsGetCurrentContext();
415 | [image drawInRect:rect];
416 | CGContextSetFillColorWithColor(c, [tintColor CGColor]);
417 | CGContextSetBlendMode(c, kCGBlendModeSourceAtop);
418 | CGContextFillRect(c, rect);
419 | UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
420 | UIGraphicsEndImageContext();
421 | return result;
422 | }
423 |
424 | + (UIImage*)imageForStyle:(CSNotificationViewStyle)style
425 | {
426 | UIImage* matchedImage = nil;
427 | switch (style) {
428 | case CSNotificationViewStyleSuccess:
429 | matchedImage = [UIImage imageNamed:@"CSNotificationView_checkmarkIcon"];
430 | break;
431 | case CSNotificationViewStyleError:
432 | matchedImage = [UIImage imageNamed:@"CSNotificationView_exclamationMarkIcon"];
433 | break;
434 | default:
435 | break;
436 | }
437 | return matchedImage;
438 | }
439 |
440 | + (UIColor*)blurTintColorForStyle:(CSNotificationViewStyle)style
441 | {
442 | UIColor* blurTintColor;
443 | switch (style) {
444 | case CSNotificationViewStyleSuccess:
445 | blurTintColor = [UIColor colorWithRed:0.21 green:0.72 blue:0.00 alpha:1.0];
446 | break;
447 | case CSNotificationViewStyleError:
448 | blurTintColor = [UIColor redColor];
449 | break;
450 | default:
451 | break;
452 | }
453 | return blurTintColor;
454 | }
455 |
456 | @end
457 |
--------------------------------------------------------------------------------
/NodelikeDemo/CSNotificationView.xcassets/CSNotificationView_checkmarkIcon.imageset/CSNotificationView_checkmarkIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/CSNotificationView.xcassets/CSNotificationView_checkmarkIcon.imageset/CSNotificationView_checkmarkIcon.png
--------------------------------------------------------------------------------
/NodelikeDemo/CSNotificationView.xcassets/CSNotificationView_checkmarkIcon.imageset/CSNotificationView_checkmarkIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/CSNotificationView.xcassets/CSNotificationView_checkmarkIcon.imageset/CSNotificationView_checkmarkIcon@2x.png
--------------------------------------------------------------------------------
/NodelikeDemo/CSNotificationView.xcassets/CSNotificationView_checkmarkIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "CSNotificationView_checkmarkIcon.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "CSNotificationView_checkmarkIcon@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/NodelikeDemo/CSNotificationView.xcassets/CSNotificationView_exclamationMarkIcon.imageset/CSNotificationView_exclamationMarkIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/CSNotificationView.xcassets/CSNotificationView_exclamationMarkIcon.imageset/CSNotificationView_exclamationMarkIcon.png
--------------------------------------------------------------------------------
/NodelikeDemo/CSNotificationView.xcassets/CSNotificationView_exclamationMarkIcon.imageset/CSNotificationView_exclamationMarkIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/CSNotificationView.xcassets/CSNotificationView_exclamationMarkIcon.imageset/CSNotificationView_exclamationMarkIcon@2x.png
--------------------------------------------------------------------------------
/NodelikeDemo/CSNotificationView.xcassets/CSNotificationView_exclamationMarkIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "CSNotificationView_exclamationMarkIcon.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "CSNotificationView_exclamationMarkIcon@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/NodelikeDemo/CYRLayoutManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // CYRLayoutManager.h
3 | //
4 | // Version 0.2.0
5 | //
6 | // Created by Illya Busigin on 01/05/2014.
7 | // Copyright (c) 2014 Cyrillian, Inc.
8 | //
9 | // Distributed under MIT license.
10 | // Get the latest version from here:
11 | //
12 | // https://github.com/illyabusigin/CYRTextView
13 | // Original implementation taken from: https://github.com/alldritt/TextKit_LineNumbers
14 | //
15 | // The MIT License (MIT)
16 | //
17 | // Copyright (c) 2014 Cyrillian, Inc.
18 | //
19 | // Permission is hereby granted, free of charge, to any person obtaining a copy of
20 | // this software and associated documentation files (the "Software"), to deal in
21 | // the Software without restriction, including without limitation the rights to
22 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
23 | // the Software, and to permit persons to whom the Software is furnished to do so,
24 | // subject to the following conditions:
25 | //
26 | // The above copyright notice and this permission notice shall be included in all
27 | // copies or substantial portions of the Software.
28 | //
29 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
31 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
32 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
33 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 |
36 | #import
37 |
38 | @interface CYRLayoutManager : NSLayoutManager
39 |
40 | @property (nonatomic, strong) UIFont *lineNumberFont;
41 | @property (nonatomic, strong) UIColor *lineNumberColor;
42 |
43 | @property (nonatomic, readonly) CGFloat gutterWidth;
44 | @property (nonatomic, assign) NSRange selectedRange;
45 |
46 | - (CGRect)paragraphRectForRange:(NSRange)range;
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/NodelikeDemo/CYRLayoutManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // CYRLayoutManager.h
3 | //
4 | // Version 0.2.0
5 | //
6 | // Created by Illya Busigin on 01/05/2014.
7 | // Copyright (c) 2014 Cyrillian, Inc.
8 | //
9 | // Distributed under MIT license.
10 | // Get the latest version from here:
11 | //
12 | // https://github.com/illyabusigin/CYRTextView
13 | // Original implementation taken from: https://github.com/alldritt/TextKit_LineNumbers
14 | //
15 | // The MIT License (MIT)
16 | //
17 | // Copyright (c) 2014 Cyrillian, Inc.
18 | //
19 | // Permission is hereby granted, free of charge, to any person obtaining a copy of
20 | // this software and associated documentation files (the "Software"), to deal in
21 | // the Software without restriction, including without limitation the rights to
22 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
23 | // the Software, and to permit persons to whom the Software is furnished to do so,
24 | // subject to the following conditions:
25 | //
26 | // The above copyright notice and this permission notice shall be included in all
27 | // copies or substantial portions of the Software.
28 | //
29 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
31 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
32 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
33 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 |
36 | #import "CYRLayoutManager.h"
37 |
38 | static CGFloat kMinimumGutterWidth = 30.f;
39 |
40 | @interface CYRLayoutManager ()
41 |
42 | @property (nonatomic, assign) CGFloat gutterWidth;
43 | @property (nonatomic, assign) UIEdgeInsets lineAreaInset;
44 |
45 | @property (nonatomic) NSUInteger lastParaLocation;
46 | @property (nonatomic) NSUInteger lastParaNumber;
47 |
48 | @end
49 |
50 | @implementation CYRLayoutManager
51 |
52 | #pragma mark - Initialization & Setup
53 |
54 | - (instancetype)init
55 | {
56 | self = [super init];
57 |
58 | if (self)
59 | {
60 | [self _commonSetup];
61 | }
62 |
63 | return self;
64 | }
65 |
66 | - (instancetype)initWithCoder:(NSCoder *)aDecoder
67 | {
68 | self = [super initWithCoder:aDecoder];
69 |
70 | if (self)
71 | {
72 | [self _commonSetup];
73 | }
74 |
75 | return self;
76 | }
77 |
78 | - (void)_commonSetup
79 | {
80 | self.gutterWidth = kMinimumGutterWidth;
81 | self.selectedRange = NSMakeRange(0, 0);
82 |
83 | self.lineAreaInset = UIEdgeInsetsMake(0, 10, 0, 4);
84 | self.lineNumberColor = [UIColor grayColor];
85 | self.lineNumberFont = [UIFont systemFontOfSize:10.0f];
86 | }
87 |
88 |
89 | #pragma mark - Convenience
90 |
91 | - (CGRect)paragraphRectForRange:(NSRange)range
92 | {
93 | range = [self.textStorage.string paragraphRangeForRange:range];
94 | range = [self glyphRangeForCharacterRange:range actualCharacterRange:NULL];
95 |
96 | CGRect startRect = [self lineFragmentRectForGlyphAtIndex:range.location effectiveRange:NULL];
97 | CGRect endRect = [self lineFragmentRectForGlyphAtIndex:range.location + range.length - 1 effectiveRange:NULL];
98 |
99 | CGRect paragraphRectForRange = CGRectUnion(startRect, endRect);
100 | paragraphRectForRange = CGRectOffset(paragraphRectForRange, _gutterWidth, 8);
101 |
102 | return paragraphRectForRange;
103 | }
104 |
105 | - (NSUInteger) _paraNumberForRange:(NSRange) charRange
106 | {
107 | // NSString does not provide a means of efficiently determining the paragraph number of a range of text. This code
108 | // attempts to optimize what would normally be a series linear searches by keeping track of the last paragraph number
109 | // found and uses that as the starting point for next paragraph number search. This works (mostly) because we
110 | // are generally asked for continguous increasing sequences of paragraph numbers. Also, this code is called in the
111 | // course of drawing a pagefull of text, and so even when moving back, the number of paragraphs to search for is
112 | // relativly low, even in really long bodies of text.
113 | //
114 | // This all falls down when the user edits the text, and can potentially invalidate the cached paragraph number which
115 | // causes a (potentially lengthy) search from the beginning of the string.
116 |
117 | if (charRange.location == self.lastParaLocation)
118 | return self.lastParaNumber;
119 | else if (charRange.location < self.lastParaLocation)
120 | {
121 | // We need to look backwards from the last known paragraph for the new paragraph range. This generally happens
122 | // when the text in the UITextView scrolls downward, revaling paragraphs before/above the ones previously drawn.
123 |
124 | NSString* s = self.textStorage.string;
125 | __block NSUInteger paraNumber = self.lastParaNumber;
126 |
127 | [s enumerateSubstringsInRange:NSMakeRange(charRange.location, self.lastParaLocation - charRange.location)
128 | options:NSStringEnumerationByParagraphs |
129 | NSStringEnumerationSubstringNotRequired |
130 | NSStringEnumerationReverse
131 | usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop){
132 | if (enclosingRange.location <= charRange.location) {
133 | *stop = YES;
134 | }
135 | --paraNumber;
136 | }];
137 |
138 | self.lastParaLocation = charRange.location;
139 | self.lastParaNumber = paraNumber;
140 |
141 | return paraNumber;
142 | }
143 | else
144 | {
145 | // We need to look forward from the last known paragraph for the new paragraph range. This generally happens
146 | // when the text in the UITextView scrolls upwards, revealing paragraphs that follow the ones previously drawn.
147 |
148 | NSString* s = self.textStorage.string;
149 | __block NSUInteger paraNumber = self.lastParaNumber;
150 |
151 | [s enumerateSubstringsInRange:NSMakeRange(self.lastParaLocation, charRange.location - self.lastParaLocation)
152 | options:NSStringEnumerationByParagraphs | NSStringEnumerationSubstringNotRequired
153 | usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop){
154 | if (enclosingRange.location >= charRange.location) {
155 | *stop = YES;
156 | }
157 | ++paraNumber;
158 | }];
159 |
160 | self.lastParaLocation = charRange.location;
161 | self.lastParaNumber = paraNumber;
162 |
163 | return paraNumber;
164 | }
165 | }
166 |
167 |
168 | #pragma mark - Layouting
169 |
170 | - (void)processEditingForTextStorage:(NSTextStorage *)textStorage edited:(NSTextStorageEditActions)editMask range:(NSRange)newCharRange changeInLength:(NSInteger)delta invalidatedRange:(NSRange)invalidatedCharRange
171 | {
172 | [super processEditingForTextStorage:textStorage edited:editMask range:newCharRange changeInLength:delta invalidatedRange:invalidatedCharRange];
173 |
174 | if (invalidatedCharRange.location < self.lastParaLocation)
175 | {
176 | // When the backing store is edited ahead the cached paragraph location, invalidate the cache and force a complete
177 | // recalculation. We cannot be much smarter than this because we don't know how many paragraphs have been deleted
178 | // since the text has already been removed from the backing store.
179 | self.lastParaLocation = 0;
180 | self.lastParaNumber = 0;
181 | }
182 | }
183 |
184 |
185 | #pragma mark - Drawing
186 |
187 | - (void) drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin
188 | {
189 | [super drawBackgroundForGlyphRange:glyphsToShow atPoint:origin];
190 |
191 | // Draw line numbers. Note that the background for line number gutter is drawn by the LineNumberTextView class.
192 | NSDictionary* atts = @{NSFontAttributeName : _lineNumberFont ,
193 | NSForegroundColorAttributeName : _lineNumberColor};
194 |
195 | [self enumerateLineFragmentsForGlyphRange:glyphsToShow
196 | usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer *textContainer, NSRange glyphRange, BOOL *stop) {
197 | NSRange charRange = [self characterRangeForGlyphRange:glyphRange actualGlyphRange:nil];
198 | NSRange paraRange = [self.textStorage.string paragraphRangeForRange:charRange];
199 |
200 | BOOL showCursorRect = NSLocationInRange(_selectedRange.location, paraRange);
201 |
202 | if (showCursorRect)
203 | {
204 | CGContextRef context = UIGraphicsGetCurrentContext();
205 | CGRect cursorRect = CGRectMake(0, usedRect.origin.y + 8, _gutterWidth, usedRect.size.height);
206 |
207 | CGContextSetFillColorWithColor(context, [UIColor colorWithWhite:0.9 alpha:1].CGColor);
208 | CGContextFillRect(context, cursorRect);
209 | }
210 |
211 | // Only draw line numbers for the paragraph's first line fragment. Subsequent fragments are wrapped portions of the paragraph and don't get the line number.
212 | if (charRange.location == paraRange.location) {
213 | CGRect gutterRect = CGRectOffset(CGRectMake(0, rect.origin.y, _gutterWidth, rect.size.height), origin.x, origin.y);
214 | NSUInteger paraNumber = [self _paraNumberForRange:charRange];
215 | NSString* ln = [NSString stringWithFormat:@"%ld", (unsigned long) paraNumber + 1];
216 | CGSize size = [ln sizeWithAttributes:atts];
217 |
218 | [ln drawInRect:CGRectOffset(gutterRect, CGRectGetWidth(gutterRect) - _lineAreaInset.right - size.width - _gutterWidth, (CGRectGetHeight(gutterRect) - size.height) / 2.0)
219 | withAttributes:atts];
220 | }
221 |
222 | }];
223 | }
224 |
225 | @end
226 |
--------------------------------------------------------------------------------
/NodelikeDemo/CYRTextStorage.h:
--------------------------------------------------------------------------------
1 | //
2 | // CYRTextStorage.h
3 | //
4 | // Version 0.2.0
5 | //
6 | // Created by Illya Busigin on 01/05/2014.
7 | // Copyright (c) 2014 Cyrillian, Inc.
8 | //
9 | // Distributed under MIT license.
10 | // Get the latest version from here:
11 | //
12 | // https://github.com/illyabusigin/CYRTextView
13 | //
14 | // The MIT License (MIT)
15 | //
16 | // Copyright (c) 2014 Cyrillian, Inc.
17 | //
18 | // Permission is hereby granted, free of charge, to any person obtaining a copy of
19 | // this software and associated documentation files (the "Software"), to deal in
20 | // the Software without restriction, including without limitation the rights to
21 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
22 | // the Software, and to permit persons to whom the Software is furnished to do so,
23 | // subject to the following conditions:
24 | //
25 | // The above copyright notice and this permission notice shall be included in all
26 | // copies or substantial portions of the Software.
27 | //
28 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
30 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
31 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
32 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 |
35 | #import
36 |
37 | @interface CYRTextStorage : NSTextStorage
38 |
39 | @property (nonatomic, strong) NSArray *tokens;
40 | @property (nonatomic, strong) UIFont *defaultFont;
41 |
42 | - (void)update;
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/NodelikeDemo/CYRTextStorage.m:
--------------------------------------------------------------------------------
1 | //
2 | // CYRTextStorage.m
3 | //
4 | // Version 0.2.0
5 | //
6 | // Created by Illya Busigin on 01/05/2014.
7 | // Copyright (c) 2014 Cyrillian, Inc.
8 | //
9 | // Distributed under MIT license.
10 | // Get the latest version from here:
11 | //
12 | // https://github.com/illyabusigin/CYRTextView
13 | //
14 | // The MIT License (MIT)
15 | //
16 | // Copyright (c) 2014 Cyrillian, Inc.
17 | //
18 | // Permission is hereby granted, free of charge, to any person obtaining a copy of
19 | // this software and associated documentation files (the "Software"), to deal in
20 | // the Software without restriction, including without limitation the rights to
21 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
22 | // the Software, and to permit persons to whom the Software is furnished to do so,
23 | // subject to the following conditions:
24 | //
25 | // The above copyright notice and this permission notice shall be included in all
26 | // copies or substantial portions of the Software.
27 | //
28 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
30 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
31 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
32 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 |
35 | #import "CYRTextStorage.h"
36 | #import "CYRToken.h"
37 |
38 | @interface CYRTextStorage ()
39 |
40 | @property (nonatomic, strong) NSMutableAttributedString *attributedString;
41 | @property (nonatomic, strong) NSMutableDictionary *regularExpressionCache;
42 |
43 | @end
44 |
45 | @implementation CYRTextStorage
46 |
47 | #pragma mark - Initialization & Setup
48 |
49 | - (id)init
50 | {
51 | if (self = [super init])
52 | {
53 | _defaultFont = [UIFont systemFontOfSize:12.0f];
54 | _attributedString = [NSMutableAttributedString new];
55 |
56 | _tokens = @[];
57 | _regularExpressionCache = @{}.mutableCopy;
58 | }
59 |
60 | return self;
61 | }
62 |
63 |
64 | #pragma mark - Overrides
65 |
66 | - (void)setTokens:(NSMutableArray *)tokens
67 | {
68 | _tokens = tokens;
69 |
70 | // Clear the regular expression cache
71 | [self.regularExpressionCache removeAllObjects];
72 |
73 | // Redraw all text
74 | [self update];
75 | }
76 |
77 | - (NSString *)string
78 | {
79 | return [_attributedString string];
80 | }
81 |
82 | - (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range
83 | {
84 | return [_attributedString attributesAtIndex:location effectiveRange:range];
85 | }
86 |
87 | - (void)replaceCharactersInRange:(NSRange)range withString:(NSString*)str
88 | {
89 | [self beginEditing];
90 |
91 | [_attributedString replaceCharactersInRange:range withString:str];
92 |
93 | [self edited:NSTextStorageEditedCharacters | NSTextStorageEditedAttributes range:range changeInLength:str.length - range.length];
94 | [self endEditing];
95 | }
96 |
97 | - (void)setAttributes:(NSDictionary*)attrs range:(NSRange)range
98 | {
99 | [self beginEditing];
100 |
101 | [_attributedString setAttributes:attrs range:range];
102 |
103 | [self edited:NSTextStorageEditedAttributes range:range changeInLength:0];
104 | [self endEditing];
105 | }
106 |
107 | -(void)processEditing
108 | {
109 | [self performReplacementsForRange:[self editedRange]];
110 | [super processEditing];
111 | }
112 |
113 | - (void)performReplacementsForRange:(NSRange)changedRange
114 | {
115 | NSRange extendedRange = NSUnionRange(changedRange, [[_attributedString string] lineRangeForRange:NSMakeRange(NSMaxRange(changedRange), 0)]);
116 |
117 | [self applyStylesToRange:extendedRange];
118 | }
119 |
120 |
121 | -(void)update
122 | {
123 | [self addAttributes:@{NSFontAttributeName : self.defaultFont} range:NSMakeRange(0, self.length)];
124 |
125 | [self applyStylesToRange:NSMakeRange(0, self.length)];
126 | }
127 |
128 | - (void)applyStylesToRange:(NSRange)searchRange
129 | {
130 | if (self.editedRange.location == NSNotFound)
131 | {
132 | return;
133 | }
134 |
135 | NSRange paragaphRange = [self.string paragraphRangeForRange: self.editedRange];
136 |
137 | // Reset the text attributes
138 | [self setAttributes:@{NSForegroundColorAttributeName : [UIColor blackColor]} range:paragaphRange];
139 |
140 | [self setAttributes:@{NSFontAttributeName : self.defaultFont} range:paragaphRange];
141 |
142 | for (CYRToken *attribute in self.tokens)
143 | {
144 | NSRegularExpression *regex = [self expressionForDefinition:attribute.name];
145 |
146 | [regex enumerateMatchesInString:self.string options:0 range:paragaphRange
147 | usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
148 |
149 | [attribute.attributes enumerateKeysAndObjectsUsingBlock:^(NSString *attributeName, id attributeValue, BOOL *stop) {
150 | [self addAttribute:attributeName value:attributeValue range:result.range];
151 | }];
152 | }];
153 | }
154 | }
155 |
156 | - (NSRegularExpression *)expressionForDefinition:(NSString *)definition
157 | {
158 | __block CYRToken *attribute = nil;
159 |
160 | [self.tokens enumerateObjectsUsingBlock:^(CYRToken *enumeratedAttribute, NSUInteger idx, BOOL *stop) {
161 | if ([enumeratedAttribute.name isEqualToString:definition])
162 | {
163 | attribute = enumeratedAttribute;
164 | *stop = YES;
165 | }
166 | }];
167 |
168 | NSRegularExpression *expression = self.regularExpressionCache[attribute.expression];
169 |
170 | if (!expression)
171 | {
172 | expression = [NSRegularExpression regularExpressionWithPattern:attribute.expression
173 | options:NSRegularExpressionCaseInsensitive error:nil];
174 |
175 | [self.regularExpressionCache setObject:expression forKey:definition];
176 | }
177 |
178 | return expression;
179 | }
180 |
181 | @end
182 |
--------------------------------------------------------------------------------
/NodelikeDemo/CYRTextView.h:
--------------------------------------------------------------------------------
1 | //
2 | // CYRTextView.h
3 | //
4 | // Version 0.2.0
5 | //
6 | // Created by Illya Busigin on 01/05/2014.
7 | // Copyright (c) 2014 Cyrillian, Inc.
8 | // Copyright (c) 2013 Dominik Hauser
9 | // Copyright (c) 2013 Sam Rijs
10 | //
11 | // Distributed under MIT license.
12 | // Get the latest version from here:
13 | //
14 | // https://github.com/illyabusigin/CYRTextView
15 | // Gestures sourced from: https://github.com/srijs/NLTextView
16 | //
17 | // The MIT License (MIT)
18 | //
19 | // Copyright (c) 2014 Cyrillian, Inc.
20 | //
21 | // Permission is hereby granted, free of charge, to any person obtaining a copy of
22 | // this software and associated documentation files (the "Software"), to deal in
23 | // the Software without restriction, including without limitation the rights to
24 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
25 | // the Software, and to permit persons to whom the Software is furnished to do so,
26 | // subject to the following conditions:
27 | //
28 | // The above copyright notice and this permission notice shall be included in all
29 | // copies or substantial portions of the Software.
30 | //
31 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
33 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
34 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
35 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
36 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 |
38 | #import
39 | #import "CYRToken.h"
40 |
41 | @interface CYRTextView : UITextView
42 |
43 | @property (nonatomic, strong) NSArray *tokens;
44 | @property (nonatomic, strong) UIPanGestureRecognizer *singleFingerPanRecognizer;
45 | @property (nonatomic, strong) UIPanGestureRecognizer *doubleFingerPanRecognizer;
46 |
47 | @property UIColor *gutterBackgroundColor;
48 | @property UIColor *gutterLineColor;
49 |
50 | @property (nonatomic, assign) BOOL lineCursorEnabled;
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/NodelikeDemo/CYRTextView.m:
--------------------------------------------------------------------------------
1 | //
2 | // CYRTextView.m
3 | //
4 | // Version 0.2.0
5 | //
6 | // Created by Illya Busigin on 01/05/2014.
7 | // Copyright (c) 2014 Cyrillian, Inc.
8 | // Copyright (c) 2013 Dominik Hauser
9 | // Copyright (c) 2013 Sam Rijs
10 | //
11 | // Distributed under MIT license.
12 | // Get the latest version from here:
13 | //
14 | // https://github.com/illyabusigin/CYRTextView
15 | //
16 | // The MIT License (MIT)
17 | //
18 | // Copyright (c) 2014 Cyrillian, Inc.
19 | //
20 | // Permission is hereby granted, free of charge, to any person obtaining a copy of
21 | // this software and associated documentation files (the "Software"), to deal in
22 | // the Software without restriction, including without limitation the rights to
23 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
24 | // the Software, and to permit persons to whom the Software is furnished to do so,
25 | // subject to the following conditions:
26 | //
27 | // The above copyright notice and this permission notice shall be included in all
28 | // copies or substantial portions of the Software.
29 | //
30 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
32 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
33 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
34 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
35 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 |
37 | #import "CYRTextView.h"
38 | #import "CYRLayoutManager.h"
39 | #import "CYRTextStorage.h"
40 |
41 | #define RGB(r,g,b) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:1.0f]
42 |
43 | static void *CYRTextViewContext = &CYRTextViewContext;
44 | static const float kCursorVelocity = 1.0f/8.0f;
45 |
46 | @interface CYRTextView ()
47 |
48 | @property (nonatomic, strong) CYRLayoutManager *lineNumberLayoutManager;
49 | @property (nonatomic, strong) CYRTextStorage *syntaxTextStorage;
50 |
51 | @end
52 |
53 | @implementation CYRTextView
54 | {
55 | NSRange startRange;
56 | }
57 |
58 | #pragma mark - Initialization & Setup
59 |
60 | - (id)initWithFrame:(CGRect)frame
61 | {
62 | CYRTextStorage *textStorage = [CYRTextStorage new];
63 | CYRLayoutManager *layoutManager = [CYRLayoutManager new];
64 |
65 | self.lineNumberLayoutManager = layoutManager;
66 |
67 | NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];
68 |
69 | // Wrap text to the text view's frame
70 | textContainer.widthTracksTextView = YES;
71 |
72 | [layoutManager addTextContainer:textContainer];
73 |
74 | [textStorage removeLayoutManager:textStorage.layoutManagers.firstObject];
75 | [textStorage addLayoutManager:layoutManager];
76 |
77 | self.syntaxTextStorage = textStorage;
78 |
79 | if ((self = [super initWithFrame:frame textContainer:textContainer]))
80 | {
81 | self.contentMode = UIViewContentModeRedraw; // causes drawRect: to be called on frame resizing and device rotation
82 |
83 | [self _commonSetup];
84 | }
85 |
86 | return self;
87 | }
88 |
89 | - (void)_commonSetup
90 | {
91 | // Setup observers
92 | [self addObserver:self forKeyPath:NSStringFromSelector(@selector(font)) options:NSKeyValueObservingOptionNew context:CYRTextViewContext];
93 | [self addObserver:self forKeyPath:NSStringFromSelector(@selector(selectedTextRange)) options:NSKeyValueObservingOptionNew context:CYRTextViewContext];
94 | [self addObserver:self forKeyPath:NSStringFromSelector(@selector(selectedRange)) options:NSKeyValueObservingOptionNew context:CYRTextViewContext];
95 |
96 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleTextViewDidChangeNotification:) name:UITextViewTextDidChangeNotification object:self];
97 |
98 | // Setup defaults
99 | self.font = [UIFont systemFontOfSize:16.0f];
100 | self.autocapitalizationType = UITextAutocapitalizationTypeNone;
101 | self.autocorrectionType = UITextAutocorrectionTypeNo;
102 | self.lineCursorEnabled = YES;
103 | self.gutterBackgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
104 | self.gutterLineColor = [UIColor lightGrayColor];
105 |
106 | // Inset the content to make room for line numbers
107 | self.textContainerInset = UIEdgeInsetsMake(8, self.lineNumberLayoutManager.gutterWidth, 8, 0);
108 |
109 | // Setup the gesture recognizers
110 | _singleFingerPanRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(singleFingerPanHappend:)];
111 | _singleFingerPanRecognizer.maximumNumberOfTouches = 1;
112 | [self addGestureRecognizer:_singleFingerPanRecognizer];
113 |
114 | _doubleFingerPanRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(doubleFingerPanHappend:)];
115 | _doubleFingerPanRecognizer.minimumNumberOfTouches = 2;
116 | [self addGestureRecognizer:_doubleFingerPanRecognizer];
117 | }
118 |
119 |
120 | #pragma mark - Cleanup
121 |
122 | - (void)dealloc
123 | {
124 | [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(font))];
125 | [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(selectedTextRange))];
126 | [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(selectedRange))];
127 | }
128 |
129 |
130 | #pragma mark - KVO
131 |
132 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
133 | {
134 | if ([keyPath isEqualToString:NSStringFromSelector(@selector(font))] && context == CYRTextViewContext)
135 | {
136 | // Whenever the UITextView font is changed we want to keep a reference in the stickyFont ivar. We do this to counteract a bug where the underlying font can be changed without notice and cause undesired behaviour.
137 | self.syntaxTextStorage.defaultFont = self.font;
138 | }
139 | else if (([keyPath isEqualToString:NSStringFromSelector(@selector(selectedTextRange))] ||
140 | [keyPath isEqualToString:NSStringFromSelector(@selector(selectedRange))]) && context == CYRTextViewContext)
141 | {
142 | [self setNeedsDisplay];
143 | }
144 | else
145 | {
146 | [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
147 | }
148 | }
149 |
150 |
151 | #pragma mark - Notifications
152 |
153 | - (void)handleTextViewDidChangeNotification:(NSNotification *)notification
154 | {
155 | if (notification.object == self)
156 | {
157 | CGRect line = [self caretRectForPosition: self.selectedTextRange.start];
158 | CGFloat overflow = line.origin.y + line.size.height - ( self.contentOffset.y + self.bounds.size.height - self.contentInset.bottom - self.contentInset.top );
159 |
160 | if ( overflow > 0 )
161 | {
162 | // We are at the bottom of the visible text and introduced a line feed, scroll down (iOS 7 does not do it)
163 | // Scroll caret to visible area
164 | CGPoint offset = self.contentOffset;
165 | offset.y += overflow + 7; // leave 7 pixels margin
166 | // Cannot animate with setContentOffset:animated: or caret will not appear
167 | // [UIView animateWithDuration:.2 animations:^{
168 | // [self setContentOffset:offset];
169 | // }];
170 | }
171 | }
172 | }
173 |
174 |
175 | #pragma mark - Overrides
176 |
177 | - (void)setTokens:(NSMutableArray *)tokens
178 | {
179 | [self.syntaxTextStorage setTokens:tokens];
180 | }
181 |
182 | - (NSArray *)tokens
183 | {
184 | CYRTextStorage *syntaxTextStorage = (CYRTextStorage *)self.textStorage;
185 |
186 | return syntaxTextStorage.tokens;
187 | }
188 |
189 | - (void)setText:(NSString *)text
190 | {
191 | UITextRange *textRange = [self textRangeFromPosition:self.beginningOfDocument toPosition:self.endOfDocument];
192 | [self replaceRange:textRange withText:text];
193 | }
194 |
195 |
196 | #pragma mark - Line Drawing
197 |
198 | // Original implementation sourced from: https://github.com/alldritt/TextKit_LineNumbers
199 | - (void)drawRect:(CGRect)rect
200 | {
201 | // Drag the line number gutter background. The line numbers them selves are drawn by LineNumberLayoutManager.
202 | CGContextRef context = UIGraphicsGetCurrentContext();
203 | CGRect bounds = self.bounds;
204 |
205 | CGFloat height = MAX(CGRectGetHeight(bounds), self.contentSize.height) + 200;
206 |
207 | // Set the regular fill
208 | CGContextSetFillColorWithColor(context, self.gutterBackgroundColor.CGColor);
209 | CGContextFillRect(context, CGRectMake(bounds.origin.x, bounds.origin.y, self.lineNumberLayoutManager.gutterWidth, height));
210 |
211 | // Draw line
212 | CGContextSetFillColorWithColor(context, self.gutterLineColor.CGColor);
213 | CGContextFillRect(context, CGRectMake(self.lineNumberLayoutManager.gutterWidth, bounds.origin.y, 0.5, height));
214 |
215 | if (_lineCursorEnabled)
216 | {
217 | self.lineNumberLayoutManager.selectedRange = self.selectedRange;
218 |
219 | NSRange glyphRange = [self.lineNumberLayoutManager.textStorage.string paragraphRangeForRange:self.selectedRange];
220 | glyphRange = [self.lineNumberLayoutManager glyphRangeForCharacterRange:glyphRange actualCharacterRange:NULL];
221 | self.lineNumberLayoutManager.selectedRange = glyphRange;
222 | [self.lineNumberLayoutManager invalidateDisplayForGlyphRange:glyphRange];
223 | }
224 |
225 | [super drawRect:rect];
226 | }
227 |
228 |
229 | #pragma mark - Gestures
230 |
231 | // Sourced from: https://github.com/srijs/NLTextView
232 | - (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer
233 | {
234 | // Only accept horizontal pans for the code navigation to preserve correct scrolling behaviour.
235 | if (gestureRecognizer == _singleFingerPanRecognizer || gestureRecognizer == _doubleFingerPanRecognizer)
236 | {
237 | CGPoint translation = [gestureRecognizer translationInView:self];
238 | return fabsf(translation.x) > fabsf(translation.y);
239 | }
240 |
241 | return YES;
242 |
243 | }
244 |
245 | // Sourced from: https://github.com/srijs/NLTextView
246 | - (void)singleFingerPanHappend:(UIPanGestureRecognizer *)sender
247 | {
248 | if (sender.state == UIGestureRecognizerStateBegan)
249 | {
250 | startRange = self.selectedRange;
251 | }
252 |
253 | CGFloat cursorLocation = MAX(startRange.location + [sender translationInView:self].x * kCursorVelocity, 0);
254 |
255 | self.selectedRange = NSMakeRange(cursorLocation, 0);
256 | }
257 |
258 | // Sourced from: https://github.com/srijs/NLTextView
259 | - (void)doubleFingerPanHappend:(UIPanGestureRecognizer *)sender
260 | {
261 | if (sender.state == UIGestureRecognizerStateBegan)
262 | {
263 | startRange = self.selectedRange;
264 | }
265 |
266 | CGFloat cursorLocation = MAX(startRange.location + [sender translationInView:self].x * kCursorVelocity, 0);
267 |
268 | if (cursorLocation > startRange.location)
269 | {
270 | self.selectedRange = NSMakeRange(startRange.location, fabsf(startRange.location - cursorLocation));
271 | }
272 | else
273 | {
274 | self.selectedRange = NSMakeRange(cursorLocation, fabsf(startRange.location - cursorLocation));
275 | }
276 | }
277 |
278 | @end
279 |
--------------------------------------------------------------------------------
/NodelikeDemo/CYRToken.h:
--------------------------------------------------------------------------------
1 | //
2 | // CYRTextAttribute.h
3 | //
4 | // Version 0.2.0
5 | //
6 | // Created by Illya Busigin on 01/05/2014.
7 | // Copyright (c) 2014 Cyrillian, Inc.
8 | //
9 | // Distributed under MIT license.
10 | // Get the latest version from here:
11 | //
12 | // https://github.com/illyabusigin/CYRTextView
13 | //
14 | // The MIT License (MIT)
15 | //
16 | // Copyright (c) 2014 Cyrillian, Inc.
17 | //
18 | // Permission is hereby granted, free of charge, to any person obtaining a copy of
19 | // this software and associated documentation files (the "Software"), to deal in
20 | // the Software without restriction, including without limitation the rights to
21 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
22 | // the Software, and to permit persons to whom the Software is furnished to do so,
23 | // subject to the following conditions:
24 | //
25 | // The above copyright notice and this permission notice shall be included in all
26 | // copies or substantial portions of the Software.
27 | //
28 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
30 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
31 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
32 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 |
35 | #import
36 |
37 | @interface CYRToken : NSObject
38 |
39 | @property (nonatomic, strong) NSString *name;
40 | @property (nonatomic, strong) NSString *expression;
41 | @property (nonatomic, strong) NSDictionary *attributes;
42 |
43 | + (instancetype)tokenWithName:(NSString *)name expression:(NSString *)expression attributes:(NSDictionary *)attributes;
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/NodelikeDemo/CYRToken.m:
--------------------------------------------------------------------------------
1 | //
2 | // CYRTextAttribute.m
3 | //
4 | // Version 0.2.0
5 | //
6 | // Created by Illya Busigin on 01/05/2014.
7 | // Copyright (c) 2014 Cyrillian, Inc.
8 | //
9 | // Distributed under MIT license.
10 | // Get the latest version from here:
11 | //
12 | // https://github.com/illyabusigin/CYRTextView
13 | //
14 | // The MIT License (MIT)
15 | //
16 | // Copyright (c) 2014 Cyrillian, Inc.
17 | //
18 | // Permission is hereby granted, free of charge, to any person obtaining a copy of
19 | // this software and associated documentation files (the "Software"), to deal in
20 | // the Software without restriction, including without limitation the rights to
21 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
22 | // the Software, and to permit persons to whom the Software is furnished to do so,
23 | // subject to the following conditions:
24 | //
25 | // The above copyright notice and this permission notice shall be included in all
26 | // copies or substantial portions of the Software.
27 | //
28 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
30 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
31 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
32 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 |
35 | #import "CYRToken.h"
36 |
37 | @implementation CYRToken
38 |
39 | + (instancetype)tokenWithName:(NSString *)name expression:(NSString *)expression attributes:(NSDictionary *)attributes
40 | {
41 | CYRToken *textAttribute = [CYRToken new];
42 |
43 | textAttribute.name = name;
44 | textAttribute.expression = expression;
45 | textAttribute.attributes = attributes;
46 |
47 | return textAttribute;
48 | }
49 |
50 | @end
51 |
--------------------------------------------------------------------------------
/NodelikeDemo/FHSegmentedViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // KPSegmentedViewController.h
3 | // KPKuaiPai
4 | //
5 | // Created by Johnny iDay on 13-12-14.
6 | // Copyright (c) 2013年 Johnny iDay. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FHSegmentedViewController : UIViewController
12 |
13 | @property(nonatomic, assign) UIViewController *selectedViewController;
14 | @property(nonatomic, strong) IBOutlet UISegmentedControl *segmentedControl;
15 | @property(nonatomic, assign) NSInteger selectedViewControllerIndex;
16 |
17 | - (void)setViewControllers:(NSArray *)viewControllers;
18 | - (void)setViewControllers:(NSArray *)viewControllers titles:(NSArray *)titles;
19 | - (void)setViewControllers:(NSArray *)viewControllers imagesNamed:(NSArray *)imageNames;
20 | - (void)setViewControllers:(NSArray *)viewControllers images:(NSArray *)images;
21 | - (void)pushViewController:(UIViewController *)viewController;
22 | - (void)pushViewController:(UIViewController *)viewController title:(NSString *)title;
23 | - (void)pushViewController:(UIViewController *)viewController imageNamed:(NSString *)imageName;
24 | - (void)pushViewController:(UIViewController *)viewController image:(UIImage *)image;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/NodelikeDemo/FHSegmentedViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // KPSegmentedViewController.m
3 | // KPKuaiPai
4 | //
5 | // Created by Johnny iDay on 13-12-14.
6 | // Copyright (c) 2013年 Johnny iDay. All rights reserved.
7 | //
8 |
9 | #import "FHSegmentedViewController.h"
10 |
11 | @interface FHSegmentedViewController ()
12 |
13 | @end
14 |
15 | @implementation FHSegmentedViewController
16 |
17 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
18 | {
19 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
20 | if (self) {
21 | // Custom initialization
22 | }
23 | return self;
24 | }
25 |
26 | - (void)viewDidLoad
27 | {
28 | [super viewDidLoad];
29 | // Do any additional setup after loading the view.
30 |
31 | if (!_segmentedControl) {
32 | _segmentedControl = [[UISegmentedControl alloc] init];
33 | _segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
34 | self.navigationItem.titleView = _segmentedControl;
35 | } else {
36 | [_segmentedControl removeAllSegments];
37 | }
38 | [_segmentedControl addTarget:self action:@selector(segmentedControlSelected:) forControlEvents:UIControlEventValueChanged];
39 | }
40 |
41 | - (void)didReceiveMemoryWarning
42 | {
43 | [super didReceiveMemoryWarning];
44 | // Dispose of any resources that can be recreated.
45 | }
46 |
47 | - (void)setViewControllers:(NSArray *)viewControllers titles:(NSArray *)titles
48 | {
49 | if ([_segmentedControl numberOfSegments] > 0) {
50 | return;
51 | }
52 | for (int i = 0; i < [viewControllers count]; i++) {
53 | [self pushViewController:viewControllers[i] title:titles[i]];
54 | }
55 | [_segmentedControl setSelectedSegmentIndex:0];
56 | self.selectedViewControllerIndex = 0;
57 | }
58 |
59 | - (void)setViewControllers:(NSArray *)viewControllers imagesNamed:(NSArray *)imageNames {
60 | if ([_segmentedControl numberOfSegments] > 0) {
61 | return;
62 | }
63 | for (int i = 0; i < [viewControllers count]; i++) {
64 | [self pushViewController:viewControllers[i] imageNamed:imageNames[i]];
65 | }
66 | [_segmentedControl setSelectedSegmentIndex:0];
67 | self.selectedViewControllerIndex = 0;
68 | }
69 |
70 | - (void)setViewControllers:(NSArray *)viewControllers images:(NSArray *)images {
71 | if ([_segmentedControl numberOfSegments] > 0) {
72 | return;
73 | }
74 | for (int i = 0; i < [viewControllers count]; i++) {
75 | [self pushViewController:viewControllers[i] image:images[i]];
76 | }
77 | [_segmentedControl setSelectedSegmentIndex:0];
78 | self.selectedViewControllerIndex = 0;
79 | }
80 |
81 | - (void)setViewControllers:(NSArray *)viewControllers
82 | {
83 | if ([_segmentedControl numberOfSegments] > 0) {
84 | return;
85 | }
86 | for (int i = 0; i < [viewControllers count]; i++) {
87 | [self pushViewController:viewControllers[i] title:[viewControllers[i] title]];
88 | }
89 | [_segmentedControl setSelectedSegmentIndex:0];
90 | self.selectedViewControllerIndex = 0;
91 | }
92 |
93 | - (void)pushViewController:(UIViewController *)viewController
94 | {
95 | [self pushViewController:viewController title:viewController.title];
96 | }
97 | - (void)pushViewController:(UIViewController *)viewController title:(NSString *)title
98 | {
99 | [_segmentedControl insertSegmentWithTitle:title atIndex:_segmentedControl.numberOfSegments animated:NO];
100 | [self addChildViewController:viewController];
101 | [_segmentedControl sizeToFit];
102 | }
103 |
104 | - (void)pushViewController:(UIViewController *)viewController imageNamed:(NSString *)imageName
105 | {
106 | [_segmentedControl insertSegmentWithImage:[UIImage imageNamed:imageName] atIndex:_segmentedControl.numberOfSegments animated:NO];
107 | [self addChildViewController:viewController];
108 | [_segmentedControl sizeToFit];
109 | }
110 |
111 | - (void)pushViewController:(UIViewController *)viewController image:(UIImage *)image {
112 | [_segmentedControl insertSegmentWithImage:image atIndex:_segmentedControl.numberOfSegments animated:NO];
113 | [self addChildViewController:viewController];
114 | [_segmentedControl sizeToFit];
115 | }
116 |
117 | - (void)segmentedControlSelected:(id)sender
118 | {
119 | self.selectedViewControllerIndex = _segmentedControl.selectedSegmentIndex;
120 | }
121 |
122 | - (void)setSelectedViewControllerIndex:(NSInteger)index
123 | {
124 | if (!_selectedViewController) {
125 | _selectedViewController = self.childViewControllers[index];
126 | if ([[UIDevice currentDevice].systemVersion floatValue] < 7.0f) {
127 | CGFloat deltaTop = 20.0f;
128 | if (self.navigationController && !self.navigationController.navigationBar.translucent) {
129 | deltaTop = self.navigationController.navigationBar.frame.size.height;
130 | }
131 | CGRect frame = self.view.frame;
132 | [_selectedViewController view].frame = CGRectMake(frame.origin.x, frame.origin.y - deltaTop, frame.size.width, frame.size.height);
133 | // [[_selectedViewController view] sizeToFit];
134 | } else {
135 | [_selectedViewController view].frame = self.view.frame;
136 | }
137 | [self.view addSubview:[_selectedViewController view]];
138 | [_selectedViewController didMoveToParentViewController:self];
139 | } else if (index != _selectedViewControllerIndex) {
140 | if ([[UIDevice currentDevice].systemVersion floatValue] < 7.0f) {
141 | [self.childViewControllers[index] view].frame = self.view.frame;
142 | }
143 | [self transitionFromViewController:_selectedViewController toViewController:self.childViewControllers[index] duration:0.0f options:UIViewAnimationOptionTransitionNone animations:nil completion:^(BOOL finished) {
144 | _selectedViewController = self.childViewControllers[index];
145 | _selectedViewControllerIndex = index;
146 | }];
147 | }
148 | }
149 |
150 | @end
151 |
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "29x29",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-Small.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "29x29",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-Small@2x.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "40x40",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-Spotlight-40@2x.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "idiom" : "iphone",
23 | "size" : "57x57",
24 | "scale" : "1x"
25 | },
26 | {
27 | "idiom" : "iphone",
28 | "size" : "57x57",
29 | "scale" : "2x"
30 | },
31 | {
32 | "size" : "60x60",
33 | "idiom" : "iphone",
34 | "filename" : "Icon-60@2x.png",
35 | "scale" : "2x"
36 | },
37 | {
38 | "size" : "29x29",
39 | "idiom" : "ipad",
40 | "filename" : "Icon-Small-1.png",
41 | "scale" : "1x"
42 | },
43 | {
44 | "size" : "29x29",
45 | "idiom" : "ipad",
46 | "filename" : "Icon-Small@2x-1.png",
47 | "scale" : "2x"
48 | },
49 | {
50 | "size" : "40x40",
51 | "idiom" : "ipad",
52 | "filename" : "Icon-Spotlight-40.png",
53 | "scale" : "1x"
54 | },
55 | {
56 | "size" : "40x40",
57 | "idiom" : "ipad",
58 | "filename" : "Icon-Spotlight-40@2x-1.png",
59 | "scale" : "2x"
60 | },
61 | {
62 | "idiom" : "ipad",
63 | "size" : "50x50",
64 | "scale" : "1x"
65 | },
66 | {
67 | "idiom" : "ipad",
68 | "size" : "50x50",
69 | "scale" : "2x"
70 | },
71 | {
72 | "idiom" : "ipad",
73 | "size" : "72x72",
74 | "scale" : "1x"
75 | },
76 | {
77 | "idiom" : "ipad",
78 | "size" : "72x72",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "76x76",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-76.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "76x76",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-76@2x.png",
91 | "scale" : "2x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-76.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-Small-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-Small-1.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-Small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-Small.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x-1.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/KOKeyboard/hal-black.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "hal-black.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "hal-black@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/KOKeyboard/hal-black.imageset/hal-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/KOKeyboard/hal-black.imageset/hal-black.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/KOKeyboard/hal-black.imageset/hal-black@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/KOKeyboard/hal-black.imageset/hal-black@2x.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/KOKeyboard/hal-blue.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "hal-blue.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "hal-blue@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/KOKeyboard/hal-blue.imageset/hal-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/KOKeyboard/hal-blue.imageset/hal-blue.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/KOKeyboard/hal-blue.imageset/hal-blue@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/KOKeyboard/hal-blue.imageset/hal-blue@2x.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/KOKeyboard/hal-white.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "hal-white.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "hal-white@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/KOKeyboard/hal-white.imageset/hal-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/KOKeyboard/hal-white.imageset/hal-white.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/KOKeyboard/hal-white.imageset/hal-white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/KOKeyboard/hal-white.imageset/hal-white@2x.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "7.0",
8 | "filename" : "launch-phone@2x.png",
9 | "scale" : "2x"
10 | },
11 | {
12 | "extent" : "full-screen",
13 | "idiom" : "iphone",
14 | "subtype" : "retina4",
15 | "filename" : "launch-phone-r4-1.png",
16 | "minimum-system-version" : "7.0",
17 | "orientation" : "portrait",
18 | "scale" : "2x"
19 | },
20 | {
21 | "orientation" : "portrait",
22 | "idiom" : "ipad",
23 | "extent" : "full-screen",
24 | "minimum-system-version" : "7.0",
25 | "filename" : "launch-pad.png",
26 | "scale" : "1x"
27 | },
28 | {
29 | "orientation" : "landscape",
30 | "idiom" : "ipad",
31 | "extent" : "full-screen",
32 | "minimum-system-version" : "7.0",
33 | "filename" : "launch-pad-land.png",
34 | "scale" : "1x"
35 | },
36 | {
37 | "orientation" : "portrait",
38 | "idiom" : "ipad",
39 | "extent" : "full-screen",
40 | "minimum-system-version" : "7.0",
41 | "filename" : "launch-pad@2x.png",
42 | "scale" : "2x"
43 | },
44 | {
45 | "orientation" : "landscape",
46 | "idiom" : "ipad",
47 | "extent" : "full-screen",
48 | "minimum-system-version" : "7.0",
49 | "filename" : "launch-pad-land@2x.png",
50 | "scale" : "2x"
51 | },
52 | {
53 | "orientation" : "portrait",
54 | "idiom" : "iphone",
55 | "extent" : "full-screen",
56 | "scale" : "1x"
57 | },
58 | {
59 | "orientation" : "portrait",
60 | "idiom" : "iphone",
61 | "extent" : "full-screen",
62 | "scale" : "2x"
63 | },
64 | {
65 | "orientation" : "portrait",
66 | "idiom" : "iphone",
67 | "extent" : "full-screen",
68 | "subtype" : "retina4",
69 | "scale" : "2x"
70 | },
71 | {
72 | "orientation" : "portrait",
73 | "idiom" : "ipad",
74 | "extent" : "to-status-bar",
75 | "scale" : "1x"
76 | },
77 | {
78 | "orientation" : "portrait",
79 | "idiom" : "ipad",
80 | "extent" : "full-screen",
81 | "scale" : "1x"
82 | },
83 | {
84 | "orientation" : "landscape",
85 | "idiom" : "ipad",
86 | "extent" : "to-status-bar",
87 | "scale" : "1x"
88 | },
89 | {
90 | "orientation" : "landscape",
91 | "idiom" : "ipad",
92 | "extent" : "full-screen",
93 | "scale" : "1x"
94 | },
95 | {
96 | "orientation" : "portrait",
97 | "idiom" : "ipad",
98 | "extent" : "to-status-bar",
99 | "scale" : "2x"
100 | },
101 | {
102 | "orientation" : "portrait",
103 | "idiom" : "ipad",
104 | "extent" : "full-screen",
105 | "scale" : "2x"
106 | },
107 | {
108 | "orientation" : "landscape",
109 | "idiom" : "ipad",
110 | "extent" : "to-status-bar",
111 | "scale" : "2x"
112 | },
113 | {
114 | "orientation" : "landscape",
115 | "idiom" : "ipad",
116 | "extent" : "full-screen",
117 | "scale" : "2x"
118 | }
119 | ],
120 | "info" : {
121 | "version" : 1,
122 | "author" : "xcode"
123 | }
124 | }
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/LaunchImage.launchimage/launch-pad-land.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/LaunchImage.launchimage/launch-pad-land.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/LaunchImage.launchimage/launch-pad-land@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/LaunchImage.launchimage/launch-pad-land@2x.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/LaunchImage.launchimage/launch-pad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/LaunchImage.launchimage/launch-pad.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/LaunchImage.launchimage/launch-pad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/LaunchImage.launchimage/launch-pad@2x.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/LaunchImage.launchimage/launch-phone-r4-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/LaunchImage.launchimage/launch-phone-r4-1.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/LaunchImage.launchimage/launch-phone@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/LaunchImage.launchimage/launch-phone@2x.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/bookmarks.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "bookmarks.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "bookmarks@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/bookmarks.imageset/bookmarks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/bookmarks.imageset/bookmarks.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/bookmarks.imageset/bookmarks@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/bookmarks.imageset/bookmarks@2x.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/info.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "info.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "info@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/info.imageset/info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/info.imageset/info.png
--------------------------------------------------------------------------------
/NodelikeDemo/Images.xcassets/info.imageset/info@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/NodelikeDemo/Images.xcassets/info.imageset/info@2x.png
--------------------------------------------------------------------------------
/NodelikeDemo/Interpreter-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleDocumentTypes
10 |
11 |
12 | CFBundleTypeName
13 | JavaScript
14 | CFBundleTypeRole
15 | Viewer
16 | LSHandlerRank
17 | Default
18 | LSItemContentTypes
19 |
20 | public.text
21 |
22 |
23 |
24 | CFBundleExecutable
25 | ${EXECUTABLE_NAME}
26 | CFBundleIdentifier
27 | de.awesam.${PRODUCT_NAME:rfc1034identifier}
28 | CFBundleInfoDictionaryVersion
29 | 6.0
30 | CFBundleName
31 | ${PRODUCT_NAME}
32 | CFBundlePackageType
33 | APPL
34 | CFBundleShortVersionString
35 | 1.2.0
36 | CFBundleSignature
37 | ????
38 | CFBundleVersion
39 | 145036003
40 | LSRequiresIPhoneOS
41 |
42 | UILaunchStoryboardName
43 | LaunchScreen
44 | UIMainStoryboardFile
45 | Main
46 | UIMainStoryboardFile~ipad
47 | Main
48 | UIRequiredDeviceCapabilities
49 |
50 | armv7
51 |
52 | UIStatusBarStyle
53 | UIStatusBarStyleBlackOpaque
54 | UISupportedInterfaceOrientations
55 |
56 | UIInterfaceOrientationPortrait
57 |
58 | UISupportedInterfaceOrientations~ipad
59 |
60 | UIInterfaceOrientationPortrait
61 | UIInterfaceOrientationLandscapeLeft
62 | UIInterfaceOrientationLandscapeRight
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/NodelikeDemo/Interpreter-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header
3 | //
4 | // The contents of this file are implicitly included at the beginning of every source file.
5 | //
6 |
7 | #import
8 |
9 | #ifndef __IPHONE_5_0
10 | #warning "This project uses features only available in iOS SDK 5.0 and later."
11 | #endif
12 |
13 | #ifdef __OBJC__
14 | #import
15 | #import
16 | #endif
--------------------------------------------------------------------------------
/NodelikeDemo/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/NodelikeDemo/NLAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // NLAppDelegate.h
3 | // NodelikeDemo
4 | //
5 | // Created by Sam Rijs on 10/13/13.
6 | // Copyright (c) 2013 Sam Rijs. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import
12 |
13 | @interface NLAppDelegate : UIResponder
14 |
15 | @property (strong, nonatomic) UIWindow *window;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/NodelikeDemo/NLAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // NLAppDelegate.m
3 | // NodelikeDemo
4 | //
5 | // Created by Sam Rijs on 10/13/13.
6 | // Copyright (c) 2013 Sam Rijs. All rights reserved.
7 | //
8 |
9 | #import "NLAppDelegate.h"
10 |
11 | #import "NLContext.h"
12 |
13 | @implementation NLAppDelegate {
14 | NSString *scriptToLoad;
15 | }
16 |
17 | - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
18 |
19 | NSString *script = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
20 |
21 | if (script) {
22 |
23 | scriptToLoad = script;
24 |
25 | UIAlertView *alert = [[UIAlertView alloc]
26 | initWithTitle:@"Open File"
27 | message:@"You are about to load a file into the editor. This will clear your current script."
28 | delegate:self
29 | cancelButtonTitle:@"Cancel"
30 | otherButtonTitles:@"OK",
31 | nil];
32 | [alert show];
33 |
34 | }
35 |
36 | return YES;
37 | }
38 |
39 | - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
40 | if ([[alertView buttonTitleAtIndex:buttonIndex] isEqualToString:@"OK"]) {
41 | [NSNotificationCenter.defaultCenter postNotificationName:@"NLFileOpen" object:nil userInfo:@{@"script": scriptToLoad}];
42 | }
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/NodelikeDemo/NLColor.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+NLColor.h
3 | // Interpreter
4 | //
5 | // Created by Sam Rijs on 11/20/13.
6 | // Copyright (c) 2013 Sam Rijs. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NLColor : UIColor
12 |
13 | + (UIColor *)greenColor;
14 | + (UIColor *)blackColor;
15 | + (UIColor *)beigeColor;
16 | + (UIColor *)whiteColor;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/NodelikeDemo/NLColor.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+NLColor.m
3 | // Interpreter
4 | //
5 | // Created by Sam Rijs on 11/20/13.
6 | // Copyright (c) 2013 Sam Rijs. All rights reserved.
7 | //
8 |
9 | #import "NLColor.h"
10 |
11 | @implementation NLColor
12 |
13 | + (UIColor *)greenColor { return [self colorWithRed:163/255. green:232/255. blue: 54/255. alpha:1]; }
14 | + (UIColor *)blackColor { return [self colorWithRed: 34/255. green: 34/255. blue: 34/255. alpha:1]; }
15 | + (UIColor *)beigeColor { return [self colorWithRed:252/255. green:245/255. blue:228/255. alpha:1]; }
16 | + (UIColor *)whiteColor { return [self colorWithRed:236/255. green:235/255. blue:232/255. alpha:1]; }
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/NodelikeDemo/NLConsoleViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // NLConsoleViewController.h
3 | // Interpreter
4 | //
5 | // Created by Sam Rijs on 1/28/14.
6 | // Copyright (c) 2014 Sam Rijs. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "NLMasterViewController.h"
12 |
13 | @interface NLConsoleViewController : UIViewController
14 |
15 | @property NLMasterViewController *masterViewController;
16 |
17 | @property IBOutlet UITextView *console;
18 |
19 | @property NSString *consoleText;
20 |
21 | - (void)log:(NSString *)string;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/NodelikeDemo/NLConsoleViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // NLConsoleViewController.m
3 | // Interpreter
4 | //
5 | // Created by Sam Rijs on 1/28/14.
6 | // Copyright (c) 2014 Sam Rijs. All rights reserved.
7 | //
8 |
9 | #import "NLConsoleViewController.h"
10 |
11 | @implementation NLConsoleViewController
12 |
13 | - (instancetype)initWithCoder:(NSCoder *)aDecoder {
14 | self = [super initWithCoder:aDecoder];
15 | self.consoleText = @"";
16 | return self;
17 | }
18 |
19 | - (void)viewDidAppear:(BOOL)animated {
20 | self.console.text = self.consoleText;
21 | }
22 |
23 | - (void)log:(NSString *)string {
24 | dispatch_async(dispatch_get_main_queue(), ^{
25 | self.consoleText = [self.consoleText stringByAppendingFormat:@"%@\n", string];
26 | self.console.text = self.consoleText;
27 | });
28 | }
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/NodelikeDemo/NLDocumentationViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // NLDocumentationViewController.h
3 | // Pinbrowser
4 | //
5 | // Created by Mikael Konutgan on 11/02/2013.
6 | // Copyright (c) 2013 Mikael Konutgan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NLDocumentationViewController : UIViewController
12 |
13 | @property (strong, nonatomic) IBOutlet UIWebView *webView;
14 |
15 | /**
16 | * The URL that will be loaded by the web view controller.
17 | * If there is one present when the web view appears, it will be automatically loaded, by calling `load`,
18 | * Otherwise, you can set a `URL` after the web view has already been loaded and then manually call `load`.
19 | */
20 | @property (strong, nonatomic) NSURL *URL;
21 |
22 | /** The array of data objects on which to perform the activity. */
23 | @property (strong, nonatomic) NSArray *activityItems;
24 |
25 | /** An array of UIActivity objects representing the custom services that your application supports. */
26 | @property (strong, nonatomic) NSArray *applicationActivities;
27 |
28 | /** The list of services that should not be displayed. */
29 | @property (strong, nonatomic) NSArray *excludedActivityTypes;
30 |
31 | /**
32 | * A Boolean indicating whether the web view controller’s toolbar,
33 | * which displays a stop/refresh, back, forward and share button, is shown.
34 | * The default value of this property is `YES`.
35 | */
36 | @property (assign, nonatomic) BOOL showsNavigationToolbar;
37 |
38 | /**
39 | * Loads the given `URL`. This is called automatically when the when the web view appears if a `URL` exists,
40 | * otehrwise it can be called manually.
41 | */
42 | - (void)load;
43 |
44 | /**
45 | * Clears the contents of the web view.
46 | */
47 | - (void)clear;
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/NodelikeDemo/NLDocumentationViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // NLDocumentationViewController.m
3 | // Pinbrowser
4 | //
5 | // Created by Mikael Konutgan on 11/02/2013.
6 | // Copyright (c) 2013 Mikael Konutgan. All rights reserved.
7 | //
8 |
9 | #import "NLDocumentationViewController.h"
10 |
11 | @interface NLDocumentationViewController ()
12 |
13 | @property (strong, nonatomic) UIBarButtonItem *stopLoadingButton;
14 | @property (strong, nonatomic) UIBarButtonItem *reloadButton;
15 | @property (strong, nonatomic) UIBarButtonItem *backButton;
16 | @property (strong, nonatomic) UIBarButtonItem *forwardButton;
17 |
18 | @property (strong, nonatomic) UIPopoverController *activitiyPopoverController;
19 |
20 | @property (assign, nonatomic) BOOL toolbarPreviouslyHidden;
21 |
22 | @end
23 |
24 | @implementation NLDocumentationViewController
25 |
26 | - (id)initWithCoder:(NSCoder *)aDecoder
27 | {
28 | self = [super initWithCoder:aDecoder];
29 | if (self) {
30 | _showsNavigationToolbar = NO;
31 | _URL = [NSURL URLWithString:@"http://nodejs.org/docs/latest/api/"];
32 | }
33 | return self;
34 | }
35 |
36 | - (void)load
37 | {
38 | NSURLRequest *request = [NSURLRequest requestWithURL:self.URL];
39 | [self.webView loadRequest:request];
40 |
41 | if (self.navigationController.toolbarHidden) {
42 | self.toolbarPreviouslyHidden = YES;
43 | if (self.showsNavigationToolbar) {
44 | [self.navigationController setToolbarHidden:NO animated:YES];
45 | }
46 | }
47 | }
48 |
49 | - (void)clear
50 | {
51 | [self.webView loadHTMLString:@"" baseURL:nil];
52 | self.title = @"";
53 | }
54 |
55 | #pragma mark - View controller lifecycle
56 |
57 | - (void)viewDidLoad
58 | {
59 | [super viewDidLoad];
60 | self.webView.scalesPageToFit = YES;
61 | }
62 |
63 | - (void)viewWillAppear:(BOOL)animated
64 | {
65 | [super viewWillAppear:animated];
66 | [self setupToolBarItems];
67 | self.webView.delegate = self;
68 | if (self.URL) {
69 | [self load];
70 | }
71 | }
72 |
73 | - (void)viewWillDisappear:(BOOL)animated
74 | {
75 | [super viewWillDisappear:animated];
76 | [self.webView stopLoading];
77 | self.webView.delegate = nil;
78 | [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
79 |
80 | if (self.toolbarPreviouslyHidden && self.showsNavigationToolbar) {
81 | [self.navigationController setToolbarHidden:YES animated:YES];
82 | }
83 | }
84 |
85 | #pragma mark - Helpers
86 |
87 | - (UIImage *)backButtonImage
88 | {
89 | static UIImage *image;
90 |
91 | static dispatch_once_t predicate;
92 | dispatch_once(&predicate, ^{
93 | CGSize size = CGSizeMake(12.0, 21.0);
94 | UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
95 |
96 | UIBezierPath *path = [UIBezierPath bezierPath];
97 | path.lineWidth = 1.5;
98 | path.lineCapStyle = kCGLineCapButt;
99 | path.lineJoinStyle = kCGLineJoinMiter;
100 | [path moveToPoint:CGPointMake(11.0, 1.0)];
101 | [path addLineToPoint:CGPointMake(1.0, 11.0)];
102 | [path addLineToPoint:CGPointMake(11.0, 20.0)];
103 | [path stroke];
104 |
105 | image = UIGraphicsGetImageFromCurrentImageContext();
106 | UIGraphicsEndImageContext();
107 | });
108 |
109 | return image;
110 | }
111 |
112 | - (UIImage *)forwardButtonImage
113 | {
114 | static UIImage *image;
115 |
116 | static dispatch_once_t predicate;
117 | dispatch_once(&predicate, ^{
118 | UIImage *backButtonImage = [self backButtonImage];
119 |
120 | CGSize size = backButtonImage.size;
121 | UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
122 |
123 | CGContextRef context = UIGraphicsGetCurrentContext();
124 |
125 | CGFloat x_mid = size.width / 2.0;
126 | CGFloat y_mid = size.height / 2.0;
127 |
128 | CGContextTranslateCTM(context, x_mid, y_mid);
129 | CGContextRotateCTM(context, M_PI);
130 |
131 | [backButtonImage drawAtPoint:CGPointMake(-x_mid, -y_mid)];
132 |
133 | image = UIGraphicsGetImageFromCurrentImageContext();
134 | UIGraphicsEndImageContext();
135 | });
136 |
137 | return image;
138 | }
139 |
140 | - (void)setupToolBarItems
141 | {
142 |
143 | self.stopLoadingButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop
144 | target:self.webView
145 | action:@selector(stopLoading)];
146 |
147 | self.reloadButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
148 | target:self.webView
149 | action:@selector(reload)];
150 |
151 | self.backButton = [[UIBarButtonItem alloc] initWithImage:[self backButtonImage]
152 | style:UIBarButtonItemStylePlain
153 | target:self.webView
154 | action:@selector(goBack)];
155 |
156 | self.forwardButton = [[UIBarButtonItem alloc] initWithImage:[self forwardButtonImage]
157 | style:UIBarButtonItemStylePlain
158 | target:self.webView
159 | action:@selector(goForward)];
160 |
161 | self.backButton.enabled = NO;
162 | self.forwardButton.enabled = NO;
163 |
164 | UIBarButtonItem *actionButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction
165 | target:self
166 | action:@selector(action:)];
167 |
168 | UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
169 | target:nil
170 | action:nil];
171 |
172 | UIBarButtonItem *space_ = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
173 | target:nil
174 | action:nil];
175 | space_.width = 60.0f;
176 |
177 | self.navigationController.toolbarItems = @[self.stopLoadingButton, space, self.backButton, space_, self.forwardButton, space, actionButton];
178 | }
179 |
180 | - (void)toggleState
181 | {
182 | self.backButton.enabled = self.webView.canGoBack;
183 | self.forwardButton.enabled = self.webView.canGoForward;
184 |
185 | NSMutableArray *toolbarItems = [self.navigationController.toolbarItems mutableCopy];
186 | if (self.webView.loading) {
187 | toolbarItems[0] = self.stopLoadingButton;
188 | } else {
189 | toolbarItems[0] = self.reloadButton;
190 | }
191 | self.navigationController.toolbarItems = [toolbarItems copy];
192 | }
193 |
194 | - (void)finishLoad
195 | {
196 | [self toggleState];
197 | [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
198 | }
199 |
200 | #pragma mark - Button actions
201 |
202 | - (void)action:(id)sender
203 | {
204 | if (self.activitiyPopoverController.popoverVisible) {
205 | [self.activitiyPopoverController dismissPopoverAnimated:YES];
206 | return;
207 | }
208 |
209 | NSArray *activityItems;
210 | if (self.activityItems) {
211 | activityItems = [self.activityItems arrayByAddingObject:self.URL];
212 | } else {
213 | activityItems = @[self.URL];
214 | }
215 |
216 | UIActivityViewController *vc = [[UIActivityViewController alloc] initWithActivityItems:activityItems
217 | applicationActivities:self.applicationActivities];
218 | if (self.excludedActivityTypes) {
219 | vc.excludedActivityTypes = self.excludedActivityTypes;
220 | }
221 |
222 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
223 | [self presentViewController:vc animated:YES completion:NULL];
224 | } else {
225 | if (!self.activitiyPopoverController) {
226 | self.activitiyPopoverController = [[UIPopoverController alloc] initWithContentViewController:vc];
227 | }
228 | self.activitiyPopoverController.delegate = self;
229 | [self.activitiyPopoverController presentPopoverFromBarButtonItem:[self.toolbarItems lastObject]
230 | permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
231 | }
232 | }
233 |
234 | #pragma mark - Web view delegate
235 |
236 | - (void)webViewDidStartLoad:(UIWebView *)webView
237 | {
238 | [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
239 | [self toggleState];
240 | }
241 |
242 | - (void)webViewDidFinishLoad:(UIWebView *)webView
243 | {
244 | [self finishLoad];
245 | self.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
246 | self.URL = self.webView.request.URL;
247 | }
248 |
249 | - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
250 | {
251 | [self finishLoad];
252 | }
253 |
254 | #pragma mark - Popover controller delegate
255 |
256 | - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
257 | {
258 | self.activitiyPopoverController = nil;
259 | }
260 |
261 | @end
262 |
--------------------------------------------------------------------------------
/NodelikeDemo/NLEditorViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // NLEditorViewController.h
3 | // NodelikeDemo
4 | //
5 | // Created by Sam Rijs on 10/13/13.
6 | // Copyright (c) 2013 Sam Rijs. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "NLMasterViewController.h"
11 |
12 | #import "NLTextView.h"
13 |
14 | @interface NLEditorViewController : UIViewController
15 |
16 | @property IBOutlet NLTextView *input;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/NodelikeDemo/NLEditorViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // NLEditorViewController.m
3 | // NodelikeDemo
4 | //
5 | // Created by Sam Rijs on 10/13/13.
6 | // Copyright (c) 2013 Sam Rijs. All rights reserved.
7 | //
8 |
9 | #import "NLEditorViewController.h"
10 |
11 | #import "KOKeyboardRow.h"
12 |
13 | #import "NLColor.h"
14 | #import "NLContext.h"
15 |
16 | @implementation NLEditorViewController
17 |
18 | - (void)viewDidLoad
19 | {
20 | [super viewDidLoad];
21 |
22 | self.input = [NLTextView textViewForView:self.view];
23 |
24 | self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
25 |
26 | [self.view addSubview:self.input];
27 |
28 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
29 | [KOKeyboardRow applyToTextView:self.input];
30 | ((KOKeyboardRow *)self.input.inputAccessoryView).viewController = self;
31 | }
32 |
33 | [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(fileOpenTriggered:) name:@"NLFileOpen" object:nil];
34 |
35 | }
36 |
37 | - (void)viewDidAppear:(BOOL)animated {
38 | [self.input becomeFirstResponder];
39 | }
40 |
41 | - (void)fileOpenTriggered:(NSNotification*)notification {
42 | self.input.text = notification.userInfo[@"script"];
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/NodelikeDemo/NLMasterViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // NLMasterViewController.h
3 | // Interpreter
4 | //
5 | // Created by Sam Rijs on 1/28/14.
6 | // Copyright (c) 2014 Sam Rijs. All rights reserved.
7 | //
8 |
9 | #import "FHSegmentedViewController.h"
10 |
11 | #import "NLContext.h"
12 |
13 | @interface NLMasterViewController : FHSegmentedViewController
14 |
15 | @property UIViewController *editorViewController;
16 | @property UIViewController *consoleViewController;
17 | @property UIViewController *documentationViewController;
18 |
19 | @property NLContext *context;
20 |
21 | @property UIBackgroundTaskIdentifier backgroundTask;
22 |
23 | - (void)executeJS:(NSString *)code;
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/NodelikeDemo/NLMasterViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // NLMasterViewController.m
3 | // Interpreter
4 | //
5 | // Created by Sam Rijs on 1/28/14.
6 | // Copyright (c) 2014 Sam Rijs. All rights reserved.
7 | //
8 |
9 | #import "NLMasterViewController.h"
10 |
11 | #import "NLEditorViewController.h"
12 | #import "NLConsoleViewController.h"
13 |
14 | #import "CSNotificationView.h"
15 | #import "PBWebViewController.h"
16 |
17 | #import "NLColor.h"
18 |
19 | @interface NLMasterViewController ()
20 |
21 | @end
22 |
23 | @implementation NLMasterViewController
24 |
25 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
26 | {
27 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
28 | if (self) {
29 | // Custom initialization
30 | }
31 | return self;
32 | }
33 |
34 | - (void)viewDidLoad
35 | {
36 |
37 | [super viewDidLoad];
38 |
39 | self.editorViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"editorViewController"];
40 | self.consoleViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"consoleViewController"];
41 | self.documentationViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"documentationViewController"];
42 |
43 | [self setViewControllers:@[self.editorViewController, self.consoleViewController]];
44 | [self pushViewController:self.documentationViewController];
45 |
46 | [self setupStyle];
47 |
48 | __weak NLMasterViewController *weakSelf = self;
49 |
50 | _context = [[NLContext alloc] initWithVirtualMachine:[[JSVirtualMachine alloc] init]];
51 |
52 | [NLContext attachToContext:_context];
53 |
54 | _context.exceptionHandler = ^(JSContext *c, JSValue *e) {
55 | dispatch_async(dispatch_get_main_queue(), ^{
56 | [weakSelf error:[e toString]];
57 | NSLog(@"%@ stack: %@", e, [e valueForProperty:@"stack"]);
58 | });
59 | };
60 |
61 | id logger = ^(JSValue *thing) {
62 | [JSContext.currentArguments enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
63 | NSLog(@"log: %@", [obj toString]);
64 | [((NLConsoleViewController *)self.consoleViewController) log:[obj toString]];
65 | }];
66 | };
67 | _context[@"console"] = @{@"log": logger, @"error": logger};
68 |
69 | //[_context evaluateScript:@"process.env['NODE_DEBUG']='module'"];
70 |
71 | }
72 |
73 | - (void)setupStyle {
74 |
75 | //self.navigationController.navigationBar.tintColor = [NLColor greenColor];
76 | //self.navigationController.navigationBar.barTintColor = [NLColor blackColor];
77 | self.navigationController.toolbar.tintColor = [NLColor blackColor];
78 | self.navigationController.toolbar.barTintColor = [[NLColor whiteColor] colorWithAlphaComponent:0.5];
79 |
80 | }
81 |
82 | - (void)executeJS:(NSString *)code {
83 | JSValue *ret = [_context evaluateScript:code];
84 | if (![ret isUndefined]) {
85 | [self output:[ret toString]];
86 | }
87 |
88 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
89 |
90 | self.backgroundTask = [UIApplication.sharedApplication beginBackgroundTaskWithExpirationHandler:^{
91 | NSLog(@"beginBG called");
92 | [UIApplication.sharedApplication endBackgroundTask:self.backgroundTask];
93 | self.backgroundTask = UIBackgroundTaskInvalid;
94 | }];
95 |
96 | [NLContext runEventLoopSync];
97 |
98 | [UIApplication.sharedApplication endBackgroundTask:self.backgroundTask];
99 | self.backgroundTask = UIBackgroundTaskInvalid;
100 |
101 | });
102 |
103 | }
104 |
105 | - (void)output:(NSString *)message {
106 | [CSNotificationView showInViewController:self
107 | style:CSNotificationViewStyleSuccess
108 | message:message];
109 | }
110 |
111 | - (void)error:(NSString *)message {
112 | [CSNotificationView showInViewController:self
113 | style:CSNotificationViewStyleError
114 | message:message];
115 | }
116 |
117 | - (IBAction)execute:(id)sender {
118 | [self executeJS:((NLEditorViewController *)self.editorViewController).input.text];
119 | }
120 |
121 | - (IBAction)showInfo:(id)sender {
122 | PBWebViewController *docuViewController = [[PBWebViewController alloc] init];
123 | docuViewController.URL = [NSURL URLWithString:@"http://nodeapp.org/?utm_source=interpreter&utm_medium=App&utm_campaign=info"];
124 | [self.navigationController pushViewController:docuViewController animated:YES];
125 | }
126 |
127 |
128 | - (void)didReceiveMemoryWarning
129 | {
130 | [super didReceiveMemoryWarning];
131 | // Dispose of any resources that can be recreated.
132 | }
133 |
134 | @end
135 |
--------------------------------------------------------------------------------
/NodelikeDemo/NLTextView.h:
--------------------------------------------------------------------------------
1 | //
2 | // The MIT License (MIT)
3 | //
4 | // Copyright (c) 2013 Dominik Hauser
5 | // Copyright (c) 2013 Sam Rijs
6 | //
7 | // Permission is hereby granted, free of charge, to any person obtaining a copy of
8 | // this software and associated documentation files (the "Software"), to deal in
9 | // the Software without restriction, including without limitation the rights to
10 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 | // the Software, and to permit persons to whom the Software is furnished to do so,
12 | // subject to the following conditions:
13 | //
14 | // The above copyright notice and this permission notice shall be included in all
15 | // copies or substantial portions of the Software.
16 | //
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 | //
24 |
25 | #import
26 |
27 | #import "CYRTextView.h"
28 |
29 | @interface NLTextView : CYRTextView
30 |
31 | + (instancetype)textViewForView:(UIView *)view;
32 |
33 | @property NSDictionary *highlightDefinition;
34 | @property (nonatomic) NSDictionary *highlightTheme;
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/NodelikeDemo/NLTextView.m:
--------------------------------------------------------------------------------
1 | //
2 | // The MIT License (MIT)
3 | //
4 | // Copyright (c) 2013 Dominik Hauser
5 | // Copyright (c) 2013 Sam Rijs
6 | //
7 | // Permission is hereby granted, free of charge, to any person obtaining a copy of
8 | // this software and associated documentation files (the "Software"), to deal in
9 | // the Software without restriction, including without limitation the rights to
10 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 | // the Software, and to permit persons to whom the Software is furnished to do so,
12 | // subject to the following conditions:
13 | //
14 | // The above copyright notice and this permission notice shall be included in all
15 | // copies or substantial portions of the Software.
16 | //
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 | //
24 |
25 | #import "NLTextView.h"
26 |
27 | #import "CYRToken.h"
28 |
29 | @implementation NLTextView
30 |
31 | + (instancetype)textViewForView:(UIView *)view {
32 | CGRect frame = view.frame;
33 | frame.size.height -= 64;
34 | return [[self alloc] initWithFrame:frame];
35 | }
36 |
37 | - (instancetype)initWithFrame:(CGRect)frame {
38 | self = [super initWithFrame:frame];
39 |
40 | self.gutterBackgroundColor = [UIColor clearColor];
41 | self.gutterLineColor = [UIColor clearColor];
42 |
43 | self.font = [UIFont fontWithName:@"Menlo" size:14.0];
44 |
45 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
46 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
47 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil];
48 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
49 |
50 | self.highlightDefinition = [NLTextView defaultHighlightDefinition];
51 | self.highlightTheme = [NLTextView defaultHighlightTheme];
52 |
53 | NSMutableArray *tokens = [NSMutableArray new];
54 | [self.highlightDefinition enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
55 | [tokens addObject:[CYRToken tokenWithName:key expression:obj
56 | attributes:@{NSForegroundColorAttributeName:self.highlightTheme[key]}]];
57 | }];
58 | self.tokens = tokens;
59 |
60 | return self;
61 | }
62 |
63 |
64 | - (void)keyboardWillShow:(NSNotification *)notification {
65 | [self moveTextViewForKeyboard:notification up:YES];
66 | }
67 |
68 | - (void)keyboardWillHide:(NSNotification *)notification {
69 | [self moveTextViewForKeyboard:notification up:NO];
70 | }
71 |
72 | - (void)keyboardDidChangeFrame:(NSNotification *)notification {
73 | CGRect keyboardEndFrame, newFrame, keyboardFrame;
74 | [[notification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
75 | newFrame = self.superview.bounds;
76 | keyboardFrame = [self.superview convertRect:keyboardEndFrame toView:nil];
77 | newFrame.size.height -= keyboardFrame.size.height;
78 | self.frame = newFrame;
79 | }
80 |
81 | - (void)orientationChanged:(NSNotification *)notification {
82 | self.frame = self.superview.bounds;
83 | }
84 |
85 | - (void)moveTextViewForKeyboard:(NSNotification* )notification up:(BOOL)up {
86 | NSDictionary* userInfo = [notification userInfo];
87 | NSTimeInterval animationDuration;
88 | UIViewAnimationCurve animationCurve;
89 | CGRect keyboardEndFrame;
90 |
91 | [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
92 | [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
93 | [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
94 |
95 | [UIView beginAnimations:nil context:nil];
96 | [UIView setAnimationDuration:animationDuration];
97 | [UIView setAnimationCurve:animationCurve];
98 |
99 | CGRect newFrame = self.frame;
100 | CGRect keyboardFrame = [self.superview convertRect:keyboardEndFrame toView:nil];
101 | newFrame.size.height -= keyboardFrame.size.height * (up?1:-1);
102 | self.frame = newFrame;
103 |
104 | [UIView commitAnimations];
105 | }
106 |
107 | + (NSDictionary *)defaultHighlightDefinition {
108 |
109 | NSString *path = [NSBundle.mainBundle pathForResource:@"Syntax" ofType:@"plist"];
110 | return [NSDictionary dictionaryWithContentsOfFile:path];
111 |
112 | }
113 |
114 | + (NSDictionary *)defaultHighlightTheme {
115 |
116 | return @{//@"text": [UIColor colorWithRed:255.0/255 green:255.0/255 blue:255.0/255 alpha:1],
117 | //@"background": [UIColor colorWithRed: 40.0/255 green: 43.0/255 blue: 52.0/255 alpha:1],
118 | @"comment": [UIColor colorWithRed: 72.0/255 green:190.0/255 blue:102.0/255 alpha:1],
119 | @"documentation_comment": [UIColor colorWithRed: 72.0/255 green:190.0/255 blue:102.0/255 alpha:1],
120 | @"documentation_comment_keyword": [UIColor colorWithRed: 72.0/255 green:190.0/255 blue:102.0/255 alpha:1],
121 | @"string": [UIColor colorWithRed:230.0/255 green: 66.0/255 blue: 75.0/255 alpha:1],
122 | @"character": [UIColor colorWithRed:139.0/255 green:134.0/255 blue:201.0/255 alpha:1],
123 | @"number": [UIColor colorWithRed:139.0/255 green:134.0/255 blue:201.0/255 alpha:1],
124 | @"keyword": [UIColor colorWithRed:195.0/255 green: 55.0/255 blue:149.0/255 alpha:1],
125 | @"preprocessor": [UIColor colorWithRed:211.0/255 green:142.0/255 blue: 99.0/255 alpha:1],
126 | @"url": [UIColor colorWithRed: 35.0/255 green: 63.0/255 blue:208.0/255 alpha:1],
127 | @"attribute": [UIColor colorWithRed:103.0/255 green:135.0/255 blue:142.0/255 alpha:1],
128 | @"project": [UIColor colorWithRed:146.0/255 green:199.0/255 blue:119.0/255 alpha:1],
129 | @"other": [UIColor colorWithRed: 0.0/255 green:175.0/255 blue:199.0/255 alpha:1]};
130 |
131 | }
132 |
133 | @end
134 |
--------------------------------------------------------------------------------
/NodelikeDemo/PBWebViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // PBWebViewController.h
3 | // Pinbrowser
4 | //
5 | // Created by Mikael Konutgan on 11/02/2013.
6 | // Copyright (c) 2013 Mikael Konutgan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface PBWebViewController : UIViewController
12 |
13 | /**
14 | * The URL that will be loaded by the web view controller.
15 | * If there is one present when the web view appears, it will be automatically loaded, by calling `load`,
16 | * Otherwise, you can set a `URL` after the web view has already been loaded and then manually call `load`.
17 | */
18 | @property (strong, nonatomic) NSURL *URL;
19 |
20 | /** The array of data objects on which to perform the activity. */
21 | @property (strong, nonatomic) NSArray *activityItems;
22 |
23 | /** An array of UIActivity objects representing the custom services that your application supports. */
24 | @property (strong, nonatomic) NSArray *applicationActivities;
25 |
26 | /** The list of services that should not be displayed. */
27 | @property (strong, nonatomic) NSArray *excludedActivityTypes;
28 |
29 | /**
30 | * A Boolean indicating whether the web view controller’s toolbar,
31 | * which displays a stop/refresh, back, forward and share button, is shown.
32 | * The default value of this property is `YES`.
33 | */
34 | @property (assign, nonatomic) BOOL showsNavigationToolbar;
35 |
36 | /**
37 | * Loads the given `URL`. This is called automatically when the when the web view appears if a `URL` exists,
38 | * otehrwise it can be called manually.
39 | */
40 | - (void)load;
41 |
42 | /**
43 | * Clears the contents of the web view.
44 | */
45 | - (void)clear;
46 |
47 | @end
48 |
--------------------------------------------------------------------------------
/NodelikeDemo/PBWebViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // PBWebViewController.m
3 | // Pinbrowser
4 | //
5 | // Created by Mikael Konutgan on 11/02/2013.
6 | // Copyright (c) 2013 Mikael Konutgan. All rights reserved.
7 | //
8 |
9 | #import "PBWebViewController.h"
10 |
11 | @interface PBWebViewController ()
12 |
13 | @property (strong, nonatomic) UIWebView *webView;
14 |
15 | @property (strong, nonatomic) UIBarButtonItem *stopLoadingButton;
16 | @property (strong, nonatomic) UIBarButtonItem *reloadButton;
17 | @property (strong, nonatomic) UIBarButtonItem *backButton;
18 | @property (strong, nonatomic) UIBarButtonItem *forwardButton;
19 |
20 | @property (strong, nonatomic) UIPopoverController *activitiyPopoverController;
21 |
22 | @property (assign, nonatomic) BOOL toolbarPreviouslyHidden;
23 |
24 | @end
25 |
26 | @implementation PBWebViewController
27 |
28 | - (id)init
29 | {
30 | self = [super init];
31 | if (self) {
32 | _showsNavigationToolbar = YES;
33 | }
34 | return self;
35 | }
36 |
37 | - (void)load
38 | {
39 | NSURLRequest *request = [NSURLRequest requestWithURL:self.URL];
40 | [self.webView loadRequest:request];
41 |
42 | if (self.navigationController.toolbarHidden) {
43 | self.toolbarPreviouslyHidden = YES;
44 | if (self.showsNavigationToolbar) {
45 | [self.navigationController setToolbarHidden:NO animated:YES];
46 | }
47 | }
48 | }
49 |
50 | - (void)clear
51 | {
52 | [self.webView loadHTMLString:@"" baseURL:nil];
53 | self.title = @"";
54 | }
55 |
56 | #pragma mark - View controller lifecycle
57 |
58 | - (void)loadView
59 | {
60 | self.webView = [[UIWebView alloc] init];
61 | self.webView.scalesPageToFit = YES;
62 | self.view = self.webView;
63 | }
64 |
65 | - (void)viewDidLoad
66 | {
67 | [super viewDidLoad];
68 | [self setupToolBarItems];
69 | }
70 |
71 | - (void)viewWillAppear:(BOOL)animated
72 | {
73 | [super viewWillAppear:animated];
74 | self.webView.delegate = self;
75 | if (self.URL) {
76 | [self load];
77 | }
78 | }
79 |
80 | - (void)viewWillDisappear:(BOOL)animated
81 | {
82 | [super viewWillDisappear:animated];
83 | [self.webView stopLoading];
84 | self.webView.delegate = nil;
85 | [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
86 |
87 | if (self.toolbarPreviouslyHidden && self.showsNavigationToolbar) {
88 | [self.navigationController setToolbarHidden:YES animated:YES];
89 | }
90 | }
91 |
92 | #pragma mark - Helpers
93 |
94 | - (UIImage *)backButtonImage
95 | {
96 | static UIImage *image;
97 |
98 | static dispatch_once_t predicate;
99 | dispatch_once(&predicate, ^{
100 | CGSize size = CGSizeMake(12.0, 21.0);
101 | UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
102 |
103 | UIBezierPath *path = [UIBezierPath bezierPath];
104 | path.lineWidth = 1.5;
105 | path.lineCapStyle = kCGLineCapButt;
106 | path.lineJoinStyle = kCGLineJoinMiter;
107 | [path moveToPoint:CGPointMake(11.0, 1.0)];
108 | [path addLineToPoint:CGPointMake(1.0, 11.0)];
109 | [path addLineToPoint:CGPointMake(11.0, 20.0)];
110 | [path stroke];
111 |
112 | image = UIGraphicsGetImageFromCurrentImageContext();
113 | UIGraphicsEndImageContext();
114 | });
115 |
116 | return image;
117 | }
118 |
119 | - (UIImage *)forwardButtonImage
120 | {
121 | static UIImage *image;
122 |
123 | static dispatch_once_t predicate;
124 | dispatch_once(&predicate, ^{
125 | UIImage *backButtonImage = [self backButtonImage];
126 |
127 | CGSize size = backButtonImage.size;
128 | UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
129 |
130 | CGContextRef context = UIGraphicsGetCurrentContext();
131 |
132 | CGFloat x_mid = size.width / 2.0;
133 | CGFloat y_mid = size.height / 2.0;
134 |
135 | CGContextTranslateCTM(context, x_mid, y_mid);
136 | CGContextRotateCTM(context, M_PI);
137 |
138 | [backButtonImage drawAtPoint:CGPointMake(-x_mid, -y_mid)];
139 |
140 | image = UIGraphicsGetImageFromCurrentImageContext();
141 | UIGraphicsEndImageContext();
142 | });
143 |
144 | return image;
145 | }
146 |
147 | - (void)setupToolBarItems
148 | {
149 | self.stopLoadingButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop
150 | target:self.webView
151 | action:@selector(stopLoading)];
152 |
153 | self.reloadButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
154 | target:self.webView
155 | action:@selector(reload)];
156 |
157 | self.backButton = [[UIBarButtonItem alloc] initWithImage:[self backButtonImage]
158 | style:UIBarButtonItemStylePlain
159 | target:self.webView
160 | action:@selector(goBack)];
161 |
162 | self.forwardButton = [[UIBarButtonItem alloc] initWithImage:[self forwardButtonImage]
163 | style:UIBarButtonItemStylePlain
164 | target:self.webView
165 | action:@selector(goForward)];
166 |
167 | self.backButton.enabled = NO;
168 | self.forwardButton.enabled = NO;
169 |
170 | UIBarButtonItem *actionButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction
171 | target:self
172 | action:@selector(action:)];
173 |
174 | UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
175 | target:nil
176 | action:nil];
177 |
178 | UIBarButtonItem *space_ = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
179 | target:nil
180 | action:nil];
181 | space_.width = 60.0f;
182 |
183 | self.toolbarItems = @[self.stopLoadingButton, space, self.backButton, space_, self.forwardButton, space, actionButton];
184 | }
185 |
186 | - (void)toggleState
187 | {
188 | self.backButton.enabled = self.webView.canGoBack;
189 | self.forwardButton.enabled = self.webView.canGoForward;
190 |
191 | NSMutableArray *toolbarItems = [self.toolbarItems mutableCopy];
192 | if (self.webView.loading) {
193 | toolbarItems[0] = self.stopLoadingButton;
194 | } else {
195 | toolbarItems[0] = self.reloadButton;
196 | }
197 | self.toolbarItems = [toolbarItems copy];
198 | }
199 |
200 | - (void)finishLoad
201 | {
202 | [self toggleState];
203 | [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
204 | }
205 |
206 | #pragma mark - Button actions
207 |
208 | - (void)action:(id)sender
209 | {
210 | if (self.activitiyPopoverController.popoverVisible) {
211 | [self.activitiyPopoverController dismissPopoverAnimated:YES];
212 | return;
213 | }
214 |
215 | NSArray *activityItems;
216 | if (self.activityItems) {
217 | activityItems = [self.activityItems arrayByAddingObject:self.URL];
218 | } else {
219 | activityItems = @[self.URL];
220 | }
221 |
222 | UIActivityViewController *vc = [[UIActivityViewController alloc] initWithActivityItems:activityItems
223 | applicationActivities:self.applicationActivities];
224 | if (self.excludedActivityTypes) {
225 | vc.excludedActivityTypes = self.excludedActivityTypes;
226 | }
227 |
228 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
229 | [self presentViewController:vc animated:YES completion:NULL];
230 | } else {
231 | if (!self.activitiyPopoverController) {
232 | self.activitiyPopoverController = [[UIPopoverController alloc] initWithContentViewController:vc];
233 | }
234 | self.activitiyPopoverController.delegate = self;
235 | [self.activitiyPopoverController presentPopoverFromBarButtonItem:[self.toolbarItems lastObject]
236 | permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
237 | }
238 | }
239 |
240 | #pragma mark - Web view delegate
241 |
242 | - (void)webViewDidStartLoad:(UIWebView *)webView
243 | {
244 | [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
245 | [self toggleState];
246 | }
247 |
248 | - (void)webViewDidFinishLoad:(UIWebView *)webView
249 | {
250 | [self finishLoad];
251 | self.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
252 | self.URL = self.webView.request.URL;
253 | }
254 |
255 | - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
256 | {
257 | [self finishLoad];
258 | }
259 |
260 | #pragma mark - Popover controller delegate
261 |
262 | - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
263 | {
264 | self.activitiyPopoverController = nil;
265 | }
266 |
267 | @end
268 |
--------------------------------------------------------------------------------
/NodelikeDemo/SEJSONViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // SEJSONViewController.h
3 | // SEJSONViewController
4 | //
5 | // Created by Sérgio Estêvão on 04/09/2013.
6 | // Copyright (c) 2013 Sérgio Estêvão. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | /**
12 | SEJSONViewController allows to browse the content of a JSON object.
13 |
14 | @warning SEJSONViewControllers must be used with a navigation controller in order to function properly and to be able to drill down trough the JSON data.
15 | */
16 | @interface SEJSONViewController : UITableViewController
17 |
18 | - (void) setData:(id)data;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/NodelikeDemo/SEJSONViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // SEJSONViewController.m
3 | // SEJSONViewController
4 | //
5 | // Created by Sérgio Estêvão on 04/09/2013.
6 | // Copyright (c) 2013 Sérgio Estêvão. All rights reserved.
7 | //
8 |
9 | #import "SEJSONViewController.h"
10 |
11 | @interface SEJSONViewController () {
12 | id _data;
13 | }
14 |
15 | @end
16 |
17 | @implementation SEJSONViewController
18 |
19 | - (id)initWithStyle:(UITableViewStyle)style
20 | {
21 | self = [super initWithStyle:style];
22 | if (self) {
23 | // Custom initialization
24 | }
25 | return self;
26 | }
27 |
28 | - (void)viewDidLoad
29 | {
30 | [super viewDidLoad];
31 | }
32 |
33 | - (void)didReceiveMemoryWarning
34 | {
35 | [super didReceiveMemoryWarning];
36 | // Dispose of any resources that can be recreated.
37 | }
38 |
39 | - (void) setData:(id)data {
40 | _data = data;
41 | [self.tableView reloadData];
42 | }
43 | #pragma mark - Table view data source
44 |
45 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
46 | {
47 | if (_data == nil) return 0;
48 | // Return the number of sections.
49 | if ([_data isKindOfClass:[NSDictionary class]]){
50 | return 1;
51 | }
52 |
53 | if ([_data isKindOfClass:[NSArray class]]){
54 | return [_data count];
55 | }
56 |
57 | return 0;
58 | }
59 |
60 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
61 | {
62 | // Return the number of rows in the section.
63 | if ([_data isKindOfClass:[NSDictionary class]]){
64 | return [_data count];
65 | }
66 |
67 | if ([_data isKindOfClass:[NSArray class]]){
68 | id obj = _data[section];
69 | if ([obj isKindOfClass:[NSDictionary class]]){
70 | return [[obj allKeys] count];
71 | }
72 | return 1;
73 | }
74 |
75 | return 0;
76 | }
77 |
78 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
79 | {
80 | static NSString *CellIdentifier = @"Cell";
81 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
82 |
83 | // Configure the cell...
84 | if (cell == nil){
85 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
86 | }
87 | id obj = _data;
88 | if ([_data isKindOfClass:[NSArray class]]){
89 | obj = _data[indexPath.section];
90 | }
91 |
92 | if ([obj isKindOfClass:[NSDictionary class]]){
93 | cell.textLabel.text = [obj allKeys][indexPath.row];
94 | id subObj = obj[cell.textLabel.text];
95 | if ([[subObj class] isSubclassOfClass:[NSDictionary class]] ||
96 | [[subObj class] isSubclassOfClass:[NSArray class]]
97 | )
98 | {
99 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
100 | cell.detailTextLabel.text = @"";
101 | } else {
102 | cell.accessoryType = UITableViewCellAccessoryNone;
103 | cell.detailTextLabel.text = [subObj description];
104 | }
105 | } else if ([obj isKindOfClass:[NSArray class]]) {
106 | cell.textLabel.text = [NSString stringWithFormat:@"%li",(long)indexPath.row];
107 | cell.detailTextLabel.text = @"";
108 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
109 | } else {
110 | cell.textLabel.text = [obj description];
111 | cell.detailTextLabel.text = @"";
112 | cell.accessoryType = UITableViewCellAccessoryNone;
113 | }
114 |
115 |
116 | return cell;
117 | }
118 |
119 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
120 | {
121 | if ([[_data class] isSubclassOfClass:[NSArray class]]){
122 | return [NSString stringWithFormat:@"%li",(long)section];
123 | }
124 |
125 | return @"Attributes";
126 | }
127 |
128 |
129 | #pragma mark - Table view delegate
130 |
131 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
132 | {
133 | // Navigation logic may go here. Create and push another view controller.
134 | NSString * title = self.title;
135 | id obj = _data;
136 | id selectedObjet = nil;
137 | if ([_data isKindOfClass:[NSArray class]]){
138 | obj = _data[indexPath.section];
139 | }
140 |
141 | if ([obj isKindOfClass:[NSDictionary class]]){
142 | NSString * key = [obj allKeys][indexPath.row];
143 | selectedObjet = obj[key];
144 | title = key;
145 | } else if ([obj isKindOfClass:[NSArray class]]) {
146 | selectedObjet = obj[indexPath.row];
147 | title = [NSString stringWithFormat:@"%@-%li",self.title, (long)indexPath.row];
148 | }
149 |
150 | if ( !([selectedObjet isKindOfClass:[NSDictionary class]] || [selectedObjet isKindOfClass:[NSArray class]])) return;
151 |
152 | SEJSONViewController *detailViewController = [[SEJSONViewController alloc] initWithStyle:self.tableView.style];
153 | [detailViewController setData:selectedObjet];
154 | detailViewController.title = title;
155 | // ...
156 | // Pass the selected object to the new view controller.
157 | [self.navigationController pushViewController:detailViewController animated:YES];
158 |
159 | }
160 |
161 | @end
162 |
--------------------------------------------------------------------------------
/NodelikeDemo/Syntax.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | comment
6 | (\/\/[^"\n\r]*(?:"[^"\n\r]*"[^"\n\r]*)*[\r\n])
7 | documentation_comment
8 | \/\*(.*?)\*\/
9 | documentation_comment_keyword
10 | (\/\*|\*\/)
11 | keyword
12 | (?<!\w)(if|else|for|in|while|do|continue|break|with|try|catch|switch|case|new|var|function|return|delete|true|false|void|throw|typeof|const|default|escape|isFinite|isNaN|Number|parseFloat|parseInt|reload|taint|unescape|untaint|write|Anchor|Applet|Area|Array|Boolean|Button|Checkbox|Date|document|window|Image|FileUpload|Form|Frame|Function|Hidden|Link|MimeType|Math|Max|Min|Layer|navigator|Object|Password|Plugin|Radio|RegExp|Reset|Screen|Select|String|Text|Textarea|this|Window|abs|acos|asin|atan|atan2|ceil|cos|ctg|E|exp|floor|LN2|LN10|log|LOG2E|LOG10E|PI|pow|round|sin|sqrt|SQRT1_2|SQRT2|tan|onAbort|onBlur|onChange|onClick|onError|onFocus|onLoad|onMouseOut|onMouseOver|onReset|onSelect|onSubmit|onUnload|above|action|alinkColor|alert|anchor|anchors|appCodeName|applets|apply|appName|appVersion|argument|arguments|arity|availHeight|availWidth|back|background|below|bgColor|border|big|blink|blur|bold|border|call|caller|charAt|charCodeAt|checked|clearInterval|clearTimeout|click|clip|close|closed|colorDepth|complete|compile|constructor|confirm|cookie|current|cursor|data|defaultChecked|defaultSelected|defaultStatus|defaultValue|description|disableExternalCapture|domain|elements|embeds|enabledPlugin|enableExternalCapture|encoding|eval|exec|fgColor|filename|find|fixed|focus|fontcolor|fontsize|form|forms|formName|forward|frames|fromCharCode|getDate|getDay|getHours|getMiliseconds|getMinutes|getMonth|getSeconds|getSelection|getTime|getTimezoneOffset|getUTCDate|getUTCDay|getUTCFullYear|getUTCHours|getUTCMilliseconds|getUTCMinutes|getUTCMonth|getUTCSeconds|getYear|global|go|hash|height|history|home|host|hostname|href|hspace|ignoreCase|images|index|indexOf|innerHeight|innerWidth|input|italics|javaEnabled|join|language|lastIndex|lastIndexOf|lastModified|lastParen|layers|layerX|layerY|left|leftContext|length|link|linkColor|links|location|locationbar|load|lowsrc|match|MAX_VALUE|menubar|method|mimeTypes|MIN_VALUE|modifiers|moveAbove|moveBelow|moveBy|moveTo|moveToAbsolute|multiline|name|NaN|NEGATIVE_INFINITY|negative_infinity|next|open|opener|options|outerHeight|outerWidth|pageX|pageY|pageXoffset|pageYoffset|parent|parse|pathname|personalbar|pixelDepth|platform|plugins|pop|port|POSITIVE_INFINITY|positive_infinity|preference|previous|print|prompt|protocol|prototype|push|referrer|refresh|releaseEvents|reload|replace|reset|resizeBy|resizeTo|reverse|rightContext|screenX|screenY|scroll|scrollbar|scrollBy|scrollTo|search|select|selected|selectedIndex|self|setDate|setHours|setMinutes|setMonth|setSeconds|setTime|setTimeout|setUTCDate|setUTCDay|setUTCFullYear|setUTCHours|setUTCMilliseconds|setUTCMinutes|setUTCMonth|setUTCSeconds|setYear|shift|siblingAbove|siblingBelow|small|sort|source|splice|split|src|status|statusbar|strike|sub|submit|substr|substring|suffixes|sup|taintEnabled|target|test|text|title|toGMTString|toLocaleString|toLowerCase|toolbar|toSource|toString|top|toUpperCase|toUTCString|type|URL|unshift|unwatch|userAgent|UTC|value|valueOf|visibility|vlinkColor|vspace|width|watch|which|width|write|writeln|x|y|zIndex)(?!\w)
13 | number
14 | (?<!\w)(((0x[0-9a-fA-F]+)|(([0-9]+\.?[0-9]*|\.[0-9]+)([eE][-+]?[0-9]+)?))[fFlLuU]{0,2})(?!\w)
15 | string
16 | ("(?:[^"\\]|\\.)*")
17 | url
18 | ((https?|mailto|ftp|file)://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?)
19 |
20 |
21 |
--------------------------------------------------------------------------------
/NodelikeDemo/Vendor/KOKeyboard/KOKeyboardRow.h:
--------------------------------------------------------------------------------
1 | //
2 | // ExtraKeyboardRow.h
3 | // KeyboardTest
4 | //
5 | // Created by Kuba on 28.06.12.
6 | // Copyright (c) 2012 Adam Horacek, Kuba Brecka
7 | //
8 | // Website: http://www.becomekodiak.com/
9 | // github: http://github.com/adamhoracek/KOKeyboard
10 | // Twitter: http://twitter.com/becomekodiak
11 | // Mail: adam@becomekodiak.com, kuba@becomekodiak.com
12 | //
13 | // Permission is hereby granted, free of charge, to any person
14 | // obtaining a copy of this software and associated documentation
15 | // files (the "Software"), to deal in the Software without
16 | // restriction, including without limitation the rights to use,
17 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
18 | // copies of the Software, and to permit persons to whom the
19 | // Software is furnished to do so, subject to the following
20 | // conditions:
21 | //
22 | // The above copyright notice and this permission notice shall be
23 | // included in all copies or substantial portions of the Software.
24 | //
25 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
27 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
29 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
30 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
32 | // OTHER DEALINGS IN THE SOFTWARE.
33 | //
34 |
35 | #import
36 |
37 | #import "NLEditorViewController.h"
38 |
39 | @interface KOKeyboardRow : UIView
40 |
41 | @property NLEditorViewController *viewController;
42 |
43 | + (void)applyToTextView:(UITextView *)textView;
44 | - (void)trackPointMovedX:(int)xdiff Y:(int)ydiff selecting:(BOOL)selecting;
45 | - (void)trackPointStarted;
46 | - (void)execButtonPressed;
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/NodelikeDemo/Vendor/KOKeyboard/KOKeyboardRow.m:
--------------------------------------------------------------------------------
1 | //
2 | // ExtraKeyboardRow.m
3 | // KeyboardTest
4 | //
5 | // Created by Kuba on 28.06.12.
6 | // Copyright (c) 2012 Adam Horacek, Kuba Brecka
7 | //
8 | // Website: http://www.becomekodiak.com/
9 | // github: http://github.com/adamhoracek/KOKeyboard
10 | // Twitter: http://twitter.com/becomekodiak
11 | // Mail: adam@becomekodiak.com, kuba@becomekodiak.com
12 | //
13 | // Permission is hereby granted, free of charge, to any person
14 | // obtaining a copy of this software and associated documentation
15 | // files (the "Software"), to deal in the Software without
16 | // restriction, including without limitation the rights to use,
17 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
18 | // copies of the Software, and to permit persons to whom the
19 | // Software is furnished to do so, subject to the following
20 | // conditions:
21 | //
22 | // The above copyright notice and this permission notice shall be
23 | // included in all copies or substantial portions of the Software.
24 | //
25 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
27 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
29 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
30 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
32 | // OTHER DEALINGS IN THE SOFTWARE.
33 | //
34 |
35 | #import "KOKeyboardRow.h"
36 | #import "KOSwipeButton.h"
37 |
38 | #import "NLColor.h"
39 |
40 | @interface KOKeyboardRow ()
41 |
42 | @property (nonatomic, retain) UITextView *textView;
43 | @property (nonatomic, assign) CGRect startLocation;
44 |
45 | @end
46 |
47 | @implementation KOKeyboardRow
48 |
49 | @synthesize textView, startLocation;
50 |
51 | + (void)applyToTextView:(UITextView *)t
52 | {
53 | int barHeight = 46;
54 | int barWidth = 768;
55 |
56 | int buttonCount = 1;
57 | int buttonHeight = 40;
58 | NSString *keys = @"TTTTT";
59 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
60 | buttonCount = 11;
61 | barHeight = 72;
62 | buttonHeight = 60;
63 | keys = @"()\"[]{}'<>\\/$´`~^|€£-+=%*◉◉◉◉◉!?#@&_:;,.1203467589TTTTT";
64 | }
65 |
66 | KOKeyboardRow *v = [[KOKeyboardRow alloc] initWithFrame:CGRectMake(0, 0, barWidth, barHeight)];
67 | v.backgroundColor = [NLColor blackColor];//[UIColor colorWithRed:240/255. green:240/255. blue:240/255. alpha:1];
68 | v.autoresizingMask = UIViewAutoresizingFlexibleHeight;
69 | v.textView = t;
70 |
71 | int leftMargin = 3;
72 | int topMargin = 1;
73 | int buttonSpacing = 6;
74 | int buttonWidth = (barWidth - 2 * leftMargin - (buttonCount - 1) * buttonSpacing) / buttonCount;
75 | leftMargin = (barWidth - buttonWidth * buttonCount - buttonSpacing * (buttonCount - 1)) / 2;
76 |
77 | for (int i = 0; i < buttonCount; i++) {
78 | KOSwipeButton *b = [[KOSwipeButton alloc] initWithFrame:CGRectMake(leftMargin + i * (buttonSpacing + buttonWidth), topMargin + (barHeight - buttonHeight) / 2, buttonWidth, buttonHeight)];
79 | b.keys = [keys substringWithRange:NSMakeRange(i * 5, 5)];
80 | b.delegate = v;
81 | b.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
82 | [v addSubview:b];
83 | }
84 |
85 | t.inputAccessoryView = v;
86 | }
87 |
88 | - (void)insertText:(NSString *)text
89 | {
90 | [textView insertText:text];
91 | }
92 |
93 | - (void)trackPointStarted
94 | {
95 | startLocation = [textView caretRectForPosition:textView.selectedTextRange.start];
96 | }
97 |
98 | - (void)trackPointMovedX:(int)xdiff Y:(int)ydiff selecting:(BOOL)selecting
99 | {
100 | CGRect loc = startLocation;
101 |
102 | loc.origin.y -= textView.contentOffset.y;
103 |
104 | UITextPosition *p1 = [textView closestPositionToPoint:loc.origin];
105 |
106 | loc.origin.x -= xdiff;
107 | loc.origin.y -= ydiff;
108 |
109 | UITextPosition *p2 = [textView closestPositionToPoint:loc.origin];
110 |
111 | if (!selecting) {
112 | p1 = p2;
113 | }
114 | UITextRange *r = [textView textRangeFromPosition:p1 toPosition:p2];
115 |
116 | textView.selectedTextRange = r;
117 | }
118 |
119 | @end
120 |
--------------------------------------------------------------------------------
/NodelikeDemo/Vendor/KOKeyboard/KOSwipeButton.h:
--------------------------------------------------------------------------------
1 | //
2 | // SwipeButton.h
3 | // KeyboardTest
4 | //
5 | // Created by Kuba on 28.06.12.
6 | // Copyright (c) 2012 Adam Horacek, Kuba Brecka
7 | //
8 | // Website: http://www.becomekodiak.com/
9 | // github: http://github.com/adamhoracek/KOKeyboard
10 | // Twitter: http://twitter.com/becomekodiak
11 | // Mail: adam@becomekodiak.com, kuba@becomekodiak.com
12 | //
13 | // Permission is hereby granted, free of charge, to any person
14 | // obtaining a copy of this software and associated documentation
15 | // files (the "Software"), to deal in the Software without
16 | // restriction, including without limitation the rights to use,
17 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
18 | // copies of the Software, and to permit persons to whom the
19 | // Software is furnished to do so, subject to the following
20 | // conditions:
21 | //
22 | // The above copyright notice and this permission notice shall be
23 | // included in all copies or substantial portions of the Software.
24 | //
25 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
27 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
29 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
30 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
32 | // OTHER DEALINGS IN THE SOFTWARE.
33 | //
34 |
35 | #import
36 |
37 | @interface KOSwipeButton : UIView
38 |
39 | @property (nonatomic, weak) id delegate;
40 |
41 | - (void)setKeys:(NSString *)newKeys;
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/NodelikeDemo/Vendor/KOKeyboard/KOSwipeButton.m:
--------------------------------------------------------------------------------
1 | //
2 | // SwipeButton.m
3 | // KeyboardTest
4 | //
5 | // Created by Kuba on 28.06.12.
6 | // Copyright (c) 2012 Adam Horacek, Kuba Brecka
7 | //
8 | // Website: http://www.becomekodiak.com/
9 | // github: http://github.com/adamhoracek/KOKeyboard
10 | // Twitter: http://twitter.com/becomekodiak
11 | // Mail: adam@becomekodiak.com, kuba@becomekodiak.com
12 | //
13 | // Permission is hereby granted, free of charge, to any person
14 | // obtaining a copy of this software and associated documentation
15 | // files (the "Software"), to deal in the Software without
16 | // restriction, including without limitation the rights to use,
17 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
18 | // copies of the Software, and to permit persons to whom the
19 | // Software is furnished to do so, subject to the following
20 | // conditions:
21 | //
22 | // The above copyright notice and this permission notice shall be
23 | // included in all copies or substantial portions of the Software.
24 | //
25 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
27 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
29 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
30 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
32 | // OTHER DEALINGS IN THE SOFTWARE.
33 | //
34 |
35 | #import "KOSwipeButton.h"
36 | #import "KOKeyboardRow.h"
37 |
38 | #import "NLColor.h"
39 |
40 | @interface KOSwipeButton ()
41 |
42 | @property (nonatomic, retain) NSMutableArray *labels;
43 | @property (nonatomic, assign) CGPoint touchBeginPoint;
44 | @property (nonatomic, retain) UILabel *selectedLabel;
45 | @property (nonatomic, retain) UIImageView *bgView;
46 | @property (nonatomic, retain) UIImageView *foregroundView;
47 | @property (nonatomic, assign) BOOL trackPoint;
48 | @property (nonatomic, assign) BOOL tabButton;
49 | @property (nonatomic, retain) NSDate *firstTapDate;
50 | @property (nonatomic, assign) BOOL selecting;
51 | @property (nonatomic, retain) UIImage *blueImage;
52 | @property (nonatomic, retain) UIImage *pressedImage;
53 | @property (nonatomic, retain) UIImage *blueFgImage;
54 | @property (nonatomic, retain) UIImage *pressedFgImage;
55 |
56 | @end
57 |
58 | #define TIME_INTERVAL_FOR_DOUBLE_TAP 0.4
59 |
60 | @implementation KOSwipeButton
61 |
62 | @synthesize labels, touchBeginPoint, selectedLabel, delegate, bgView, trackPoint, tabButton, selecting, firstTapDate, blueImage, pressedImage, foregroundView, blueFgImage, pressedFgImage;
63 |
64 | - (void)setFrame:(CGRect)frame
65 | {
66 | [super setFrame:frame];
67 | }
68 |
69 | - (id)initWithFrame:(CGRect)frame
70 | {
71 | self = [super initWithFrame:frame];
72 |
73 | int labelWidth = 20;
74 | int labelHeight = 20;
75 | int leftInset = 9;
76 | int rightInset = 9;
77 | int topInset = 3;
78 | int bottomInset = 8;
79 |
80 | self.labels = [[NSMutableArray alloc] init];
81 |
82 | UIFont *f = [UIFont systemFontOfSize:15];
83 |
84 | UILabel *l = [[UILabel alloc] initWithFrame:CGRectMake(leftInset, topInset, labelWidth, labelHeight)];
85 | l.textAlignment = NSTextAlignmentLeft;
86 | l.text = @"1";
87 | l.font = f;
88 | [self addSubview:l];
89 | [l setTextColor:[UIColor whiteColor]];
90 | [l setHighlightedTextColor:[NLColor greenColor]];
91 | l.backgroundColor = [UIColor clearColor];
92 | [labels addObject:l];
93 |
94 | l = [[UILabel alloc] initWithFrame:CGRectMake(self.frame.size.width - labelWidth - rightInset, topInset, labelWidth, labelHeight)];
95 | l.textAlignment = NSTextAlignmentRight;
96 | l.text = @"2";
97 | l.font = f;
98 | l.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
99 | [self addSubview:l];
100 | [l setTextColor:[UIColor whiteColor]];
101 | [l setHighlightedTextColor:[NLColor greenColor]];
102 | l.backgroundColor = [UIColor clearColor];
103 | [labels addObject:l];
104 |
105 | l = [[UILabel alloc] initWithFrame:CGRectIntegral(CGRectMake((self.frame.size.width - labelWidth - leftInset - rightInset) / 2 + leftInset, (self.frame.size.height - labelHeight - topInset - bottomInset) / 2 + topInset, labelWidth, labelHeight))];
106 | l.textAlignment = NSTextAlignmentCenter;
107 | l.text = @"3";
108 | l.font = f;
109 | l.autoresizingMask = UIViewAutoresizingFlexibleWidth;
110 | [self addSubview:l];
111 | [l setTextColor:[UIColor whiteColor]];
112 | [l setHighlightedTextColor:[NLColor greenColor]];
113 | l.backgroundColor = [UIColor clearColor];
114 | [labels addObject:l];
115 |
116 | l = [[UILabel alloc] initWithFrame:CGRectMake(leftInset, (self.frame.size.height - labelHeight - bottomInset), labelWidth, labelHeight)];
117 | l.textAlignment = NSTextAlignmentLeft;
118 | l.text = @"4";
119 | l.font = f;
120 | [self addSubview:l];
121 | [l setTextColor:[UIColor whiteColor]];
122 | [l setHighlightedTextColor:[NLColor greenColor]];
123 | l.backgroundColor = [UIColor clearColor];
124 | [labels addObject:l];
125 |
126 | l = [[UILabel alloc] initWithFrame:CGRectMake(self.frame.size.width - labelWidth - rightInset, (self.frame.size.height - labelHeight - bottomInset), labelWidth, labelHeight)];
127 | l.textAlignment = NSTextAlignmentRight;
128 | l.text = @"5";
129 | l.font = f;
130 | l.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
131 | [self addSubview:l];
132 | [l setTextColor:[UIColor whiteColor]];
133 | [l setHighlightedTextColor:[NLColor greenColor]];
134 | l.backgroundColor = [UIColor clearColor];
135 | [labels addObject:l];
136 |
137 | firstTapDate = [[NSDate date] dateByAddingTimeInterval:-1];
138 |
139 | return self;
140 | }
141 |
142 | - (void)setKeys:(NSString *)newKeys
143 | {
144 | for (int i = 0; i < MIN(newKeys.length, 5); i++) {
145 | [[labels objectAtIndex:i] setText:[newKeys substringWithRange:NSMakeRange(i, 1)]];
146 |
147 | if ([[newKeys substringToIndex:1] isEqualToString:@"◉"] |
148 | [[newKeys substringToIndex:1] isEqualToString:@"T"]) {
149 |
150 | trackPoint = [[newKeys substringToIndex:1] isEqualToString:@"◉"];
151 | tabButton = [[newKeys substringToIndex:1] isEqualToString:@"T"];
152 |
153 | if (i != 2)
154 | [[labels objectAtIndex:i] setHidden:YES];
155 | else {
156 | if (trackPoint) {
157 | [[labels objectAtIndex:i] setHidden:YES];
158 |
159 | [[labels objectAtIndex:i] setFont:[UIFont systemFontOfSize:20]];
160 | blueImage = [UIImage imageNamed:@"key-blue.png"];
161 | pressedImage = [UIImage imageNamed:@"key-pressed.png"];
162 |
163 | UIImage *bgImg1 = [UIImage imageNamed:@"hal-black.png"];
164 | UIImage *bgImg2 = [UIImage imageNamed:@"hal-blue.png"];
165 | blueFgImage = [UIImage imageNamed:@"hal-white.png"];
166 | pressedFgImage = bgImg2;
167 | foregroundView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 19, 19)];
168 | foregroundView.frame = CGRectMake((int)((self.frame.size.width - foregroundView.frame.size.width) / 2), (int)((self.frame.size.height - foregroundView.frame.size.height) / 2), 19, 19);
169 | [foregroundView setImage:bgImg1];
170 | [foregroundView setHighlightedImage:bgImg2];
171 | foregroundView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
172 | [self addSubview:foregroundView];
173 |
174 | } else {
175 | [[labels objectAtIndex:i] setText:@"TAB"];
176 | [[labels objectAtIndex:i] setFrame:self.bounds];
177 | }
178 | }
179 | }
180 | }
181 | }
182 |
183 | - (void)selectLabel:(int)idx
184 | {
185 | selectedLabel = nil;
186 |
187 | for (int i = 0; i < labels.count; i++) {
188 | UILabel *l = [labels objectAtIndex:i];
189 | l.highlighted = (idx == i);
190 |
191 | if (idx == i)
192 | selectedLabel = l;
193 | }
194 |
195 | bgView.highlighted = selectedLabel != nil;
196 | foregroundView.highlighted = selectedLabel != nil;
197 | }
198 |
199 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
200 | {
201 | UITouch *t = [touches anyObject];
202 | touchBeginPoint = [t locationInView:self];
203 |
204 | if (trackPoint) {
205 | if (fabs([firstTapDate timeIntervalSinceNow]) < TIME_INTERVAL_FOR_DOUBLE_TAP) {
206 | bgView.highlightedImage = blueImage;
207 | foregroundView.highlightedImage = blueFgImage;
208 | selecting = YES;
209 | } else {
210 | bgView.highlightedImage = pressedImage;
211 | foregroundView.highlightedImage = pressedFgImage;
212 | selecting = NO;
213 | }
214 | firstTapDate = [NSDate date];
215 |
216 | [delegate trackPointStarted];
217 | }
218 |
219 | [self selectLabel:2];
220 | }
221 |
222 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
223 | {
224 | UITouch *t = [touches anyObject];
225 | CGPoint touchMovePoint = [t locationInView:self];
226 |
227 | CGFloat xdiff = touchBeginPoint.x - touchMovePoint.x;
228 | CGFloat ydiff = touchBeginPoint.y - touchMovePoint.y;
229 | CGFloat distance = sqrt(xdiff * xdiff + ydiff * ydiff);
230 |
231 | if (trackPoint) {
232 | [delegate trackPointMovedX:xdiff Y:ydiff selecting:selecting];
233 | return;
234 | }
235 |
236 | if (distance > 250) {
237 | [self selectLabel:-1];
238 | } else if (!tabButton && (distance > 20)) {
239 | CGFloat angle = atan2(xdiff, ydiff);
240 |
241 | if (angle >= 0 && angle < M_PI_2) {
242 | [self selectLabel:0];
243 | } else if (angle >= 0 && angle >= M_PI_2) {
244 | [self selectLabel:3];
245 | } else if (angle < 0 && angle > -M_PI_2) {
246 | [self selectLabel:1];
247 | } else if (angle < 0 && angle <= -M_PI_2) {
248 | [self selectLabel:4];
249 | }
250 | } else {
251 | [self selectLabel:2];
252 | }
253 | }
254 |
255 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
256 | {
257 | if (selectedLabel != nil) {
258 | if (tabButton) {
259 | [delegate insertText:@"\t"];
260 | } else if (! trackPoint) {
261 | NSString *textToInsert = selectedLabel.text;
262 | [delegate insertText:textToInsert];
263 | }
264 | }
265 |
266 | [self selectLabel:-1];
267 | }
268 |
269 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
270 | {
271 | [self selectLabel:-1];
272 | }
273 |
274 | @end
275 |
--------------------------------------------------------------------------------
/NodelikeDemo/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/NodelikeDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // NodelikeDemo
4 | //
5 | // Created by Sam Rijs on 10/13/13.
6 | // Copyright (c) 2013 Sam Rijs. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "NLAppDelegate.h"
12 |
13 | int main(int argc, char * argv[])
14 | {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([NLAppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '7.0'
2 |
3 | pod 'Nodelike', :git => 'https://github.com/node-app/Nodelike.git', :commit => '9eab9ce1053eb80599cb323222601ce8695486dc', :submodules => true
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Important: This project is no longer maintained. The code is still available, but please don't regard it as anything but a hack. Please do not open new support tickets.
2 |
3 | # Interpreter [](https://travis-ci.org/node-app/Interpreter) [](https://gitter.im/node-app/Interpreter)
4 |
5 | This is an example project implementing a Node.JS interpreter as an iOS app, utilising the [Nodelike](https://github.com/node-app/Nodelike) framework.
6 |
7 | Nodelike is a project to implement a roughly Node.JS-compatible interface using JavaScriptCore.framework on iOS 7 and OS X Mavericks.
8 |
9 | (JavaScriptCore hasn't been available before iOS 7, and on OS X the project makes extensive use of the newly-updated 10.9-only Objective-C API. Previously on 10.8 there existed only a very low-level and very verbose C API.)
10 |
11 | This is currently in a very incomplete state. It could, however, become usable over the following weeks.
12 |
13 | 
14 |
15 | The goals
16 | ---------
17 | - to be _drop-in compatible_ with the current nodejs master
18 | - to be _very lightweight_
19 | - to _reuse javascript code from node_ (/lib)
20 | - to provide the _most minimal binding_ that is possible (via libuv)
21 | - NOT to achieve Node.js performance (this is meant as a client-side, not a server-side application)
22 | - NOT to be backwards-compatible (nodejs cutting edge and newest iOS/OS X required)
23 |
24 | What's working right now
25 | ------------------------
26 |
27 | - `console.log()`
28 | - `process`: `.argv`, `.env`, `.exit()`, `.nextTick()`
29 | - `require()` for native modules
30 | - `fs`
31 | - `net`
32 | - `http`
33 | - `timers`
34 | - `util`
35 | - `url`
36 | - `events`
37 | - `path`
38 | - `stream`
39 | - `querystring`
40 | - `punycode`
41 | - `assert`
42 |
43 | How to compile
44 | --------------
45 |
46 | 1. You need to have [CocoaPods](http://cocoapods.org) installed. If you do not have already, run `sudo gem install cocoapods`.
47 | 2. Install the dependencies via `pod install`.
48 | 3. Open `Interpreter.xcworkspace` in Xcode and run!
49 |
50 | How to use the app
51 | ------------------
52 |
53 | You can enter Javascript code into the TextView and execute that via a tap on the `Execute` button.
54 | After each execution, when the result of the executed script is not undefined, a popover will appear containing that result.
55 |
56 | Have fun!
57 |
--------------------------------------------------------------------------------
/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/node-app/Interpreter/debb0f3ee1e38e6864070d3a8c423a674aa820db/demo.png
--------------------------------------------------------------------------------
/node_modules/examples/index.js:
--------------------------------------------------------------------------------
1 | module.exports = ['01','02','03','04'].map(function (m) { return require('example' + m); });
--------------------------------------------------------------------------------
/node_modules/examples/node_modules/example01/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function () {
2 |
3 | var eventemitter = require('events').EventEmitter,
4 | timers = require('timers');
5 |
6 | var e = new eventemitter()
7 |
8 | e.on("hello", function () {
9 | console.log("Hello!")
10 | });
11 |
12 | e.on("world", function () {
13 | console.log("World!")
14 | });
15 |
16 | timers.setTimeout(function () {
17 | e.emit('hello');
18 | }, 5000);
19 |
20 | timers.setTimeout(function () {
21 | e.emit('world');
22 | }, 10000);
23 |
24 | };
--------------------------------------------------------------------------------
/node_modules/examples/node_modules/example02/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function () {
2 |
3 | var fs = require("fs");
4 |
5 | fs.readdir("/", function (err, dir) {
6 | if (err) return console.log(err);
7 | console.log(dir);
8 | });
9 |
10 | };
--------------------------------------------------------------------------------
/node_modules/examples/node_modules/example03/index.js:
--------------------------------------------------------------------------------
1 | var http = require('http');
2 |
3 | module.exports = function () {
4 |
5 | http.createServer(function (req, res) {
6 | res.statusCode = 200;
7 | res.write(new Buffer("PONG!"));
8 | res.end();
9 | }).listen(5000);
10 |
11 | http.get("http://localhost:5000/", function(res) {
12 | console.log("Got response: " + res.statusCode);
13 | res.on("data", function (data) {
14 | console.log("Got data: " + data);
15 | });
16 | }).on('error', function(e) {
17 | console.log("Got error: " + e.message);
18 | });
19 |
20 | };
--------------------------------------------------------------------------------
/node_modules/examples/node_modules/example04/index.js:
--------------------------------------------------------------------------------
1 | var net = require('net');
2 |
3 | module.exports = function () {
4 |
5 | var server = net.createServer(function (socket) {
6 | socket.write('Echo server\r\n');
7 | socket.pipe(socket);
8 | });
9 |
10 | server.listen(1337);
11 |
12 | };
--------------------------------------------------------------------------------