10 |
11 | @interface RSCCControl : NSObject
12 |
13 | @property (copy) NSString *title, *license, *date, *image, *link, *pod, *source;
14 |
15 | @property (nonatomic) BOOL isOnCocoaPods;
16 |
17 | @property (nonatomic) CGFloat rating;
18 |
19 | @property (nonatomic) int appsUsingThisControl;
20 |
21 | - initWithAssignment:(void (^)(RSCCControl *))assignment;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/CocoaControls/RSCCControl.m:
--------------------------------------------------------------------------------
1 | //
2 | // RSCCControl.m
3 | // CocoaControls
4 | //
5 | // Created by R0CKSTAR on 14-5-3.
6 | // Copyright (c) 2014年 P.D.Q. All rights reserved.
7 | //
8 |
9 | #import "RSCCControl.h"
10 |
11 | @implementation RSCCControl
12 |
13 | - initWithAssignment:(void (^)(RSCCControl *))assignment {
14 |
15 | return self = super.init ? !assignment ?: assignment(self) , self : nil;
16 | }
17 |
18 | - (NSString*) description {
19 |
20 | return [NSString stringWithFormat:@"[Title : %@] [License : %@] [Date : %@] [Image : %@] [Link : %@] [CocoaPods : %d] [Rating : %f] [Apps using this Control : %d] [Pod : %@] [Source : %@]",
21 | self.title, self.license, self.date, self.image, self.link, self.isOnCocoaPods, self.rating, self.appsUsingThisControl, self.pod, self.source];
22 | }
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/CocoaControls/RSCCControlCellView.h:
--------------------------------------------------------------------------------
1 | //
2 | // RSCCControlCellView.h
3 | // CocoaControls
4 | //
5 | // Created by R0CKSTAR on 14-5-5.
6 | // Copyright (c) 2014年 P.D.Q. All rights reserved.
7 | //
8 |
9 | extern int const RSCCControlCellViewImageButtonTagBase,
10 | RSCCControlCellViewCocoaPodsButtonTagBase,
11 | RSCCControlCellViewCloneButtonTagBase;
12 |
13 | extern CGFloat const kCocoaPodsButtonWidthConstant,
14 | kButtonsGapConstant;
15 |
16 | @class RSCCControlCellViewBackgroundView;
17 |
18 | @interface RSCCControlCellView : NSTableCellView
19 |
20 | @property (assign) IBOutlet RSCCControlCellViewBackgroundView *backgroundView;
21 | @property (assign) IBOutlet NSTextField *titleField, *dateField, *licenseField;
22 | @property (assign) IBOutlet NSButton *imageButton, *cocoaPodsButton, *cloneButton;
23 | @property (assign) IBOutlet NSImageView *star0, *star1, *star2, *star3, *star4;
24 | @property (assign) IBOutlet NSLayoutConstraint *cocoaPodsButtonWidth, *buttonsGap;
25 |
26 | @property (nonatomic) NSArray *stars;
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/CocoaControls/RSCCControlCellView.m:
--------------------------------------------------------------------------------
1 | //
2 | // RSCCControlCellView.m
3 | // CocoaControls
4 | //
5 | // Created by R0CKSTAR on 14-5-5.
6 | // Copyright (c) 2014年 P.D.Q. All rights reserved.
7 | //
8 |
9 | #import "RSCCControlCellView.h"
10 |
11 | @interface RSCCControlCellViewBackgroundView : NSView
12 | @end
13 |
14 | @implementation RSCCControlCellViewBackgroundView
15 |
16 | - (void) drawRect:(NSRect)dirtyRect {
17 |
18 | CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
19 | NSUInteger hexRGBA = 0xeeeeeeee;
20 | CGContextSetRGBFillColor(context, ((hexRGBA & 0xFF000000) >> 24), ((hexRGBA & 0x00FF0000) >> 16), ((hexRGBA & 0x0000FF00) >> 8), (hexRGBA & 0x000000FF) / 255.0f);
21 | CGContextFillRect(context, NSRectToCGRect(dirtyRect));
22 | }
23 |
24 | @end
25 |
26 | int const RSCCControlCellViewImageButtonTagBase = 1000,
27 | RSCCControlCellViewCocoaPodsButtonTagBase = 2000,
28 | RSCCControlCellViewCloneButtonTagBase = 3000;
29 |
30 | CGFloat const kCocoaPodsButtonWidthConstant = 40.0f,
31 | kButtonsGapConstant = 10.0f;
32 |
33 | @implementation RSCCControlCellView
34 |
35 | - (void) setBackgroundStyle:(NSBackgroundStyle)backgroundStyle {}
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/CocoaControls/RSCCCore.h:
--------------------------------------------------------------------------------
1 | //
2 | // RSCCCore.h
3 | // CocoaControls
4 | //
5 | // Created by R0CKSTAR on 14-5-3.
6 | // Copyright (c) 2014年 P.D.Q. All rights reserved.
7 | //
8 |
9 | #import "AFNetworking.h"
10 | #import "RSCCAPI.h"
11 | #import "RSCCControl.h"
12 |
13 | extern NSString *const RSCCCoreControlsDidLoadNotification,
14 | *const RSCCCoreDetailDidLoadNotification;
15 |
16 | @interface RSCCCore : NSObject
17 |
18 | @property (copy) NSString *filter;
19 |
20 | @property (readonly) AFHTTPRequestOperationManager *imageManager;
21 |
22 | + (instancetype) sharedCore;
23 |
24 | - (void) refreshControls;
25 |
26 | - (void) moreControls;
27 |
28 | - (void) detailForControl:(RSCCControl*) control withSender:(NSButton*)_;
29 |
30 | - (void) searchControlsWithKey:(NSString*) key;
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/CocoaControls/RSCCCore.m:
--------------------------------------------------------------------------------
1 | //
2 | // RSCCCore.m
3 | // CocoaControls
4 | //
5 | // Created by R0CKSTAR on 14-5-3.
6 | // Copyright (c) 2014年 P.D.Q. All rights reserved.
7 | //
8 |
9 | #import "RSCCCore.h"
10 | #import "RSCCHTMLResponseSerializer.h"
11 | #import "RSCCImageRequestSerializer.h"
12 | #import "RSCCImageResponseSerializer.h"
13 | #import "TFHpple.h"
14 |
15 | NSString *const RSCCCoreControlsDidLoadNotification = @"com.pdq.core.controls.did.load",
16 | *const RSCCCoreDetailDidLoadNotification = @"com.pdq.core.control.detail.did.load";
17 |
18 | @interface RSCCCore ()
19 |
20 | @property (nonatomic) AFHTTPRequestOperationManager *requestManager, *imageManager;
21 | @property (nonatomic) int page;
22 |
23 | @end
24 |
25 | @implementation RSCCCore
26 |
27 | - (void) RSCC_parseControlsWithDoc:(TFHpple *)doc {
28 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
29 | NSMutableArray *cs = [@[] mutableCopy];
30 | NSArray *elements = [doc searchWithXPathQuery:@"//*[@class=\"block-grid-item\"]"];
31 | for (TFHppleElement *element in elements) {
32 | RSCCControl *c = [[RSCCControl alloc] initWithAssignment:^(RSCCControl *c) {
33 | NSArray *ps = [element childrenWithTagName:@"p"];
34 | for (TFHppleElement *p in ps) {
35 | TFHppleElement *a = [p firstChildWithTagName:@"a"];
36 | if (a) {
37 | TFHppleElement *img = [a firstChildWithTagName:@"img"];
38 | if (img) {
39 | c.image = [img attributes][@"src"];
40 | } else {
41 | c.title = a.text;
42 | c.link = [a attributes][@"href"];
43 | }
44 | } else {
45 | NSArray *is = [p childrenWithTagName:@"i"];
46 | if ([is count] > 0) {
47 | for (TFHppleElement *i in is) {
48 | NSString *class = [i attributes][@"class"];
49 | if ([class isEqualToString:@"icon-star"]) {
50 | c.rating += 1;
51 | } else if ([class isEqualToString:@"icon-star-half-full"]) {
52 | c.rating += 0.5;
53 | }
54 | }
55 | } else {
56 | NSArray *components = [p.text componentsSeparatedByString:@" • "];
57 | for (NSString *component in components) {
58 | if ([component rangeOfString:@"CocoaPod"].length > 0) {
59 | c.isOnCocoaPods = YES;
60 | } else if ([component rangeOfString:@"Licensed"].length > 0 || [component rangeOfString:@"License"].length > 0) {
61 | c.license = [component stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
62 | } else if ([component rangeOfString:@"App"].length > 0){
63 | c.appsUsingThisControl = [[[component substringToIndex:[component rangeOfString:@"App"].location] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] intValue];
64 | } else {
65 | c.date = component;
66 | }
67 | }
68 | }
69 | }
70 | }
71 | }];
72 | [cs addObject:c];
73 | }
74 | dispatch_async(dispatch_get_main_queue(), ^{
75 | [NSNotificationCenter.defaultCenter postNotificationName:RSCCCoreControlsDidLoadNotification object:[NSArray arrayWithArray:cs] userInfo:@{@"page" : @(self.page)}];
76 | });
77 | });
78 | }
79 |
80 | - (void) RSCC_loadControlsWithURLString:(NSString *)URLString {
81 | [self.requestManager.operationQueue cancelAllOperations];
82 | [self.imageManager.operationQueue cancelAllOperations];
83 |
84 | [self.requestManager GET:URLString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
85 | [self RSCC_parseControlsWithDoc:responseObject];
86 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
87 | if ([error code] != NSURLErrorCancelled) {
88 | [NSNotificationCenter.defaultCenter postNotificationName:RSCCCoreControlsDidLoadNotification object:[NSArray array] userInfo:@{@"page" : @(self.page)}];
89 | }
90 | }];
91 | }
92 |
93 | - init {
94 | self = [super init];
95 | if (self) {
96 | self.requestManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:RSCCAPIRoot]];
97 | self.requestManager.responseSerializer = [RSCCHTMLResponseSerializer serializer];
98 |
99 | self.imageManager = [AFHTTPRequestOperationManager manager];
100 | self.imageManager.requestSerializer = [RSCCImageRequestSerializer serializer];
101 | self.imageManager.responseSerializer = [RSCCImageResponseSerializer serializer];
102 |
103 | self.filter = nil;
104 |
105 | [self refreshControls];
106 | }
107 | return self;
108 | }
109 |
110 | + (instancetype) sharedCore {
111 | static RSCCCore *sharedCore = nil;
112 | static dispatch_once_t onceToken;
113 | dispatch_once(&onceToken, ^{
114 | sharedCore = [self new];
115 | });
116 | return sharedCore;
117 | }
118 |
119 | - (void) refreshControls {
120 | self.page = 1;
121 |
122 | NSString *URLString = (self.filter != nil) ? [NSString stringWithFormat:@"%@&%@", self.filter, [NSString stringWithFormat:RSCCAPIPageFormat, self.page]] : [NSString stringWithFormat:@"%@?%@", RSCCAPIAllPlatform, [NSString stringWithFormat:RSCCAPIPageFormat, self.page]];
123 | [self RSCC_loadControlsWithURLString:URLString];
124 | }
125 |
126 | - (void) moreControls {
127 | self.page += 1;
128 |
129 | NSString *URLString = self.filter ? [NSString stringWithFormat:@"%@&%@", self.filter, [NSString stringWithFormat:RSCCAPIPageFormat, self.page]] : [NSString stringWithFormat:@"%@?%@", RSCCAPIAllPlatform, [NSString stringWithFormat:RSCCAPIPageFormat, self.page]];
130 |
131 | [self RSCC_loadControlsWithURLString:URLString];
132 | }
133 |
134 | - (void) searchControlsWithKey:(NSString*)key {
135 | self.page = 0;
136 |
137 | [self RSCC_loadControlsWithURLString:[[NSString stringWithFormat:RSCCAPISearchFormat, key] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
138 | }
139 |
140 | - (void) detailForControl:(RSCCControl*)control withSender:(NSButton*)sender {
141 | [self.requestManager.operationQueue cancelAllOperations];
142 |
143 | [self.requestManager GET:[NSString stringWithFormat:@"%@%@", RSCCAPIRoot, control.link] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
144 | NSArray *elements = [responseObject searchWithXPathQuery:@"//*[@id=\"pod\"]"];
145 | if ([elements count] > 0) {
146 | TFHppleElement *pod = elements[0];
147 | control.pod = [pod attributes][@"value"];
148 | }
149 |
150 | elements = [responseObject searchWithXPathQuery:@"//*[@id=\"get_source_link\"]"];
151 | if ([elements count] > 0) {
152 | TFHppleElement *source = elements[0];
153 | control.source = [source attributes][@"href"];
154 | }
155 |
156 | if (control.pod || control.source) {
157 | [NSNotificationCenter.defaultCenter postNotificationName:RSCCCoreDetailDidLoadNotification object:control userInfo:@{@"sender" : sender}];
158 | }
159 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
160 | if ([error code] != NSURLErrorCancelled) {
161 | [NSNotificationCenter.defaultCenter postNotificationName:RSCCCoreDetailDidLoadNotification object:control userInfo:@{@"sender" : sender}];
162 | }
163 | }];
164 | }
165 |
166 | @end
167 |
--------------------------------------------------------------------------------
/CocoaControls/RSCCHTMLResponseSerializer.h:
--------------------------------------------------------------------------------
1 | //
2 | // RSCCHTMLResponseSerializer.h
3 | // CocoaControls
4 | //
5 | // Created by R0CKSTAR on 5/5/14.
6 | // Copyright (c) 2014 P.D.Q. All rights reserved.
7 | //
8 |
9 | #import "AFURLResponseSerialization.h"
10 |
11 | @interface RSCCHTMLResponseSerializer : AFHTTPResponseSerializer
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/CocoaControls/RSCCHTMLResponseSerializer.m:
--------------------------------------------------------------------------------
1 | //
2 | // RSCCHTMLResponseSerializer.m
3 | // CocoaControls
4 | //
5 | // Created by R0CKSTAR on 5/5/14.
6 | // Copyright (c) 2014 P.D.Q. All rights reserved.
7 | //
8 |
9 | #import "RSCCHTMLResponseSerializer.h"
10 |
11 | #import "TFHpple.h"
12 |
13 | @implementation RSCCHTMLResponseSerializer
14 |
15 | - responseObjectForResponse:(NSURLResponse *)response
16 | data:(NSData *)data
17 | error:(NSError *__autoreleasing *)error {
18 |
19 | return [TFHpple.alloc initWithHTMLData:data];
20 | }
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/CocoaControls/RSCCImageRequestSerializer.h:
--------------------------------------------------------------------------------
1 | //
2 | // RSCCImageRequestSerializer.h
3 | // CocoaControls
4 | //
5 | // Created by R0CKSTAR on 5/7/14.
6 | // Copyright (c) 2014 P.D.Q. All rights reserved.
7 | //
8 |
9 | #import "AFURLRequestSerialization.h"
10 |
11 | @interface RSCCImageRequestSerializer : AFHTTPRequestSerializer
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/CocoaControls/RSCCImageRequestSerializer.m:
--------------------------------------------------------------------------------
1 | //
2 | // RSCCImageRequestSerializer.m
3 | // CocoaControls
4 | //
5 | // Created by R0CKSTAR on 5/7/14.
6 | // Copyright (c) 2014 P.D.Q. All rights reserved.
7 | //
8 |
9 | #import "RSCCImageRequestSerializer.h"
10 |
11 | @implementation RSCCImageRequestSerializer
12 |
13 | - init { return super.init ? self.cachePolicy = NSURLRequestReturnCacheDataElseLoad, self : nil; }
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/CocoaControls/RSCCImageResponseSerializer.h:
--------------------------------------------------------------------------------
1 | //
2 | // RSCCImageResponseSerializer.h
3 | // CocoaControls
4 | //
5 | // Created by R0CKSTAR on 5/6/14.
6 | // Copyright (c) 2014 P.D.Q. All rights reserved.
7 | //
8 |
9 | #import "AFURLResponseSerialization.h"
10 |
11 | @interface RSCCImageResponseSerializer : AFHTTPResponseSerializer
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/CocoaControls/RSCCImageResponseSerializer.m:
--------------------------------------------------------------------------------
1 | //
2 | // RSCCImageResponseSerializer.m
3 | // CocoaControls
4 | //
5 | // Created by R0CKSTAR on 5/6/14.
6 | // Copyright (c) 2014 P.D.Q. All rights reserved.
7 | //
8 |
9 | #import "RSCCImageResponseSerializer.h"
10 |
11 | @implementation RSCCImageResponseSerializer
12 |
13 | - responseObjectForResponse:(NSURLResponse *)response
14 | data:(NSData *)data
15 | error:(NSError *__autoreleasing *)error {
16 |
17 | return [NSImage.alloc initWithData:data];
18 | }
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/CocoaControls/en.lproj/Credits.rtf:
--------------------------------------------------------------------------------
1 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf190
2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;}
3 | {\colortbl;\red255\green255\blue255;}
4 | \paperw11900\paperh16840\vieww9600\viewh8400\viewkind0
5 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
6 |
7 | \f0\b\fs24 \cf0 Engineering:
8 | \b0 \
9 | R0CKSTAR\
10 | \
11 |
12 | \b Human Interface Design:
13 | \b0 \
14 | R0CKSTAR\
15 | \
16 |
17 | \b Testing:
18 | \b0 \
19 | R0CKSTAR\
20 | \
21 |
22 | \b Documentation:
23 | \b0 \
24 | R0CKSTAR\
25 | \
26 |
27 | \b With special thanks to:
28 | \b0 \
29 | LY&YYY\
30 | }
--------------------------------------------------------------------------------
/CocoaControls/hpple/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2009 Topfunky Corporation, http://topfunky.com
2 |
3 | MIT LICENSE
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/CocoaControls/hpple/README.markdown:
--------------------------------------------------------------------------------
1 | # DESCRIPTION
2 |
3 | Hpple: A nice Objective-C wrapper on the XPathQuery library for parsing HTML.
4 |
5 | Inspired by why the lucky stiff's [Hpricot](http://github.com/why/hpricot/tree/master).
6 |
7 | # CREDITS
8 |
9 | Hpple was created by Geoffrey Grosenbach, [Topfunky Corporation](http://topfunky.com) and [PeepCode Screencasts](http://peepcode.com).
10 |
11 | [Contributors](https://github.com/topfunky/hpple/graphs/contributors)
12 |
13 | # FEATURES
14 |
15 | * Easy searching by XPath (CSS selectors are planned)
16 | * Parses HTML (XML coming soon)
17 | * Easy access to tag content, name, and attributes.
18 |
19 | # INSTALLATION
20 |
21 | * Open your XCode project and the Hpple project.
22 | * Drag the "Hpple" directory to your project.
23 | * Add the libxml2.2.dylib framework to your project and search paths as described at [Cocoa with Love](http://cocoawithlove.com/2008/10/using-libxml2-for-parsing-and-xpath.html)
24 |
25 | More documentation and short screencast coming soon...
26 |
27 | # USAGE
28 |
29 | See TFHppleHTMLTest.m in the Hpple project for samples.
30 |
31 |
32 | #import "TFHpple.h"
33 |
34 | NSData * data = [NSData dataWithContentsOfFile:@"index.html"];
35 |
36 | TFHpple * doc = [[TFHpple alloc] initWithHTMLData:data];
37 | NSArray * elements = [doc search:@"//a[@class='sponsor']"];
38 |
39 | TFHppleElement * element = [elements objectAtIndex:0];
40 | [e text]; // The text inside the HTML element (the content of the first text node)
41 | [e tagName]; // "a"
42 | [e attributes]; // NSDictionary of href, class, id, etc.
43 | [e objectForKey:@"href"]; // Easy access to single attribute
44 | [e firstChildWithTagName:@"b"]; // The first "b" child node
45 |
46 |
47 |
48 | # TODO
49 |
50 | * Internal error catching and messages
51 | * CSS3 selectors in addition to XPath
52 |
--------------------------------------------------------------------------------
/CocoaControls/hpple/TFHpple.h:
--------------------------------------------------------------------------------
1 | //
2 | // TFHpple.h
3 | // Hpple
4 | //
5 | // Created by Geoffrey Grosenbach on 1/31/09.
6 | //
7 | // Copyright (c) 2009 Topfunky Corporation, http://topfunky.com
8 | //
9 | // MIT LICENSE
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining
12 | // a copy of this software and associated documentation files (the
13 | // "Software"), to deal in the Software without restriction, including
14 | // without limitation the rights to use, copy, modify, merge, publish,
15 | // distribute, sublicense, and/or sell copies of the Software, and to
16 | // permit persons to whom the Software is furnished to do so, subject to
17 | // the following conditions:
18 | //
19 | // The above copyright notice and this permission notice shall be
20 | // included in all copies or substantial portions of the Software.
21 | //
22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 |
30 |
31 | #import
32 |
33 | #import "TFHppleElement.h"
34 |
35 | @interface TFHpple : NSObject {
36 | @private
37 | NSData * data;
38 | BOOL isXML;
39 | }
40 |
41 | - (id) initWithData:(NSData *)theData isXML:(BOOL)isDataXML;
42 | - (id) initWithXMLData:(NSData *)theData;
43 | - (id) initWithHTMLData:(NSData *)theData;
44 |
45 | + (TFHpple *) hppleWithData:(NSData *)theData isXML:(BOOL)isDataXML;
46 | + (TFHpple *) hppleWithXMLData:(NSData *)theData;
47 | + (TFHpple *) hppleWithHTMLData:(NSData *)theData;
48 |
49 | - (NSArray *) searchWithXPathQuery:(NSString *)xPathOrCSS;
50 | - (TFHppleElement *) peekAtSearchWithXPathQuery:(NSString *)xPathOrCSS;
51 |
52 | @property (nonatomic, strong, readonly) NSData * data;
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/CocoaControls/hpple/TFHpple.m:
--------------------------------------------------------------------------------
1 | //
2 | // TFHpple.m
3 | // Hpple
4 | //
5 | // Created by Geoffrey Grosenbach on 1/31/09.
6 | //
7 | // Copyright (c) 2009 Topfunky Corporation, http://topfunky.com
8 | //
9 | // MIT LICENSE
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining
12 | // a copy of this software and associated documentation files (the
13 | // "Software"), to deal in the Software without restriction, including
14 | // without limitation the rights to use, copy, modify, merge, publish,
15 | // distribute, sublicense, and/or sell copies of the Software, and to
16 | // permit persons to whom the Software is furnished to do so, subject to
17 | // the following conditions:
18 | //
19 | // The above copyright notice and this permission notice shall be
20 | // included in all copies or substantial portions of the Software.
21 | //
22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 |
30 | #import "TFHpple.h"
31 | #import "XPathQuery.h"
32 |
33 | @implementation TFHpple
34 |
35 | @synthesize data;
36 |
37 |
38 | - (id) initWithData:(NSData *)theData isXML:(BOOL)isDataXML
39 | {
40 | if (!(self = [super init])) {
41 | return nil;
42 | }
43 |
44 | data = theData;
45 | isXML = isDataXML;
46 |
47 | return self;
48 | }
49 |
50 | - (id) initWithXMLData:(NSData *)theData
51 | {
52 | return [self initWithData:theData isXML:YES];
53 | }
54 |
55 | - (id) initWithHTMLData:(NSData *)theData
56 | {
57 | return [self initWithData:theData isXML:NO];
58 | }
59 |
60 | + (TFHpple *) hppleWithData:(NSData *)theData isXML:(BOOL)isDataXML {
61 | return [[[self class] alloc] initWithData:theData isXML:isDataXML];
62 | }
63 |
64 | + (TFHpple *) hppleWithHTMLData:(NSData *)theData {
65 | return [[self class] hppleWithData:theData isXML:NO];
66 | }
67 |
68 | + (TFHpple *) hppleWithXMLData:(NSData *)theData {
69 | return [[self class] hppleWithData:theData isXML:YES];
70 | }
71 |
72 | #pragma mark -
73 |
74 | // Returns all elements at xPath.
75 | - (NSArray *) searchWithXPathQuery:(NSString *)xPathOrCSS
76 | {
77 | NSArray * detailNodes = nil;
78 | if (isXML) {
79 | detailNodes = PerformXMLXPathQuery(data, xPathOrCSS);
80 | } else {
81 | detailNodes = PerformHTMLXPathQuery(data, xPathOrCSS);
82 | }
83 |
84 | NSMutableArray * hppleElements = [NSMutableArray array];
85 | for (id node in detailNodes) {
86 | [hppleElements addObject:[TFHppleElement hppleElementWithNode:node]];
87 | }
88 | return hppleElements;
89 | }
90 |
91 | // Returns first element at xPath
92 | - (TFHppleElement *) peekAtSearchWithXPathQuery:(NSString *)xPathOrCSS
93 | {
94 | NSArray * elements = [self searchWithXPathQuery:xPathOrCSS];
95 | if ([elements count] >= 1) {
96 | return [elements objectAtIndex:0];
97 | }
98 |
99 | return nil;
100 | }
101 |
102 | @end
103 |
--------------------------------------------------------------------------------
/CocoaControls/hpple/TFHppleElement.h:
--------------------------------------------------------------------------------
1 | //
2 | // TFHppleElement.h
3 | // Hpple
4 | //
5 | // Created by Geoffrey Grosenbach on 1/31/09.
6 | //
7 | // Copyright (c) 2009 Topfunky Corporation, http://topfunky.com
8 | //
9 | // MIT LICENSE
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining
12 | // a copy of this software and associated documentation files (the
13 | // "Software"), to deal in the Software without restriction, including
14 | // without limitation the rights to use, copy, modify, merge, publish,
15 | // distribute, sublicense, and/or sell copies of the Software, and to
16 | // permit persons to whom the Software is furnished to do so, subject to
17 | // the following conditions:
18 | //
19 | // The above copyright notice and this permission notice shall be
20 | // included in all copies or substantial portions of the Software.
21 | //
22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 |
30 | #import
31 |
32 |
33 | @interface TFHppleElement : NSObject {
34 | @private
35 |
36 | NSDictionary * node;
37 | __unsafe_unretained TFHppleElement *parent;
38 | }
39 |
40 | - (id) initWithNode:(NSDictionary *) theNode;
41 |
42 | + (TFHppleElement *) hppleElementWithNode:(NSDictionary *) theNode;
43 |
44 | @property (nonatomic, copy, readonly) NSString *raw;
45 | // Returns this tag's innerHTML content.
46 | @property (nonatomic, copy, readonly) NSString *content;
47 |
48 | // Returns the name of the current tag, such as "h3".
49 | @property (nonatomic, copy, readonly) NSString *tagName;
50 |
51 | // Returns tag attributes with name as key and content as value.
52 | // href = 'http://peepcode.com'
53 | // class = 'highlight'
54 | @property (nonatomic, strong, readonly) NSDictionary *attributes;
55 |
56 | // Returns the children of a given node
57 | @property (nonatomic, strong, readonly) NSArray *children;
58 |
59 | // Returns the first child of a given node
60 | @property (nonatomic, strong, readonly) TFHppleElement *firstChild;
61 |
62 | // the parent of a node
63 | @property (nonatomic, unsafe_unretained, readonly) TFHppleElement *parent;
64 |
65 | // Returns YES if the node has any child
66 | // This is more efficient than using the children property since no NSArray is constructed
67 | - (BOOL)hasChildren;
68 |
69 | // Returns YES if this is a text node
70 | - (BOOL)isTextNode;
71 |
72 | // Provides easy access to the content of a specific attribute,
73 | // such as 'href' or 'class'.
74 | - (NSString *) objectForKey:(NSString *) theKey;
75 |
76 | // Returns the children whose tag name equals the given string
77 | // (comparison is performed with NSString's isEqualToString)
78 | // Returns an empty array if no matching child is found
79 | - (NSArray *) childrenWithTagName:(NSString *)tagName;
80 |
81 | // Returns the first child node whose tag name equals the given string
82 | // (comparison is performed with NSString's isEqualToString)
83 | // Returns nil if no matching child is found
84 | - (TFHppleElement *) firstChildWithTagName:(NSString *)tagName;
85 |
86 | // Returns the children whose class equals the given string
87 | // (comparison is performed with NSString's isEqualToString)
88 | // Returns an empty array if no matching child is found
89 | - (NSArray *) childrenWithClassName:(NSString *)className;
90 |
91 | // Returns the first child whose class requals the given string
92 | // (comparison is performed with NSString's isEqualToString)
93 | // Returns nil if no matching child is found
94 | - (TFHppleElement *) firstChildWithClassName:(NSString*)className;
95 |
96 | // Returns the first text node from this element's children
97 | // Returns nil if there is no text node among the children
98 | - (TFHppleElement *) firstTextChild;
99 |
100 | // Returns the string contained by the first text node from this element's children
101 | // Convenience method which can be used instead of firstTextChild.content
102 | - (NSString *) text;
103 |
104 | @end
105 |
--------------------------------------------------------------------------------
/CocoaControls/hpple/TFHppleElement.m:
--------------------------------------------------------------------------------
1 | //
2 | // TFHppleElement.m
3 | // Hpple
4 | //
5 | // Created by Geoffrey Grosenbach on 1/31/09.
6 | //
7 | // Copyright (c) 2009 Topfunky Corporation, http://topfunky.com
8 | //
9 | // MIT LICENSE
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining
12 | // a copy of this software and associated documentation files (the
13 | // "Software"), to deal in the Software without restriction, including
14 | // without limitation the rights to use, copy, modify, merge, publish,
15 | // distribute, sublicense, and/or sell copies of the Software, and to
16 | // permit persons to whom the Software is furnished to do so, subject to
17 | // the following conditions:
18 | //
19 | // The above copyright notice and this permission notice shall be
20 | // included in all copies or substantial portions of the Software.
21 | //
22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 |
30 |
31 | #import "TFHppleElement.h"
32 |
33 | static NSString * const TFHppleNodeContentKey = @"nodeContent";
34 | static NSString * const TFHppleNodeNameKey = @"nodeName";
35 | static NSString * const TFHppleNodeChildrenKey = @"nodeChildArray";
36 | static NSString * const TFHppleNodeAttributeArrayKey = @"nodeAttributeArray";
37 | static NSString * const TFHppleNodeAttributeNameKey = @"attributeName";
38 |
39 | static NSString * const TFHppleTextNodeName = @"text";
40 |
41 | @interface TFHppleElement ()
42 | @property (nonatomic, unsafe_unretained, readwrite) TFHppleElement *parent;
43 | @end
44 |
45 | @implementation TFHppleElement
46 | @synthesize parent;
47 |
48 |
49 | - (id) initWithNode:(NSDictionary *) theNode
50 | {
51 | if (!(self = [super init]))
52 | return nil;
53 |
54 | node = theNode;
55 |
56 | return self;
57 | }
58 |
59 | + (TFHppleElement *) hppleElementWithNode:(NSDictionary *) theNode {
60 | return [[[self class] alloc] initWithNode:theNode];
61 | }
62 |
63 | #pragma mark -
64 |
65 | - (NSString *)raw
66 | {
67 | return [node objectForKey:@"raw"];
68 | }
69 |
70 | - (NSString *) content
71 | {
72 | return [node objectForKey:TFHppleNodeContentKey];
73 | }
74 |
75 |
76 | - (NSString *) tagName
77 | {
78 | return [node objectForKey:TFHppleNodeNameKey];
79 | }
80 |
81 | - (NSArray *) children
82 | {
83 | NSMutableArray *children = [NSMutableArray array];
84 | for (NSDictionary *child in [node objectForKey:TFHppleNodeChildrenKey]) {
85 | TFHppleElement *element = [TFHppleElement hppleElementWithNode:child];
86 | element.parent = self;
87 | [children addObject:element];
88 | }
89 | return children;
90 | }
91 |
92 | - (TFHppleElement *) firstChild
93 | {
94 | NSArray * children = self.children;
95 | if (children.count)
96 | return [children objectAtIndex:0];
97 | return nil;
98 | }
99 |
100 |
101 | - (NSDictionary *) attributes
102 | {
103 | NSMutableDictionary * translatedAttributes = [NSMutableDictionary dictionary];
104 | for (NSDictionary * attributeDict in [node objectForKey:TFHppleNodeAttributeArrayKey]) {
105 | if ([attributeDict objectForKey:TFHppleNodeContentKey] && [attributeDict objectForKey:TFHppleNodeAttributeNameKey]) {
106 | [translatedAttributes setObject:[attributeDict objectForKey:TFHppleNodeContentKey]
107 | forKey:[attributeDict objectForKey:TFHppleNodeAttributeNameKey]];
108 | }
109 | }
110 | return translatedAttributes;
111 | }
112 |
113 | - (NSString *) objectForKey:(NSString *) theKey
114 | {
115 | return [[self attributes] objectForKey:theKey];
116 | }
117 |
118 | - (id) description
119 | {
120 | return [node description];
121 | }
122 |
123 | - (BOOL)hasChildren
124 | {
125 | if ([node objectForKey:TFHppleNodeChildrenKey])
126 | return YES;
127 | else
128 | return NO;
129 | }
130 |
131 | - (BOOL)isTextNode
132 | {
133 | // we must distinguish between real text nodes and standard nodes with tha name "text" ()
134 | // real text nodes must have content
135 | if ([self.tagName isEqualToString:TFHppleTextNodeName] && (self.content))
136 | return YES;
137 | else
138 | return NO;
139 | }
140 |
141 | - (NSArray*) childrenWithTagName:(NSString*)tagName
142 | {
143 | NSMutableArray* matches = [NSMutableArray array];
144 |
145 | for (TFHppleElement* child in self.children)
146 | {
147 | if ([child.tagName isEqualToString:tagName])
148 | [matches addObject:child];
149 | }
150 |
151 | return matches;
152 | }
153 |
154 | - (TFHppleElement *) firstChildWithTagName:(NSString*)tagName
155 | {
156 | for (TFHppleElement* child in self.children)
157 | {
158 | if ([child.tagName isEqualToString:tagName])
159 | return child;
160 | }
161 |
162 | return nil;
163 | }
164 |
165 | - (NSArray*) childrenWithClassName:(NSString*)className
166 | {
167 | NSMutableArray* matches = [NSMutableArray array];
168 |
169 | for (TFHppleElement* child in self.children)
170 | {
171 | if ([[child objectForKey:@"class"] isEqualToString:className])
172 | [matches addObject:child];
173 | }
174 |
175 | return matches;
176 | }
177 |
178 | - (TFHppleElement *) firstChildWithClassName:(NSString*)className
179 | {
180 | for (TFHppleElement* child in self.children)
181 | {
182 | if ([[child objectForKey:@"class"] isEqualToString:className])
183 | return child;
184 | }
185 |
186 | return nil;
187 | }
188 |
189 | - (TFHppleElement *) firstTextChild;
190 | {
191 | for (TFHppleElement* child in self.children)
192 | {
193 | if ([child isTextNode])
194 | return child;
195 | }
196 |
197 | return [self firstChildWithTagName:TFHppleTextNodeName];
198 | }
199 |
200 | - (NSString *) text
201 | {
202 | return self.firstTextChild.content;
203 | }
204 |
205 | @end
206 |
--------------------------------------------------------------------------------
/CocoaControls/hpple/XPathQuery.h:
--------------------------------------------------------------------------------
1 | //
2 | // XPathQuery.h
3 | // FuelFinder
4 | //
5 | // Created by Matt Gallagher on 4/08/08.
6 | // Copyright 2008 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | NSArray *PerformHTMLXPathQuery(NSData *document, NSString *query);
10 | NSArray *PerformXMLXPathQuery(NSData *document, NSString *query);
11 |
--------------------------------------------------------------------------------
/CocoaControls/hpple/XPathQuery.m:
--------------------------------------------------------------------------------
1 | //
2 | // XPathQuery.m
3 | // FuelFinder
4 | //
5 | // Created by Matt Gallagher on 4/08/08.
6 | // Copyright 2008 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "XPathQuery.h"
10 |
11 | #import
12 | #import
13 | #import
14 | #import
15 | #import
16 |
17 | NSDictionary *DictionaryForNode(xmlNodePtr currentNode, NSMutableDictionary *parentResult,BOOL parentContent);
18 | NSArray *PerformXPathQuery(xmlDocPtr doc, NSString *query);
19 |
20 | NSDictionary *DictionaryForNode(xmlNodePtr currentNode, NSMutableDictionary *parentResult,BOOL parentContent)
21 | {
22 | NSMutableDictionary *resultForNode = [NSMutableDictionary dictionary];
23 |
24 | if (currentNode->name)
25 | {
26 | NSString *currentNodeContent =
27 | [NSString stringWithCString:(const char *)currentNode->name encoding:NSUTF8StringEncoding];
28 | [resultForNode setObject:currentNodeContent forKey:@"nodeName"];
29 | }
30 |
31 | if (currentNode->content && currentNode->content != (xmlChar *)-1)
32 | {
33 | NSString *currentNodeContent =
34 | [NSString stringWithCString:(const char *)currentNode->content encoding:NSUTF8StringEncoding];
35 |
36 | if ([[resultForNode objectForKey:@"nodeName"] isEqual:@"text"] && parentResult)
37 | {
38 | if(parentContent)
39 | {
40 | [parentResult setObject:[currentNodeContent stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] forKey:@"nodeContent"];
41 | return nil;
42 | }
43 | [resultForNode setObject:currentNodeContent forKey:@"nodeContent"];
44 | // NSLog(@"content: %@",currentNodeContent);
45 | return resultForNode;
46 |
47 | }
48 | else {
49 | [resultForNode setObject:currentNodeContent forKey:@"nodeContent"];
50 | }
51 |
52 |
53 | }
54 |
55 | xmlAttr *attribute = currentNode->properties;
56 | if (attribute)
57 | {
58 | NSMutableArray *attributeArray = [NSMutableArray array];
59 | while (attribute)
60 | {
61 | NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary];
62 | NSString *attributeName =
63 | [NSString stringWithCString:(const char *)attribute->name encoding:NSUTF8StringEncoding];
64 | if (attributeName)
65 | {
66 | // NSLog(@"Attribute Name Set: %@",attributeName);
67 | [attributeDictionary setObject:attributeName forKey:@"attributeName"];
68 | }
69 |
70 | if (attribute->children)
71 | {
72 | NSDictionary *childDictionary = DictionaryForNode(attribute->children, attributeDictionary,true);
73 | if (childDictionary)
74 | {
75 | [attributeDictionary setObject:childDictionary forKey:@"attributeContent"];
76 | }
77 | }
78 |
79 | if ([attributeDictionary count] > 0)
80 | {
81 | [attributeArray addObject:attributeDictionary];
82 | }
83 | attribute = attribute->next;
84 | }
85 |
86 | if ([attributeArray count] > 0)
87 | {
88 | [resultForNode setObject:attributeArray forKey:@"nodeAttributeArray"];
89 | }
90 | }
91 |
92 | xmlNodePtr childNode = currentNode->children;
93 | if (childNode)
94 | {
95 | NSMutableArray *childContentArray = [NSMutableArray array];
96 | while (childNode)
97 | {
98 | NSDictionary *childDictionary = DictionaryForNode(childNode, resultForNode,false);
99 | if (childDictionary)
100 | {
101 | [childContentArray addObject:childDictionary];
102 | }
103 | childNode = childNode->next;
104 | }
105 | if ([childContentArray count] > 0)
106 | {
107 | [resultForNode setObject:childContentArray forKey:@"nodeChildArray"];
108 | }
109 | }
110 |
111 | xmlBufferPtr buffer = xmlBufferCreate();
112 | xmlNodeDump(buffer, currentNode->doc, currentNode, 0, 0);
113 |
114 | NSString *rawContent = [NSString stringWithCString:(const char *)buffer->content encoding:NSUTF8StringEncoding];
115 | [resultForNode setObject:rawContent forKey:@"raw"];
116 |
117 | xmlBufferFree(buffer);
118 |
119 | return resultForNode;
120 | }
121 |
122 | NSArray *PerformXPathQuery(xmlDocPtr doc, NSString *query)
123 | {
124 | xmlXPathContextPtr xpathCtx;
125 | xmlXPathObjectPtr xpathObj;
126 |
127 | /* Create xpath evaluation context */
128 | xpathCtx = xmlXPathNewContext(doc);
129 | if(xpathCtx == NULL)
130 | {
131 | NSLog(@"Unable to create XPath context.");
132 | return nil;
133 | }
134 |
135 | /* Evaluate xpath expression */
136 | xpathObj = xmlXPathEvalExpression((xmlChar *)[query cStringUsingEncoding:NSUTF8StringEncoding], xpathCtx);
137 | if(xpathObj == NULL) {
138 | NSLog(@"Unable to evaluate XPath.");
139 | xmlXPathFreeContext(xpathCtx);
140 | return nil;
141 | }
142 |
143 | xmlNodeSetPtr nodes = xpathObj->nodesetval;
144 | if (!nodes)
145 | {
146 | NSLog(@"Nodes was nil.");
147 | xmlXPathFreeObject(xpathObj);
148 | xmlXPathFreeContext(xpathCtx);
149 | return nil;
150 | }
151 |
152 | NSMutableArray *resultNodes = [NSMutableArray array];
153 | for (NSInteger i = 0; i < nodes->nodeNr; i++)
154 | {
155 | NSDictionary *nodeDictionary = DictionaryForNode(nodes->nodeTab[i], nil,false);
156 | if (nodeDictionary)
157 | {
158 | [resultNodes addObject:nodeDictionary];
159 | }
160 | }
161 |
162 | /* Cleanup */
163 | xmlXPathFreeObject(xpathObj);
164 | xmlXPathFreeContext(xpathCtx);
165 |
166 | return resultNodes;
167 | }
168 |
169 | NSArray *PerformHTMLXPathQuery(NSData *document, NSString *query)
170 | {
171 | xmlDocPtr doc;
172 |
173 | /* Load XML document */
174 | doc = htmlReadMemory([document bytes], (int)[document length], "", NULL, HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR);
175 |
176 | if (doc == NULL)
177 | {
178 | NSLog(@"Unable to parse.");
179 | return nil;
180 | }
181 |
182 | NSArray *result = PerformXPathQuery(doc, query);
183 | xmlFreeDoc(doc);
184 |
185 | return result;
186 | }
187 |
188 | NSArray *PerformXMLXPathQuery(NSData *document, NSString *query)
189 | {
190 | xmlDocPtr doc;
191 |
192 | /* Load XML document */
193 | doc = xmlReadMemory([document bytes], (int)[document length], "", NULL, XML_PARSE_RECOVER);
194 |
195 | if (doc == NULL)
196 | {
197 | NSLog(@"Unable to parse.");
198 | return nil;
199 | }
200 |
201 | NSArray *result = PerformXPathQuery(doc, query);
202 | xmlFreeDoc(doc);
203 |
204 | return result;
205 | }
206 |
--------------------------------------------------------------------------------
/CocoaControlsPlugin/CocoaControlsPlugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CocoaControlsPlugin/CocoaControlsPlugin.xcodeproj/project.xcworkspace/xcshareddata/CocoaControlsPlugin.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | 7C3A4982-FB4F-4965-8B4C-0C3BCAFDC7DC
9 | IDESourceControlProjectName
10 | CocoaControlsPlugin
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | 69291726009AC4C9A421F4E062E482087A00300B
14 | https://github.com/yeahdongcn/CocoaControlsPlugin.git
15 |
16 | IDESourceControlProjectPath
17 | CocoaControlsPlugin/CocoaControlsPlugin.xcodeproj
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | 69291726009AC4C9A421F4E062E482087A00300B
21 | ../../..
22 |
23 | IDESourceControlProjectURL
24 | https://github.com/yeahdongcn/CocoaControlsPlugin.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | 69291726009AC4C9A421F4E062E482087A00300B
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | 69291726009AC4C9A421F4E062E482087A00300B
36 | IDESourceControlWCCName
37 | CocoaControlsPlugin
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/CocoaControlsPlugin/CocoaControlsPlugin.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CocoaControlsPlugin/CocoaControlsPlugin.xcodeproj/xcshareddata/xcschemes/CocoaControlsPlugin.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
66 |
67 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/CocoaControlsPlugin/CocoaControlsPlugin/CocoaControlsPlugin-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | English
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | BNDL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | DVTPlugInCompatibilityUUIDs
26 |
27 | FEC992CC-CA4A-4CFD-8881-77300FCB848A
28 | C4A681B0-4A26-480E-93EC-1218098B9AA0
29 | A2E4D43F-41F4-4FB9-BB94-7177011C9AED
30 | AD68E85B-441B-4301-B564-A45E4919A6AD
31 | 63FC1C47-140D-42B0-BB4D-A10B2D225574
32 | 37B30044-3B14-46BA-ABAA-F01000C27B63
33 | 640F884E-CE55-4B40-87C0-8869546CAB7A
34 | 992275C1-432A-4CF7-B659-D84ED6D42D3F
35 | A16FF353-8441-459E-A50C-B071F53F51B7
36 | 9F75337B-21B4-4ADC-B558-F9CADF7073A7
37 | E969541F-E6F9-4D25-8158-72DC3545A6C6
38 | 8DC44374-2B35-4C57-A6FE-2AD66A36AAD9
39 | AABB7188-E14E-4433-AD3B-5CD791EAD9A3
40 | 7FDF5C7A-131F-4ABB-9EDC-8C5F8F0B8A90
41 | 0420B86A-AA43-4792-9ED0-6FE0F2B16A13
42 | CC0D0F4F-05B3-431A-8F33-F84AFCB2C651
43 | 7265231C-39B4-402C-89E1-16167C4CC990
44 | 9AFF134A-08DC-4096-8CEE-62A4BB123046
45 |
46 | NSPrincipalClass
47 | RSCCPCocoaControlsPlugin
48 | XC4Compatible
49 |
50 | XC5Compatible
51 |
52 | XCGCReady
53 |
54 | XCPluginHasUI
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/CocoaControlsPlugin/CocoaControlsPlugin/CocoaControlsPlugin-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 | #ifdef __OBJC__
8 | #import
9 | #import
10 | #endif
11 |
--------------------------------------------------------------------------------
/CocoaControlsPlugin/CocoaControlsPlugin/Helpers/CCPProject.h:
--------------------------------------------------------------------------------
1 | //
2 | // CCPWorkspace.h
3 | //
4 | // Copyright (c) 2013 Delisa Mason. http://delisa.me
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 |
24 | @interface CCPProject : NSObject
25 |
26 | @property (nonatomic) NSString *directoryPath, *podspecPath, *podfilePath, *projectName;
27 | @property (nonatomic) NSDictionary *infoDictionary;
28 | @property (readonly) BOOL hasPodfile, hasPodspecFile;
29 |
30 | + (instancetype) projectForKeyWindow;
31 | + (instancetype) projectForWindow:window;
32 |
33 | - initWithName:(NSString*)name
34 | path:(NSString*)path;
35 |
36 | - (void) createPodspecFromTemplate:(NSString*)_template;
37 |
38 | - (BOOL) containsFileWithName:(NSString*)fileName;
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/CocoaControlsPlugin/CocoaControlsPlugin/Helpers/CCPProject.m:
--------------------------------------------------------------------------------
1 | //
2 | // CCPWorkspace.m
3 | //
4 | // Copyright (c) 2013 Delisa Mason. http://delisa.me
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 |
24 | #import
25 | #import "CCPProject.h"
26 | #import "CCPWorkspaceManager.h"
27 |
28 | @implementation CCPProject
29 |
30 | + (instancetype)projectForWindow:(id)window
31 | {
32 | id workspace = [CCPWorkspaceManager workspaceForWindow:window];
33 |
34 | id contextManager = [workspace valueForKey:@"_runContextManager"];
35 | for (id scheme in[contextManager valueForKey:@"runContexts"]) {
36 | NSString *schemeName = [scheme valueForKey:@"name"];
37 | if (![schemeName hasPrefix:@"Pods-"]) {
38 | NSString *path = [CCPWorkspaceManager directoryPathForWorkspace:workspace];
39 | return [[CCPProject alloc] initWithName:schemeName path:path];
40 | }
41 | }
42 |
43 | return nil;
44 | }
45 |
46 | + (instancetype)projectForKeyWindow
47 | {
48 | id workspace = [CCPWorkspaceManager workspaceForKeyWindow];
49 |
50 | id contextManager = [workspace valueForKey:@"_runContextManager"];
51 | for (id scheme in[contextManager valueForKey:@"runContexts"]) {
52 | NSString *schemeName = [scheme valueForKey:@"name"];
53 | if (![schemeName hasPrefix:@"Pods-"]) {
54 | NSString *path = [CCPWorkspaceManager directoryPathForWorkspace:workspace];
55 | return [[CCPProject alloc] initWithName:schemeName path:path];
56 | }
57 | }
58 |
59 | return nil;
60 | }
61 |
62 | - (id)initWithName:(NSString*)name
63 | path:(NSString*)path
64 | {
65 | if (self = [self init]) {
66 | _projectName = name;
67 | _podspecPath = [path stringByAppendingPathComponent:[name stringByAppendingString:@".podspec"]];
68 | _directoryPath = path;
69 |
70 | NSString *infoPath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"%@/%@-Info.plist", _projectName, _projectName]];
71 |
72 | _infoDictionary = [NSDictionary dictionaryWithContentsOfFile:infoPath];
73 | _podfilePath = [path stringByAppendingPathComponent:@"Podfile"];
74 | }
75 |
76 | return self;
77 | }
78 |
79 | - (BOOL)hasPodspecFile
80 | {
81 | return [[NSFileManager defaultManager] fileExistsAtPath:self.podspecPath];
82 | }
83 |
84 | - (BOOL)hasPodfile
85 | {
86 | return [[NSFileManager defaultManager] fileExistsAtPath:self.podfilePath];
87 | }
88 |
89 | - (void)createPodspecFromTemplate:(NSString*)_template
90 | {
91 | NSMutableString *podspecFile = _template.mutableCopy;
92 | NSRange range; range.location = 0;
93 |
94 | range.length = podspecFile.length;
95 | [podspecFile replaceOccurrencesOfString:@""
96 | withString:self.projectName
97 | options:NSLiteralSearch
98 | range:range];
99 |
100 | NSString *version = self.infoDictionary[@"CFBundleShortVersionString"];
101 | if (version) {
102 | range.length = podspecFile.length;
103 | [podspecFile replaceOccurrencesOfString:@""
104 | withString:version
105 | options:NSLiteralSearch
106 | range:range];
107 | }
108 |
109 | range.length = podspecFile.length;
110 | [podspecFile replaceOccurrencesOfString:@"'<"
111 | withString:@"'<#"
112 | options:NSLiteralSearch
113 | range:range];
114 |
115 | range.length = podspecFile.length;
116 | [podspecFile replaceOccurrencesOfString:@">'"
117 | withString:@"#>'"
118 | options:NSLiteralSearch
119 | range:range];
120 |
121 | // Reading dependencies
122 | NSString *podfileContent = [NSString stringWithContentsOfFile:self.podfilePath encoding:NSUTF8StringEncoding error:nil];
123 | NSArray *fileLines = [podfileContent componentsSeparatedByString:@"\n"];
124 |
125 | for (NSString *tmp in fileLines) {
126 | NSString *line = [tmp stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
127 |
128 | if ([line rangeOfString:@"pod "].location == 0) {
129 | [podspecFile appendFormat:@"\n s.dependencies =\t%@", line];
130 | }
131 | }
132 |
133 | [podspecFile appendString:@"\n\nend"];
134 |
135 | // Write Podspec File
136 | [[NSFileManager defaultManager] createFileAtPath:self.podspecPath contents:nil attributes:nil];
137 | [podspecFile writeToFile:self.podspecPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
138 | }
139 |
140 | - (BOOL)containsFileWithName:(NSString*)fileName
141 | {
142 | NSString *filePath = [self.directoryPath stringByAppendingPathComponent:fileName];
143 | return [[NSFileManager defaultManager] fileExistsAtPath:filePath];
144 | }
145 |
146 | @end
147 |
--------------------------------------------------------------------------------
/CocoaControlsPlugin/CocoaControlsPlugin/Helpers/CCPWorkspaceManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // CCPWorkspaceManager.h
3 | //
4 | // Copyright (c) 2013 Delisa Mason. http://delisa.me
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 |
24 | @interface CCPWorkspaceManager : NSObject
25 |
26 | + workspaceForKeyWindow;
27 | + workspaceForWindow:(NSWindow*)window;
28 |
29 | + (NSArray*) installedPodNamesInCurrentWorkspace;
30 |
31 | + (NSString*) currentWorkspaceDirectoryPath;
32 | + (NSString*) directoryPathForWorkspace:workspace;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/CocoaControlsPlugin/CocoaControlsPlugin/Helpers/CCPWorkspaceManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // CCPWorkspaceManager.m
3 | //
4 | // Copyright (c) 2013 Delisa Mason. http://delisa.me
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to
8 | // deal in the Software without restriction, including without limitation the
9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | // sell copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | // IN THE SOFTWARE.
23 |
24 | #import "CCPWorkspaceManager.h"
25 |
26 | #import "CCPProject.h"
27 |
28 | static NSString *PODFILE = @"Podfile";
29 |
30 | @implementation CCPWorkspaceManager
31 |
32 | + (NSArray*)installedPodNamesInCurrentWorkspace
33 | {
34 | NSMutableArray *names = [NSMutableArray new];
35 | id workspace = [self workspaceForKeyWindow];
36 |
37 | id contextManager = [workspace valueForKey:@"_runContextManager"];
38 | for (id scheme in[contextManager valueForKey:@"runContexts"]) {
39 | NSString *schemeName = [scheme valueForKey:@"name"];
40 | if ([schemeName hasPrefix:@"Pods-"]) {
41 | [names addObject:[schemeName stringByReplacingOccurrencesOfString:@"Pods-" withString:@""]];
42 | }
43 | }
44 | return names;
45 | }
46 |
47 | + (NSString*)currentWorkspaceDirectoryPath
48 | {
49 | return [self directoryPathForWorkspace:[self workspaceForKeyWindow]];
50 | }
51 |
52 | + (NSString*)directoryPathForWorkspace:(id)workspace
53 | {
54 | NSString *workspacePath = [[workspace valueForKey:@"representingFilePath"] valueForKey:@"_pathString"];
55 | return [workspacePath stringByDeletingLastPathComponent];
56 | }
57 |
58 | #pragma mark - Private
59 |
60 | + (id)workspaceForKeyWindow
61 | {
62 | return [self workspaceForWindow:[NSApp keyWindow]];
63 | }
64 |
65 | + (id)workspaceForWindow:(NSWindow*)window
66 | {
67 | NSArray *workspaceWindowControllers = [NSClassFromString(@"IDEWorkspaceWindowController") valueForKey:@"workspaceWindowControllers"];
68 |
69 | for (id controller in workspaceWindowControllers) {
70 | if ([[controller valueForKey:@"window"] isEqual:window]) {
71 | return [controller valueForKey:@"_workspace"];
72 | }
73 | }
74 | return nil;
75 | }
76 |
77 | @end
78 |
--------------------------------------------------------------------------------
/CocoaControlsPlugin/CocoaControlsPlugin/RSCCPCocoaControlsPlugin.h:
--------------------------------------------------------------------------------
1 | //
2 | // RSCCPCocoaControlsPlugin.h
3 | // RSCCPCocoaControlsPlugin
4 | //
5 | // Created by R0CKSTAR on 5/8/14.
6 | // Copyright (c) 2014 P.D.Q. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface RSCCPCocoaControlsPlugin : NSObject
12 |
13 | @end
--------------------------------------------------------------------------------
/CocoaControlsPlugin/CocoaControlsPlugin/RSCCPCocoaControlsPlugin.m:
--------------------------------------------------------------------------------
1 | //
2 | // RSCCPCocoaControlsPlugin.m
3 | // RSCCPCocoaControlsPlugin
4 | //
5 | // Created by R0CKSTAR on 5/8/14.
6 | // Copyright (c) 2014 P.D.Q. All rights reserved.
7 | //
8 |
9 | #import "RSCCPCocoaControlsPlugin.h"
10 | #import "CCPProject.h"
11 |
12 | #import
13 |
14 | static RSCCPCocoaControlsPlugin *sharedPlugin;
15 |
16 | @interface RSCCPCocoaControlsPlugin()
17 |
18 | @property (nonatomic) NSBundle *bundle;
19 | @property (nonatomic, weak) NSWindow *keyWindow;
20 |
21 | @end
22 |
23 | @implementation RSCCPCocoaControlsPlugin
24 |
25 | - (void) RSCCP_openCocoaControlsApp {
26 | NSString *applicationBundlePathString = [self.bundle pathForAuxiliaryExecutable:@"CocoaControls.app"];
27 | NSString *executablePathString = [NSString stringWithFormat:@"%@%@", applicationBundlePathString, @"/Contents/MacOS/CocoaControls"];
28 | [NSTask launchedTaskWithLaunchPath:executablePathString arguments:@[]];
29 | }
30 |
31 | - (void) RSCCP_createPodfile {
32 | CCPProject *project = [CCPProject projectForWindow:self.keyWindow];
33 | if (project) {
34 | NSString *podFilePath = project.podfilePath;
35 | if (![project hasPodfile]) {
36 | NSError *error = nil;
37 | [[NSFileManager defaultManager] copyItemAtPath:[self.bundle pathForResource:@"DefaultPodfile" ofType:@""] toPath:podFilePath error:&error];
38 | if (error) {
39 | [[NSAlert alertWithError:error] runModal];
40 | }
41 | }
42 |
43 | NSFileHandle* fileHandle = [NSFileHandle fileHandleForWritingAtPath:podFilePath];
44 | @try {
45 | [fileHandle seekToEndOfFile];
46 | [fileHandle writeData:[[NSString stringWithFormat:@"%@%@", @"\n", [[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString]] dataUsingEncoding:NSUTF8StringEncoding]];
47 | }
48 | @catch (NSException *e) {
49 | NSLog(@"%@", e);
50 | }
51 | [fileHandle closeFile];
52 |
53 | [[[NSApplication sharedApplication] delegate] application:[NSApplication sharedApplication]
54 | openFile:podFilePath];
55 | }
56 | }
57 |
58 | + (void)pluginDidLoad:(NSBundle*)plugin {
59 | static dispatch_once_t onceToken;
60 | NSString *currentApplicationName = [[NSBundle mainBundle] infoDictionary][@"CFBundleName"];
61 | if ([currentApplicationName isEqual:@"Xcode"]) {
62 | dispatch_once(&onceToken, ^{
63 | sharedPlugin = [[self alloc] initWithBundle:plugin];
64 | });
65 | }
66 | }
67 |
68 | static void NotificationReceivedCallback(CFNotificationCenterRef center,
69 | void *observer, CFStringRef name,
70 | const void *object, CFDictionaryRef
71 | userInfo) {
72 | [sharedPlugin RSCCP_createPodfile];
73 | }
74 |
75 | - initWithBundle:(NSBundle*)plugin {
76 | if (self = [super init]) {
77 | // reference to plugin's bundle, for resource acccess
78 | self.bundle = plugin;
79 |
80 | CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, &NotificationReceivedCallback, CFSTR("com.pdq.rscccocoapods"), NULL, CFNotificationSuspensionBehaviorCoalesce);
81 |
82 | __weak __typeof(self)weakself = self;
83 | [[NSOperationQueue mainQueue] addOperationWithBlock:^{
84 | NSMenuItem *menuItem = [[NSApp mainMenu] itemWithTitle:@"View"];
85 | if (menuItem) {
86 | [[menuItem submenu] addItem:[NSMenuItem separatorItem]];
87 |
88 | NSMenuItem *actionMenuItem = [[NSMenuItem alloc] initWithTitle:@"Cocoa Controls"
89 | action:@selector(RSCCP_openCocoaControlsApp)
90 | keyEquivalent:@"c"];
91 | [actionMenuItem setKeyEquivalentModifierMask:NSControlKeyMask];
92 | [actionMenuItem setTarget:weakself];
93 | [[menuItem submenu] addItem:actionMenuItem];
94 | }
95 | }];
96 | }
97 | return self;
98 | }
99 |
100 | - (BOOL) validateMenuItem:(NSMenuItem*)menuItem {
101 | if ([CCPProject projectForKeyWindow]) {
102 | if (!self.keyWindow) {
103 | self.keyWindow = NSApplication.sharedApplication.keyWindow;
104 | }
105 | }
106 | return YES;
107 | }
108 |
109 | @end
110 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2012-2014 P.D.Q.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | CocoaControls.app and Xcode plugin
2 | ===================
3 | [](https://sourcegraph.com/github.com/yeahdongcn/RSImageOptimPlugin)
4 | [](https://sourcegraph.com/github.com/yeahdongcn/RSImageOptimPlugin)
5 |
6 | OS X native application with Xcode plugin for browsing, searching, integrating, cloning controls in [Cocoa Controls](http://cocoacontrols.com/).
7 |
8 | #### Plugin screenshot
9 | 
10 |
11 | #### App screenshot
12 | 
13 |
14 |
15 | ##TODO
16 | * ~~Refresh and load more controls~~
17 | * ~~Integrate Pods~~
18 | * ~~Add refresh button and load more button at the bottom (for those people not using `Magic Mouse` or `Magic Trackpad`)~~
19 |
20 | ##Requirements
21 |
22 | Xcode 5.0+ on OS X 10.9+.
23 |
24 | ##Installation
25 |
26 | #### Build from Source
27 |
28 | * Install pods.
29 | * Build the Xcode project. The plug-in will automatically be installed in `~/Library/Application Support/Developer/Shared/Xcode/Plug-ins`.
30 | * Relaunch Xcode.
31 |
32 | To uninstall, just remove the plugin from `~/Library/Application Support/Developer/Shared/Xcode/Plug-ins` and restart Xcode.
33 |
34 | ## How does it work?
35 |
36 | All the commands are laid at the bottom of the menu `View`.
37 |
38 | * Use the menu `Cocoa Controls` to open `CocoaControls.app` immediately.
39 | * `Click` on the `left image view` to open the image in a new window.
40 | * `Click` on the `pod button` to integrate pod.
41 | * `Click` on the `computer button` to clone the source.
42 | * `Double click` on the `cell view` to open the control in browser.
43 |
44 | ##Thanks
45 |
46 | Thanks [cocoapods-xcode-plugin](https://github.com/kattrali/cocoapods-xcode-plugin) from [Delisa Mason](https://github.com/kattrali) for the source to create/edit podfile.
47 |
48 | ##Credits
49 |
50 | Star icons are taken from [Font Awesome](http://fontawesome.io/) and converted to png using [font-awesome-to-png](https://github.com/odyniec/font-awesome-to-png).
51 |
52 | Filter icon is taken from [Anton Volodin](https://dribbble.com/cuzmich) [Icon](https://dribbble.com/shots/444019-Icons?list=users&offset=0).
53 |
54 | CocoaPods logo is taken from [CocoaPods](http://cocoapods.org/).
55 |
56 | Desktop icon is taken from [Github](https://github.com).
57 |
58 | Mouse scroller helper icons are taken from [Budi Tanrim](https://dribbble.com/buditanrim)'s [budicon tester](https://dribbble.com/shots/1182482-budicon-tester?list=users&offset=21).
59 |
60 | All data is taken from [Cocoa Controls](http://cocoacontrols.com/).
61 |
62 | ##License
63 |
64 | The MIT License (MIT)
65 |
66 | Copyright (c) 2012-2014 P.D.Q.
67 |
68 | Permission is hereby granted, free of charge, to any person obtaining a copy of
69 | this software and associated documentation files (the "Software"), to deal in
70 | the Software without restriction, including without limitation the rights to
71 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
72 | the Software, and to permit persons to whom the Software is furnished to do so,
73 | subject to the following conditions:
74 |
75 | The above copyright notice and this permission notice shall be included in all
76 | copies or substantial portions of the Software.
77 |
78 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
79 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
80 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
81 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
82 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
83 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
84 |
85 |
--------------------------------------------------------------------------------
/app_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/app_screenshot.png
--------------------------------------------------------------------------------
/plugin_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/plugin_screenshot.png
--------------------------------------------------------------------------------