├── .gitignore
├── .travis.yml
├── CHANGES.md
├── Gemfile
├── InterfaCSS Tests
├── ISSSelectorTests.m
├── ISSStyleSheetParserTests.m
├── InterfaCSS Tests-Info.plist
├── InterfaCSS Tests-Prefix.pch
├── InterfaCSSTests.m
├── TestData
│ ├── interfaCSSTests-variables.css
│ ├── interfaCSSTests.css
│ ├── scopedStyles.css
│ ├── styleSheetPropertyValues.css
│ ├── styleSheetStructure.css
│ ├── styleSheetWithBadData.css
│ └── viewDefinitionTest.xml
└── en.lproj
│ └── InfoPlist.strings
├── InterfaCSS.podspec
├── InterfaCSS.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcshareddata
│ └── xcschemes
│ └── UnitTests.xcscheme
├── InterfaCSS
├── InterfaCSS-Prefix.pch
├── InterfaCSS.h
├── InterfaCSS.m
├── Model
│ ├── ISSLayout.h
│ ├── ISSLayout.m
│ ├── ISSLazyValue.h
│ ├── ISSLazyValue.m
│ ├── ISSNestedElementSelector.h
│ ├── ISSNestedElementSelector.m
│ ├── ISSPointValue.h
│ ├── ISSPointValue.m
│ ├── ISSPropertyDeclaration.h
│ ├── ISSPropertyDeclaration.m
│ ├── ISSPropertyDeclarations.h
│ ├── ISSPropertyDeclarations.m
│ ├── ISSPropertyDefinition.h
│ ├── ISSPropertyDefinition.m
│ ├── ISSPropertyRegistry.h
│ ├── ISSPropertyRegistry.m
│ ├── ISSPseudoClass.h
│ ├── ISSPseudoClass.m
│ ├── ISSRectValue.h
│ ├── ISSRectValue.m
│ ├── ISSRemoteFont.h
│ ├── ISSRemoteFont.m
│ ├── ISSSelector.h
│ ├── ISSSelector.m
│ ├── ISSSelectorChain.h
│ ├── ISSSelectorChain.m
│ ├── ISSStyleSheet.h
│ ├── ISSStyleSheet.m
│ ├── ISSStylingContext.h
│ ├── ISSStylingContext.m
│ ├── ISSUIElementDetails.h
│ ├── ISSUIElementDetails.m
│ ├── ISSUpdatableValue.h
│ ├── ISSUpdatableValue.m
│ ├── ISSViewPrototype.h
│ └── ISSViewPrototype.m
├── Parser
│ ├── ISSDefaultStyleSheetParser.h
│ ├── ISSDefaultStyleSheetParser.m
│ ├── ISSParser+CSS.h
│ ├── ISSParser+CSS.m
│ ├── ISSParser.h
│ ├── ISSParser.m
│ ├── ISSStyleSheetParser.h
│ ├── ISSViewHierarchyParser.h
│ └── ISSViewHierarchyParser.m
├── UI
│ ├── ISSLayoutContextView.h
│ ├── ISSLayoutContextView.m
│ ├── ISSRootView.h
│ ├── ISSRootView.m
│ ├── ISSViewBuilder.h
│ ├── ISSViewBuilder.m
│ ├── UICollectionView+InterfaCSS.h
│ ├── UICollectionView+InterfaCSS.m
│ ├── UITableView+InterfaCSS.h
│ ├── UITableView+InterfaCSS.m
│ ├── UIView+ISSPrototypeReusableView.h
│ ├── UIView+ISSPrototypeReusableView.m
│ ├── UIView+InterfaCSS.h
│ └── UIView+InterfaCSS.m
└── Util
│ ├── ISSDateUtils.h
│ ├── ISSDateUtils.m
│ ├── ISSDownloadableResource.h
│ ├── ISSDownloadableResource.m
│ ├── ISSRefreshableResource.h
│ ├── ISSRefreshableResource.m
│ ├── ISSRuntimeIntrospectionUtils.h
│ ├── ISSRuntimeIntrospectionUtils.m
│ ├── NSArray+ISSAdditions.h
│ ├── NSArray+ISSAdditions.m
│ ├── NSAttributedString+ISSAdditions.h
│ ├── NSAttributedString+ISSAdditions.m
│ ├── NSDictionary+ISSDictionaryAdditions.h
│ ├── NSDictionary+ISSDictionaryAdditions.m
│ ├── NSMutableArray+ISSAdditions.h
│ ├── NSMutableArray+ISSAdditions.m
│ ├── NSObject+ISSLogSupport.h
│ ├── NSObject+ISSLogSupport.m
│ ├── NSString+ISSStringAdditions.h
│ ├── NSString+ISSStringAdditions.m
│ ├── UIColor+ISSColorAdditions.h
│ ├── UIColor+ISSColorAdditions.m
│ ├── UIDevice+ISSAdditions.h
│ └── UIDevice+ISSAdditions.m
├── LICENSE
├── README.markdown
├── Resources
└── InterfaCSS-title-logo.png
└── Samples
├── HelloISSLayout
├── HelloISSLayout.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
├── HelloISSLayout.xcworkspace
│ └── contents.xcworkspacedata
├── ISSLayout
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ └── LaunchScreen.xib
│ ├── Images.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Info.plist
│ ├── ViewController.swift
│ ├── layout.css
│ ├── layout.xml
│ └── styles.css
└── Podfile
└── SimpleSample
├── Podfile
├── SimpleSample.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ └── contents.xcworkspacedata
└── SimpleSample
├── AppDelegate.h
├── AppDelegate.m
├── Default-568h@2x.png
├── IBViewController.css
├── IBViewController.h
├── IBViewController.m
├── IBViewController.xib
├── PrototypeExampleViewController.h
├── PrototypeExampleViewController.m
├── SimpleSample-Info.plist
├── SimpleSample-Prefix.pch
├── SimpleSampleViewController.h
├── SimpleSampleViewController.m
├── constants.css
├── en.lproj
└── InfoPlist.strings
├── image.png
├── main.css
├── main.m
├── prototypeExample.css
└── views.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | **/xcuserdata/**
2 | *.xcuserdatad
3 | *.xcuserstate
4 | *.xcbkptlist
5 | *.pbxuser
6 | *.xcbaseline
7 | *.xccheckout
8 | *.hmap
9 | *.ipa
10 | build/
11 | Pods
12 | Podfile.lock
13 | InterfaCSS.xcworkspace
14 | Samples/*/*.xcworkspace
15 | .idea
16 | notes
17 | .DS_Store
18 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | osx_image: xcode9.2
2 | language: objective-c
3 |
4 | before_install:
5 | - gem install xcpretty --no-rdoc --no-ri --no-document --quiet
6 | - export LANG=en_US.UTF-8
7 |
8 | script: xcodebuild clean test -project InterfaCSS.xcodeproj -scheme UnitTests -destination 'platform=iOS Simulator,name=iPhone 8' | xcpretty -c && exit ${PIPESTATUS[0]}
9 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | #source 'https://rubygems.org'
2 |
3 | #gem 'cocoapods', :git => 'https://github.com/CocoaPods/CocoaPods.git', :branch => 'master'
4 | #gem 'cocoapods-core', :git => 'https://github.com/CocoaPods/Core.git', :branch => 'master'
5 | #gem 'xcodeproj', :git => 'https://github.com/CocoaPods/Xcodeproj.git', :branch => 'master'
6 |
7 | #gem 'cocoapods-keys'
8 | #gem 'cocoapods-deintegrate'
9 |
--------------------------------------------------------------------------------
/InterfaCSS Tests/InterfaCSS Tests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/InterfaCSS Tests/InterfaCSS Tests-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 |
11 | #import "NSString+ISSStringAdditions.h"
12 | #endif
13 |
14 | #define ISSAssertEqualFloats(x, y, ...) XCTAssertTrue(ISS_EQUAL_FLT(x, y), __VA_ARGS__)
15 |
--------------------------------------------------------------------------------
/InterfaCSS Tests/TestData/interfaCSSTests-variables.css:
--------------------------------------------------------------------------------
1 | .reuseTest {
2 | alpha: @globalVariableTest;
3 | }
4 |
--------------------------------------------------------------------------------
/InterfaCSS Tests/TestData/interfaCSSTests.css:
--------------------------------------------------------------------------------
1 | @globalVariableTest: 0.33;
2 | @globalVariableTest2: red;
3 |
4 | // Test caching using enabled/disabled pseudo class
5 | .class1 uilabel:enabled {
6 | alpha: 0.25;
7 | }
8 |
9 | .class1 uilabel:disabled {
10 | alpha: 0.75;
11 | }
12 |
13 | .class1 uicontrol:enabled uilabel {
14 | alpha: 0.33;
15 | }
16 |
17 | .class1 uicontrol:disabled uilabel {
18 | alpha: 0.66;
19 | }
20 |
21 | .class2 {
22 | showsTouchWhenHighlighted: YES;
23 | alpha: 0.99;
24 | }
25 |
26 | .class10 {
27 | alpha: 0.1;
28 | }
29 |
30 | .classTop {
31 | .classMiddle {
32 | .class12 {
33 | alpha: 0.3;
34 | }
35 |
36 | .class11 {
37 | alpha: 0.2;
38 | }
39 |
40 | .abc123 {
41 | alpha: 0.31;
42 | }
43 |
44 | .x123abc {
45 | alpha: 0.32;
46 | }
47 |
48 | .zyxvyt {
49 | alpha: 0.33;
50 | }
51 |
52 | .abc123abc {
53 | alpha: 0.34;
54 | }
55 |
56 | .x123abc123 {
57 | alpha: 0.35;
58 | }
59 | }
60 | }
61 |
62 | .class13 {
63 | alpha: 0.4;
64 | }
65 |
66 | .overwriteTest {
67 | alpha: 0.5;
68 | titleLabel.alpha: 0.25;
69 | }
70 |
71 | .attributedTextTest {
72 | alpha: 0.5;
73 | font: HelveticaNeue-Bold 10;
74 | textColor: #998877;
75 | }
76 |
77 | UIView.disabledStylingTest {
78 | alpha: 0.5;
79 |
80 | UILabel {
81 | alpha: 0.5;
82 | }
83 | }
84 |
85 | .cascadingStylePropertyOverrideWithDefault1 {
86 | alpha: 0.666;
87 | }
88 |
89 | .cascadingStylePropertyOverrideWithDefault2 {
90 | alpha: current;
91 | }
92 |
93 | .testDisableProperty {
94 | alpha: 0.5;
95 | }
96 |
97 | .labelAttributedTextTest {
98 | attributedText: "text" (font: HelveticaNeue-Medium 12, color: blue);
99 | }
100 |
101 | .buttonAttributedTitleTest {
102 | attributedTitle: "text" (font: HelveticaNeue-Medium 12, color: blue);
103 | attributedTitle(highlighted): "text" (font: HelveticaNeue-Medium 12, color: red);
104 | }
105 |
106 | .shadowTest1 {
107 | layer.shadowColor: red;
108 | shadowOffset: size(1,2);
109 | shadowOpacity: 0.5;
110 | shadowRadius: 10;
111 | }
112 |
113 | .shadowTest2 {
114 | shadowColor: red;
115 | shadowOffset: size(1,2);
116 | }
117 |
118 | .sizeToFitTest1 {
119 | frame: sizeToFit().top(10).left(20);
120 | }
121 |
122 | .sizeToFitTest2 {
123 | frame: sizeToFit(100%, 100%).bottom(10).right(20);
124 | }
125 |
126 | .sizeToFitTest3 {
127 | frame: sizeToFit(5, 5);
128 | }
129 |
130 | .centeredRectTest1 {
131 | frame: size(auto, auto).insets(auto, auto, auto, auto); // Centering with auto width/height
132 | }
133 |
134 | .centeredRectTest2 {
135 | frame: size(100, 100).insets(auto, auto, auto, auto); // Centering with fixed width/height
136 | }
137 |
138 | .centeredRectTest3 {
139 | frame: size(50%, 50%).left(auto).right(auto).top(auto).bottom(auto); // Centering with relative width/height
140 | }
141 |
142 | .centeredRectTest4 {
143 | frame: size(50%, 50%).left(auto).right(auto).top(42); // Only horizontal centering
144 | }
145 |
146 | .centeredRectTest5 {
147 | frame: size(50%, 50%).top(auto).bottom(auto).left(42); // Only vertical centering
148 | }
149 |
150 | .centeredRectTest6 {
151 | frame: size(auto, auto).left(auto).right(50).top(auto).bottom(50); // Only single auto inset per axix
152 | }
153 |
154 | .centeredRectTest7 {
155 | frame: size(auto, auto).left(50).right(auto).top(50).bottom(auto); // Only single auto inset per axix
156 | }
157 |
158 | .collectionViewTest {
159 | minimumLineSpacing: 42;
160 | }
161 |
162 |
163 | #layoutElement1 {
164 | layout: size(100, 100), left(parent + 10), top(parent + 10);
165 | }
166 | #layoutElement2 {
167 | layout: size(100, 100), left(layoutElement1), top(layoutElement1);
168 | }
169 | #layoutElement3 {
170 | layout: size(100, 100), left(layoutElement4), top(layoutElement1);
171 | }
172 | #layoutElement4 {
173 | layout: size(100, 100), left(layoutElement3), top(layoutElement1);
174 | }
175 | #layoutElement5 {
176 | layout: left(parent.left + 100), right(parent.right - 100), top(parent.top + 50), bottom(parent.bottom - 50);
177 | }
178 |
179 |
180 | UIView > .typeSelectorAndPrefixedPropertyTest {
181 | UILabel {
182 | font: GillSans 1;
183 | titleLabel.alpha: 1;
184 | }
185 |
186 | UIButton {
187 | titleLabel.font: GillSans 2;
188 | }
189 |
190 | .someOtherSelector, UIButton.testNestedProperty, .anotherSelector {
191 | titleLabel.alpha: 0.5;
192 | }
193 | }
194 |
195 | UIBarButtonItem.prefixedPropertyOnNonUIViewClass {
196 | customView.alpha: 0.5;
197 | }
198 |
199 | UITableViewCell.nestedPropertyNotDirectChildView {
200 | textLabel.enabled: NO;
201 | detailTextLabel.alpha: 0.5;
202 | }
203 |
204 | .textInputTraits {
205 | keyboardType: numberPad;
206 | returnKeyType: done;
207 | }
208 |
209 | UIView .testSpecificity2 {
210 | alpha: 0.75;
211 | }
212 |
213 | #someElementId .testSpecificity1 {
214 | alpha: 0.5;
215 | }
216 |
217 | .testSpecificity1 {
218 | alpha: 0.25;
219 | }
220 |
221 |
222 | .overridePropertyDefinitionStyle {
223 | text: "Monday";
224 | }
225 |
226 | UILabel.scopeTest {
227 | alpha: 1.0;
228 | }
229 |
230 |
231 | UIViewController UIView {
232 | alpha: 0.1;
233 | }
234 |
235 | UIViewController > UIView {
236 | alpha: 0.25;
237 | }
238 |
239 | UIViewController > #rootView {
240 | alpha: 0.5;
241 | }
242 |
243 | CustomViewController > UIView {
244 | alpha: 0.75;
245 | }
246 |
247 |
248 | .parentSwitcher_childElement {
249 | alpha: 0.5;
250 | }
251 |
252 | .parentSwitcher_parentElement {
253 | .parentSwitcher_childElement {
254 | alpha: 0.75;
255 | }
256 | }
257 |
258 |
259 | #elementIdAndClassTest {
260 | alpha: 0.5;
261 | }
262 |
263 | #elementIdAndClassTest.someClass {
264 | alpha: 0.75;
265 | }
266 |
267 |
268 | .styleInheritance_baseClass {
269 | alpha: 0.5;
270 | }
271 |
272 | .styleInheritance_subClass {
273 | @extend .styleInheritance_baseClass;
274 | contentScaleFactor: 10;
275 | }
276 |
--------------------------------------------------------------------------------
/InterfaCSS Tests/TestData/scopedStyles.css:
--------------------------------------------------------------------------------
1 |
2 | UILabel.scopeTest {
3 | alpha: 0.5;
4 | }
5 |
--------------------------------------------------------------------------------
/InterfaCSS Tests/TestData/styleSheetPropertyValues.css:
--------------------------------------------------------------------------------
1 |
2 | @attrFont1: HelveticaNeue-Medium 14;
3 | @attrColor1 : lighten(#ffffff, 0%);
4 | @attrFont2: HelveticaNeue-Medium 15;
5 | @attrColor2: rgb(0,0,0);
6 | @numericalConstant: 42;
7 | @mathExpressionConstant: 10 ** (3 - 1);
8 |
9 | @fontNameVariable : "GillSans";
10 | @fontSizeVariable: 42;
11 | @nestedVariable : @fontNameVariable @fontSizeVariable;
12 |
13 | .simple {
14 | alpha : 0.33;
15 | layer.cornerRadius: 5;
16 | autoresizingMask: width height left right top bottom;
17 | clipsToBounds: YES;
18 | contentMode: bottomRight;
19 | text: "Text's:";
20 | title: Title;
21 | prompt: 'Prompt';
22 | searchTextPositionAdjustment: offset(1, 2);
23 | contentSize: size(3, 4);
24 | contentInset: insets(10, 20, 30, 40);
25 | center: point(5, 6);
26 | frame: rect(1,2,3,4);
27 | bounds: size(10,20);
28 | color: rgb(128, 128, 128);
29 | tintColor: #ffffff;
30 | titleColor(selectedHighlighted) : blue;
31 | textColor : rgba(64, 64, 64, 0.5);
32 | shadowColor: red;
33 | transform: rotate(10) scale(20,30) translate(40,50);
34 | attributedText: "text" (font: HelveticaNeue-Medium 12, backgroundColor: rgb(0,0,255), color: darken(#000000, 0%), baselineOffset: 10, strokeColor: yellow, strokeWidth: 1.0);
35 | attributedTitle: "title1 " (font: @attrFont1, foregroundColor: @attrColor1), "title2" (font: @attrFont2, foregroundColor: @attrColor2, underlineStyle: single dash);
36 | }
37 |
38 | .hexColorsRGBA {
39 | color: #4080B000;
40 | titleColor: #00FF80FF;
41 | backgroundColor: #00000080;
42 | tintColor: #80000000;
43 | textColor: #800000FF;
44 | shadowColor: #80000080;
45 | }
46 |
47 | .hexColorsCompact {
48 | color: #000;
49 | titleColor: #fff;
50 | backgroundColor: #0008;
51 | tintColor: #888;
52 | textColor: #8888;
53 | shadowColor: #8880;
54 | }
55 |
56 | .localizedStrings {
57 | text: L("Text");
58 | title: localized('Title');
59 | attributedText: L("text1") (font: HelveticaNeue-Medium 12) L("-text2") (font: HelveticaNeue-Medium 12);
60 | }
61 |
62 | .stringsWithEscapes {
63 | text: "dr \"evil\" rules";
64 | attributedText: "dr \"evil\" rules" (font: HelveticaNeue-Medium 12) ", and so does austin \"danger\" powers" (font: HelveticaNeue-Medium 12);
65 | }
66 |
67 | .prefixes {
68 | cornerRadius: 5;
69 | layer.borderWidth: 10;
70 | imageView.alpha: 0.42;
71 | contentView.alpha: 0.42;
72 | backgroundView.alpha: 0.42;
73 | selectedBackgroundView.alpha: 0.42;
74 | multipleSelectionBackgroundView.alpha: 0.42;
75 | titleLabel.alpha: 0.42;
76 | textLabel.alpha: 0.42;
77 | detailTextLabel.alpha: 0.42;
78 | inputView.alpha: 0.42;
79 | inputAccessoryView.alpha: 0.42;
80 | tableHeaderView.alpha: 0.42;
81 | tableFooterView.alpha: 0.42;
82 | }
83 |
84 | .point1 {
85 | center: parent(50, -50);
86 | }
87 |
88 | .point2 {
89 | center: window(50, -50);
90 | }
91 |
92 |
93 | .rect1 { // Parent insets
94 | frame: parent(10, 10); // dx/dy inset
95 | bounds: parent(10, 20, 30, 40); // top, left, bottom, right inset
96 | }
97 |
98 | .rect2 { // Window insets
99 | frame: window(10, 10); // dx/dy inset
100 | bounds: window(10, 20, 30, 40); // top, left, bottom, right inset
101 | }
102 |
103 | .rect3 { // Parent relative size
104 | frame: size(10%, 20%).left(10).top(20);
105 | bounds: size(30%, 40%).right(30).bottom(40);
106 | }
107 |
108 | .rect4 { // Automatic sizes with parent relative insets/positioning
109 | frame: size(auto, auto).left(10%).top(20%);
110 | bounds: left(50%).right(5).top(0);
111 | }
112 |
113 | .rect5 { // Automatic sizes with parent relative insets/positioning
114 | frame: size(auto, auto).insets(10%, 20%, 30%, 40%);
115 | bounds: size(auto, auto).top(10%).left(20%).bottom(30%).right(40%);
116 | }
117 |
118 |
119 | @font1: HelveticaNeue-Medium 14;
120 | .font1 {
121 | font: @font1;
122 | }
123 | .font2 {
124 | font: bigger(@font1, 1);
125 | }
126 | .font3 {
127 | font: smaller(@font1, 1);
128 | }
129 | .font4 {
130 | font: fontWithSize(@font1, 10);
131 | }
132 | .font5 {
133 | font: HelveticaNeue-Medium 5;
134 | }
135 | .font6 {
136 | font: "Times New Roman" 5;
137 | }
138 | .font7 {
139 | font: 'Times New Roman' 5;
140 | }
141 | .font8 {
142 | font: 42;
143 | }
144 | .font9 {
145 | font: system 42;
146 | }
147 | .font10 {
148 | font: systemItalic 42;
149 | }
150 | .font11 {
151 | font: systemBold 42;
152 | }
153 |
154 | .image1 {
155 | image: image.png;
156 | backgroundImage: "image.png";
157 | shadowImage: 'image.png';
158 | progressImage: image(image.png);
159 | trackImage: image("image.png");
160 | highlightedImage: image('image.png');
161 | onImage: image(image.png, 1, 2);
162 | offImage: image(image.png, 1, 2, 3, 4);
163 | }
164 |
165 | .colorFunctions {
166 | color: lighten(rgb(17, 34, 51), 50%);
167 | titleColor: darken(#112233, 50%);
168 | textColor: saturate(rgb(17, 34, 51), 50%);
169 | tintColor: desaturate(#112233, 50%);
170 | shadowColor: fadein(rgb(17, 34, 51), 50%);
171 | sectionIndexColor: fadeout(#112233, 50%);
172 | separatorColor: saturate(fadeout(rgb(17, 34, 51), 50%), 50%);
173 | }
174 |
175 | .imageColorFunctions {
176 | image: lighten(#112233, 50%);
177 | backgroundImage: saturate(fadeout(#112233, 50%), 50%);
178 | }
179 |
180 | .fullEnumNames {
181 | autoresizingMask: UIViewAutoresizingFlexibleWidth;
182 | lineBreakMode: NSLineBreakByWordWrapping;
183 | titleColor(UIControlStateSelected): red;
184 | }
185 |
186 |
187 | .numericExpressions {
188 | hidden: 2 > 1;
189 | alpha: 2 * 3 - (2*2.5 + 0.5);
190 | cornerRadius: @numericalConstant + @mathExpressionConstant;
191 | contentSize: size(@numericalConstant, @mathExpressionConstant);
192 | }
193 |
194 |
195 | .layoutParentRelative1 {
196 | layout: size(100, 100), center(parent, parent.centerY - 100); // Using implicit centerX attribute...
197 | }
198 | .layoutParentRelative2 {
199 | layout: size(2 * parent.width, parent.height + 100), left(100), top(100);
200 | }
201 |
202 | .layoutElementRelative1 {
203 | layout: size(100, 100), right(elementFoo), bottom(elementFoo.top - 100); // Using implicit left attribute...
204 | }
205 | .layoutElementRelative2 {
206 | layout: size(elementFoo.width, 2 * elementFoo.height + 100), left(elementFoo.right), top(elementFoo.bottom - 100);
207 | }
208 |
209 | .layoutParentSizeToFit1 {
210 | layout: sizeToFit(100, 100), left(parent.right), top(parent.bottom + 100);
211 | }
212 | .layoutParentSizeToFit2 {
213 | layout: sizeToFit(parent.width * 2, 2 * parent.height + 100), right(3 * parent.left), bottom(guide.bottom);
214 | }
215 |
216 | .layoutImplicitAttributes1 {
217 | layout: size(elementFoo, 2 * elementFoo + 100), center(elementFoo, elementFoo - 100);
218 | }
219 | .layoutImplicitAttributes2 {
220 | layout: size(elementFoo, elementFoo * 2 + 100), topLeft(elementFoo, elementFoo);
221 | }
222 | .layoutImplicitAttributes3 {
223 | layout: size(elementFoo, 2 * elementFoo + 100), topRight(elementFoo, elementFoo);
224 | }
225 | .layoutImplicitAttributes4 {
226 | layout: size(elementFoo, elementFoo * 2 + 100), bottomLeft(elementFoo, elementFoo);
227 | }
228 | .layoutImplicitAttributes5 {
229 | layout: size(elementFoo, 2 * elementFoo + 100), bottomRight(elementFoo, elementFoo);
230 | }
231 |
232 |
233 | .nestedVariableClass {
234 | font: @nestedVariable;
235 | }
236 |
--------------------------------------------------------------------------------
/InterfaCSS Tests/TestData/styleSheetStructure.css:
--------------------------------------------------------------------------------
1 | /* Variables: */
2 | @variable: 0.666;
3 |
4 | // Type selector
5 | uilabel {
6 | alpha: @variable;
7 | }
8 |
9 | // Type+class selector
10 | uilabel.class1 {
11 | alpha: 0.666;
12 | }
13 |
14 | // Type+elementId+class selector
15 | uilabel#identity.class1 {
16 | alpha: 0.666;
17 | }
18 |
19 | uilabel#identity.class1.class2 {
20 | alpha: 0.666;
21 | }
22 |
23 | // elementId+class selector
24 | #identity.class1 {
25 | alpha: 0.666;
26 | }
27 |
28 | // Class selector
29 | .class1 {
30 | alpha: 0.666;
31 | }
32 |
33 | // Multi-class selector
34 | .class1.class2 {
35 | alpha: 0.666;
36 | }
37 |
38 | // Descendant selector chain
39 | uiview .class1 .class2 {
40 | alpha: 0.666;
41 | }
42 |
43 | uiview .class1.class2 {
44 | alpha: 0.666;
45 | }
46 |
47 | // Child/sibling selector chain
48 | uiview > .class1 + .class2 ~ .class3 {
49 | alpha: 0.666;
50 | }
51 |
52 | // Multiple selector (chains)
53 | uilabel, uilabel.class1, .class1, uiview .class1 .class2 {
54 | alpha: 0.666;
55 | }
56 |
57 | uilabel, uilabel.class1.class2, .class1, uiview .class1.class2 .class3 {
58 | alpha: 0.666;
59 | }
60 |
61 | // Nested declarations
62 | uiview {
63 | alpha: 0.666;
64 | .classN1 {
65 | alpha: 0.666;
66 | .classN2 {
67 | alpha: 0.666;
68 | }
69 | }
70 | }
71 |
72 | // Pseudo classes
73 | uiview:onlychild {
74 | alpha: 0.666;
75 | }
76 |
77 | uiview:minOSVersion(8.4) {
78 | alpha: 0.666;
79 | }
80 |
81 | uiview#identifier.class1:onlychild {
82 | alpha: 0.666;
83 | }
84 |
85 | uiview:nthchild(2n+1) {
86 | alpha: 0.666;
87 | }
88 |
89 | uiview uilabel:first-of-type {
90 | alpha: 0.666;
91 | }
92 |
93 | uiview.classx {
94 | alpha: 0.666;
95 |
96 | uilabel:last-of-type {
97 | alpha: 0.666;
98 | }
99 | }
100 |
101 | uiview:pad:landscape {
102 | alpha: 0.666;
103 | }
104 |
105 | uiview:portrait:phone {
106 | alpha: 0.666;
107 | }
108 |
109 | // Wildcard selectors
110 | * uiview {
111 | alpha: 0.666;
112 | }
113 |
114 | * uiview * {
115 | alpha: 0.666;
116 | }
117 |
118 | uiview * {
119 | alpha: 0.666;
120 | }
121 |
122 | uiview * uiview {
123 | alpha: 0.666;
124 | }
125 |
--------------------------------------------------------------------------------
/InterfaCSS Tests/TestData/styleSheetWithBadData.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | bad bad bad
4 |
5 |
6 | // Style 1:
7 | .style1 {
8 | alpha: 1;
9 | bad bad bad
10 | }
11 |
12 |
13 | bad bad bad
14 |
15 |
16 | // Style 2:
17 | .style2 {
18 | clipsToBounds: YES;
19 | bad bad bad
20 | }
21 |
--------------------------------------------------------------------------------
/InterfaCSS Tests/TestData/viewDefinitionTest.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/InterfaCSS Tests/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/InterfaCSS.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'InterfaCSS'
3 | s.version = '1.5.5'
4 | s.summary = 'The CSS-inspired styling and layout framework for iOS'
5 | s.homepage = 'https://github.com/tolo/InterfaCSS'
6 | s.license = 'MIT'
7 | s.authors = { 'Tobias Löfstrand' => 'tobias@leafnode.se' }
8 | s.source = { :git => 'https://github.com/tolo/InterfaCSS.git', :tag => s.version.to_s }
9 | s.ios.deployment_target = '7.0'
10 | if defined?(s.tvos)
11 | s.tvos.deployment_target = '9.0'
12 | end
13 | s.source_files = 'InterfaCSS/**/*.{h,m}'
14 | s.requires_arc = true
15 | s.frameworks = 'Foundation', 'UIKit', 'CoreGraphics', 'QuartzCore'
16 |
17 | end
18 |
--------------------------------------------------------------------------------
/InterfaCSS.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/InterfaCSS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/InterfaCSS.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
55 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
74 |
76 |
77 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/InterfaCSS/InterfaCSS-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header for all source files of the 'InterfaCSS' target in the 'InterfaCSS' project
3 | //
4 |
5 | #ifdef __OBJC__
6 | #import
7 | #import
8 | #endif
9 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSLayout.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSLayout.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSRectValue.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | extern NSString* const ISSLayoutAttributeRelationParent;
15 | extern NSString* const ISSLayoutAttributeRelationLayoutGuide;
16 |
17 |
18 | /**
19 | * ISSLayoutAttribute
20 | */
21 | typedef NS_ENUM(NSInteger, ISSLayoutAttribute) {
22 | ISSLayoutAttributeDefault = 0,
23 |
24 | ISSLayoutAttributeWidth = 0x11,
25 | ISSLayoutAttributeRight = 0x12,
26 | ISSLayoutAttributeRightMargin = 0x52,
27 | ISSLayoutAttributeLeft = 0x14,
28 | ISSLayoutAttributeLeftMargin = 0x54,
29 | ISSLayoutAttributeCenterX = 0x16,
30 | // ISSLayoutAttributeBaseline // TODO: Support for this will possibly be added in the future.
31 |
32 | ISSLayoutAttributeHeight = 0x31,
33 | ISSLayoutAttributeTop = 0x32,
34 | ISSLayoutAttributeTopMargin = 0x62,
35 | ISSLayoutAttributeBottom = 0x34,
36 | ISSLayoutAttributeBottomMargin = 0x64,
37 | ISSLayoutAttributeCenterY = 0x36
38 | };
39 |
40 | typedef NS_ENUM(NSInteger, ISSLayoutGuide) {
41 | ISSLayoutGuideTop = ISSLayoutAttributeTop,
42 | ISSLayoutGuideBottom = ISSLayoutAttributeBottom,
43 | ISSLayoutGuideCenter = ISSLayoutAttributeCenterY, // Position with equal distance to top and bottom layout guide
44 | };
45 |
46 | typedef NS_ENUM(NSInteger, ISSLayoutType) {
47 | ISSLayoutTypeStandard,
48 | ISSLayoutTypeSizeToFit,
49 | };
50 |
51 |
52 | /**
53 | * ISSLayoutAttributeValue
54 | */
55 | @interface ISSLayoutAttributeValue : NSObject
56 |
57 | @property (nonatomic, readonly) ISSLayoutAttribute targetAttribute;
58 |
59 | @property (nonatomic, nullable, strong, readonly) NSString* relativeElementId;
60 | @property (nonatomic, readonly) ISSLayoutAttribute relativeAttribute;
61 |
62 | @property (nonatomic) CGFloat multiplier;
63 | @property (nonatomic) CGFloat constant;
64 |
65 | @property (nonatomic, readonly) BOOL isConstantValue;
66 | @property (nonatomic, readonly) BOOL isParentRelativeValue;
67 | @property (nonatomic, readonly) BOOL isLayoutGuideValue;
68 | @property (nonatomic, readonly) BOOL isRelativeToLayoutMargin;
69 |
70 | + (ISSLayoutAttributeValue*) constantValue:(CGFloat)constant;
71 | + (ISSLayoutAttributeValue*) valueRelativeToAttributeInParent:(ISSLayoutAttribute)attribute multiplier:(CGFloat)multiplier constant:(CGFloat)constant;
72 | + (ISSLayoutAttributeValue*) valueRelativeToAttribute:(ISSLayoutAttribute)attribute inElement:(NSString*)elementId multiplier:(CGFloat)multiplier constant:(CGFloat)constant;
73 | + (ISSLayoutAttributeValue*) valueRelativeToLayoutGuide:(ISSLayoutGuide)guide multiplier:(CGFloat)multiplier constant:(CGFloat)constant;
74 |
75 | @end
76 |
77 |
78 | /**
79 | * ISSLayout
80 | */
81 | @interface ISSLayout : NSObject
82 |
83 | @property (nonatomic) ISSLayoutType layoutType;
84 |
85 | + (NSArray*) attributeNames;
86 | + (NSString*) attributeToString:(ISSLayoutAttribute)attribute;
87 | + (ISSLayoutAttribute) attributeFromString:(NSString*)string;
88 | + (ISSLayoutGuide) layoutGuideFromString:(NSString*)string;
89 |
90 | @property (nonatomic, readonly) NSArray* layoutAttributeValues;
91 | - (ISSLayoutAttributeValue*) valueForLayoutAttribute:(ISSLayoutAttribute)attribute;
92 |
93 | - (void) setLayoutAttributeValue:(ISSLayoutAttributeValue*)attributeValue forTargetAttribute:(ISSLayoutAttribute)targetAttribute;
94 | - (void) setLayoutAttributeValue:(ISSLayoutAttributeValue*)value;
95 |
96 | - (void) removeLayoutAttributeValue:(ISSLayoutAttributeValue*)attributeValue;
97 | - (void) removeValueForLayoutAttribute:(ISSLayoutAttribute)attribute;
98 | - (void) removeValuesForLayoutAttributes:(NSArray*)attributes;
99 |
100 | - (BOOL) resolveRectForView:(UIView*)view withResolvedElements:(NSDictionary*)elementMappings andLayoutGuideInsets:(UIEdgeInsets)layoutGuideInsets;
101 |
102 | @end
103 |
104 |
105 | NS_ASSUME_NONNULL_END
106 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSLazyValue.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSLazyValue.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | typedef id _Nullable (^ISSLazyValueBlock)(id _Nullable parameter);
15 |
16 |
17 | @interface ISSLazyValue : NSObject
18 |
19 | + (instancetype) lazyValueWithBlock:(ISSLazyValueBlock)block;
20 | - (instancetype) initWithLazyEvaluationBlock:(ISSLazyValueBlock)block;
21 |
22 | - (nullable id) evaluate;
23 | - (nullable id) evaluateWithParameter:(nullable id)parameter;
24 |
25 | @end
26 |
27 |
28 | NS_ASSUME_NONNULL_END
29 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSLazyValue.m:
--------------------------------------------------------------------------------
1 | //
2 | // ISSLazyValue.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSLazyValue.h"
10 |
11 | @interface ISSLazyValue ()
12 | @property (nonatomic, copy) ISSLazyValueBlock lazyValueBlock;
13 | @end
14 |
15 | @implementation ISSLazyValue
16 |
17 | + (instancetype) lazyValueWithBlock:(ISSLazyValueBlock)block {
18 | return [[(id)self.class alloc] initWithLazyEvaluationBlock:block];
19 | }
20 |
21 | - (instancetype) initWithLazyEvaluationBlock:(ISSLazyValueBlock)block {
22 | self = [super init];
23 | if ( self ) {
24 | self.lazyValueBlock = block;
25 | }
26 | return self;
27 | }
28 |
29 | - (id) evaluate {
30 | return self.lazyValueBlock(nil);
31 | }
32 |
33 | - (id) evaluateWithParameter:(id)parameter {
34 | return self.lazyValueBlock(parameter);
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSNestedElementSelector.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSNestedElementSelector.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSSelector.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | @interface ISSNestedElementSelector : ISSSelector
15 |
16 | + (instancetype) selectorWithNestedElementKeyPath:(NSString*)nestedElementKeyPath;
17 |
18 | @property (nonatomic, strong, readonly) NSString* nestedElementKeyPath;
19 |
20 | @end
21 |
22 |
23 | NS_ASSUME_NONNULL_END
24 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSNestedElementSelector.m:
--------------------------------------------------------------------------------
1 | //
2 | // ISSNestedElementSelector.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSNestedElementSelector.h"
10 |
11 | #import "ISSUIElementDetails.h"
12 | #import "ISSRuntimeIntrospectionUtils.h"
13 |
14 |
15 | @implementation ISSNestedElementSelector
16 |
17 | + (instancetype) selectorWithNestedElementKeyPath:(NSString*)nestedElementKeyPath {
18 | // We reuse/repurpose the elementId field of ISSSelector, with the rationale that identifying a sub element using a key path is really a specialized version of identifying an element using an id
19 | return [self selectorWithType:nil elementId:nestedElementKeyPath pseudoClasses:nil];
20 | }
21 |
22 | - (NSString*) nestedElementKeyPath {
23 | return self.elementId;
24 | }
25 |
26 | - (BOOL) matchesElement:(ISSUIElementDetails*)elementDetails stylingContext:(ISSStylingContext*)stylingContext {
27 | ISSUIElementDetails* parentDetails = [[InterfaCSS sharedInstance] detailsForUIElement:elementDetails.ownerElement];
28 | NSString* validParentKeyPath = parentDetails.validNestedElements[self.nestedElementKeyPath];
29 |
30 | if( validParentKeyPath ) {
31 | return [elementDetails.ownerElement valueForKey:validParentKeyPath] == elementDetails.uiElement;
32 | } else {
33 | return NO;
34 | }
35 | }
36 |
37 | - (NSString*) displayDescription {
38 | return [NSString stringWithFormat:@"$%@", self.nestedElementKeyPath];
39 | }
40 |
41 | - (BOOL) isEqual:(id)object {
42 | if ( [object isKindOfClass:ISSNestedElementSelector.class] ) {
43 | return [super isEqual:object];
44 | }
45 | return NO;
46 | }
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSPointValue.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSPointValue.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | typedef NS_ENUM(NSInteger, ISSPointValueType) {
15 | ISSPointValueTypeStandard,
16 | ISSPointValueTypeParentRelative,
17 | ISSPointValueTypeWindowRelative,
18 | };
19 |
20 | @interface ISSPointValue : NSObject
21 |
22 | @property (nonatomic, readonly) ISSPointValueType type;
23 | @property (nonatomic, readonly) CGPoint point;
24 |
25 |
26 | + (ISSPointValue*) zeroPoint;
27 | + (ISSPointValue*) pointWithPoint:(CGPoint)point;
28 |
29 | + (ISSPointValue*) parentCenter;
30 | + (ISSPointValue*) parentRelativeCenterPointWithPoint:(CGPoint)point;
31 |
32 | + (ISSPointValue*) windowCenter;
33 | + (ISSPointValue*) windowRelativeCenterPointWithPoint:(CGPoint)point;
34 |
35 |
36 | - (CGPoint) pointForView:(UIView*)view;
37 |
38 | @end
39 |
40 |
41 | NS_ASSUME_NONNULL_END
42 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSPointValue.m:
--------------------------------------------------------------------------------
1 | //
2 | // ISSPointValue.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 | #import
11 |
12 | #import "ISSPointValue.h"
13 |
14 |
15 | @implementation ISSPointValue
16 |
17 | + (ISSPointValue*) zeroPoint {
18 | return [[self alloc] initWithType:ISSPointValueTypeStandard point:CGPointZero];
19 | }
20 |
21 | + (ISSPointValue*) pointWithPoint:(CGPoint)point {
22 | return [[self alloc] initWithType:ISSPointValueTypeStandard point:point];
23 | }
24 |
25 | + (ISSPointValue*) parentCenter {
26 | return [[self alloc] initWithType:ISSPointValueTypeParentRelative point:CGPointZero];
27 | }
28 |
29 | + (ISSPointValue*) parentRelativeCenterPointWithPoint:(CGPoint)point {
30 | return [[self alloc] initWithType:ISSPointValueTypeParentRelative point:point];
31 | }
32 |
33 | + (ISSPointValue*) windowCenter {
34 | return [[self alloc] initWithType:ISSPointValueTypeWindowRelative point:CGPointZero];
35 | }
36 |
37 | + (ISSPointValue*) windowRelativeCenterPointWithPoint:(CGPoint)point {
38 | return [[self alloc] initWithType:ISSPointValueTypeWindowRelative point:point];
39 | }
40 |
41 | - (instancetype) initWithType:(enum ISSPointValueType)type point:(CGPoint)point {
42 | self = [super init];
43 | if ( self ) {
44 | _type = type;
45 | _point = point;
46 | }
47 | return self;
48 | }
49 |
50 | + (CGPoint) anchorAdjustedCenterPoint:(CGPoint)point forView:(UIView*)view {
51 | CGPoint anchor = view.layer.anchorPoint;
52 | CGPoint delta = CGPointMake((anchor.x - 0.5f) * view.bounds.size.width, (anchor.x - 0.5f) * view.bounds.size.height);
53 | return CGPointMake(point.x + delta.x, point.y + delta.y);
54 | }
55 |
56 | + (CGPoint) sourcePoint:(CGPoint)sourcePoint adjustedBy:(CGPoint)point {
57 | sourcePoint.x += point.x;
58 | sourcePoint.y += point.y;
59 | return sourcePoint;
60 | }
61 |
62 | + (CGPoint) windowCenterForView:(UIView*)view {
63 | UIWindow* window = view.window;
64 | CGRect bounds;
65 | if( window ) bounds = window.bounds;
66 | else bounds = [UIScreen mainScreen].bounds;
67 | return [self anchorAdjustedCenterPoint:CGPointMake(CGRectGetWidth(bounds)/2.0f, CGRectGetHeight(bounds)/2.0f) forView:view];
68 | }
69 |
70 | + (CGPoint) superViewCenterForView:(UIView*)view {
71 | if( view.superview ) return [self anchorAdjustedCenterPoint:CGPointMake(CGRectGetWidth(view.superview.bounds)/2.0f, CGRectGetHeight(view.superview.bounds)/2.0f) forView:view];
72 | else return [self windowCenterForView:view];
73 | }
74 |
75 | - (CGPoint) pointForView:(UIView*)view {
76 | if( self.type == ISSPointValueTypeStandard ) {
77 | return self.point;
78 | } else if( self.type == ISSPointValueTypeParentRelative ) {
79 | return [self.class sourcePoint:[self.class superViewCenterForView:view] adjustedBy:self.point];
80 | } else /*if( self.type == ISSPointValueTypeWindowRelative )*/ {
81 | return [self.class sourcePoint:[self.class windowCenterForView:view] adjustedBy:self.point];
82 | }
83 | }
84 |
85 | - (NSValue*) transformToNSValue {
86 | return [NSValue valueWithCGPoint:self.point];
87 | }
88 |
89 |
90 | #pragma mark - NSObject overrides
91 |
92 | - (NSString*) description {
93 | return [NSString stringWithFormat:@"ISSPointValue(%ld - %@)", (long)_type, NSStringFromCGPoint(_point)];
94 | }
95 |
96 | @end
97 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSPropertyDeclaration.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSPropertyDeclaration.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSLazyValue.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | @class ISSPropertyDefinition, ISSUIElementDetails;
15 |
16 | extern NSObject* const ISSPropertyDefinitionUseCurrentValue;
17 |
18 |
19 | /**
20 | * Represents the declaration of a property in a stylesheet, along with the declared value.
21 | */
22 | @interface ISSPropertyDeclaration : NSObject
23 |
24 | @property (nonatomic, readonly, nullable) NSString* nestedElementKeyPath;
25 | @property (nonatomic, readonly) ISSPropertyDefinition* property;
26 | @property (nonatomic, readonly, nullable) NSArray* parameters;
27 | @property (nonatomic, readonly, nullable) NSString* unrecognizedName;
28 | @property (nonatomic, strong, nullable) id propertyValue;
29 | @property (nonatomic, copy, nullable) ISSLazyValueBlock lazyPropertyTransformationBlock;
30 | @property (nonatomic, readonly) BOOL dynamicValue; // Indicates weather the value of this property may be dynamic, i.e. may need to be re-evaluated every time styles are applied
31 |
32 | - (instancetype) initWithProperty:(ISSPropertyDefinition*)property nestedElementKeyPath:(nullable NSString*)nestedElementKeyPath;
33 | - (instancetype) initWithProperty:(ISSPropertyDefinition*)property parameters:(nullable NSArray*)parameters nestedElementKeyPath:(nullable NSString*)nestedElementKeyPath;
34 | - (instancetype) initWithUnrecognizedProperty:(NSString*)unrecognizedPropertyName;
35 |
36 | - (BOOL) transformValueIfNeeded;
37 |
38 | - (BOOL) applyPropertyValueOnTarget:(ISSUIElementDetails*)targetDetails;
39 |
40 | @end
41 |
42 |
43 | NS_ASSUME_NONNULL_END
44 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSPropertyDeclaration.m:
--------------------------------------------------------------------------------
1 | //
2 | // ISSPropertyDeclaration.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSPropertyDeclaration.h"
10 |
11 | #import "ISSPropertyDefinition.h"
12 | #import "NSString+ISSStringAdditions.h"
13 | #import "NSObject+ISSLogSupport.h"
14 | #import "ISSDownloadableResource.h"
15 | #import "ISSUIElementDetails.h"
16 | #import "ISSUpdatableValue.h"
17 |
18 |
19 | NSObject* const ISSPropertyDefinitionUseCurrentValue = @"";
20 |
21 |
22 | @implementation ISSPropertyDeclaration
23 |
24 | - (instancetype) initWithProperty:(ISSPropertyDefinition*)property nestedElementKeyPath:(NSString*)nestedElementKeyPath {
25 | self = [super init];
26 | if ( self ) {
27 | _nestedElementKeyPath = nestedElementKeyPath;
28 | _property = property;
29 | }
30 | return self;
31 | }
32 |
33 | - (instancetype) initWithProperty:(ISSPropertyDefinition*)property parameters:(NSArray*)parameters nestedElementKeyPath:(NSString*)nestedElementKeyPath {
34 | self = [super init];
35 | if ( self ) {
36 | _nestedElementKeyPath = nestedElementKeyPath;
37 | _property = property;
38 | _parameters = parameters;
39 | }
40 | return self;
41 | }
42 |
43 | - (instancetype) initWithUnrecognizedProperty:(NSString*)unrecognizedPropertyName {
44 | self = [super init];
45 | if ( self ) {
46 | _unrecognizedName = unrecognizedPropertyName;
47 | }
48 | return self;
49 | }
50 |
51 | #pragma mark - NSCopying
52 |
53 | - (id) copyWithZone:(NSZone*)zone {
54 | ISSPropertyDeclaration* decl;
55 | if( _unrecognizedName ) decl = [[(id)self.class allocWithZone:zone] initWithUnrecognizedProperty:_unrecognizedName];
56 | else {
57 | decl = [[(id) self.class allocWithZone:zone] initWithProperty:self.property parameters:self.parameters nestedElementKeyPath:self.nestedElementKeyPath];
58 | decl.propertyValue = self.propertyValue;
59 | decl.lazyPropertyTransformationBlock = self.lazyPropertyTransformationBlock;
60 | }
61 | return decl;
62 | }
63 |
64 |
65 | #pragma mark - Public interface
66 |
67 | - (BOOL) dynamicValue {
68 | return self.property.supportsDynamicValue;
69 | }
70 |
71 | - (BOOL) transformValueIfNeeded {
72 | if( self.lazyPropertyTransformationBlock ) {
73 | self.propertyValue = self.lazyPropertyTransformationBlock(self);
74 | self.lazyPropertyTransformationBlock = nil;
75 | return YES;
76 | }
77 | return NO;
78 | }
79 |
80 | - (BOOL) applyPropertyValueOnTarget:(ISSUIElementDetails*)targetDetails {
81 | if( !self.property ) {
82 | ISSLogWarning(@"Cannot apply property value - unknown property!");
83 | return NO;
84 | }
85 | if( !self.propertyValue ) {
86 | ISSLogWarning(@"Cannot apply property value - value is nil!");
87 | return NO;
88 | }
89 | if( self.propertyValue == ISSPropertyDefinitionUseCurrentValue ) {
90 | ISSLogTrace(@"Property value not changed - using existing value");
91 | return YES;
92 | }
93 |
94 | id valueBeforeTransform = self.propertyValue;
95 | BOOL didTransform = [self transformValueIfNeeded];
96 | if( didTransform && !self.propertyValue ) {
97 | ISSLogWarning(@"Cannot apply property value - empty property value after transform! Value before transform: '%@'.", valueBeforeTransform);
98 | return NO;
99 | }
100 |
101 | id value = nil;
102 | BOOL skipWarning = NO;
103 | if( [self.propertyValue isKindOfClass:ISSUpdatableValue.class] ) {
104 | ISSUpdatableValue* updatableValue = self.propertyValue;
105 | [targetDetails observeUpdatableValue:updatableValue forProperty:self];
106 | [updatableValue requestUpdate];
107 | value = updatableValue.lastValue;
108 | skipWarning = value == nil;
109 | } else {
110 | [targetDetails stopObservingUpdatableValueForProperty:self];
111 | value = self.propertyValue;
112 | }
113 |
114 | BOOL result = [self.property setValue:value onTarget:targetDetails.uiElement andParameters:self.parameters];
115 | if( !result && !skipWarning ) {
116 | ISSLogDebug(@"Unable to set value on %@", targetDetails.uiElement);
117 | }
118 | return result;
119 | }
120 |
121 |
122 | #pragma mark - NSObject overrides
123 |
124 | - (NSString*) description {
125 | if( self.parameters.count ) {
126 | NSString* paramDesc = [[[self.parameters description] stringByReplacingOccurrencesOfString:@" " withString:@""] stringByReplacingOccurrencesOfString:@"\n" withString:@""];
127 | return [NSString stringWithFormat:@"ISSPropertyDeclaration[%@ %@]", self.property.displayDescription, paramDesc];
128 | }
129 | else if( self.unrecognizedName ) return [NSString stringWithFormat:@"ISSPropertyDeclaration[%@]", self.unrecognizedName];
130 | else return [NSString stringWithFormat:@"ISSPropertyDeclaration[%@]", self.property.displayDescription];
131 | }
132 |
133 | - (BOOL) isEqual:(id)object {
134 | if( object == self ) return YES;
135 | else if( [object isKindOfClass:ISSPropertyDeclaration.class] ) {
136 | ISSPropertyDeclaration* other = object;
137 | if( [other.property isEqual:self.property] && [NSString iss_string:other.nestedElementKeyPath isEqualToString:self.nestedElementKeyPath] ) {
138 | if( other.parameters == self.parameters ) return YES;
139 | else return [other.parameters isEqualToArray:self.parameters];
140 | }
141 | }
142 | return NO;
143 | }
144 |
145 | - (NSUInteger) hash {
146 | return self.property.hash;
147 | }
148 |
149 | @end
150 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSPropertyDeclarations.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSPropertyDeclarations.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | @class ISSUIElementDetails;
10 | @class ISSStylingContext;
11 | @class ISSStyleSheetScope;
12 | @class ISSSelectorChain;
13 |
14 | NS_ASSUME_NONNULL_BEGIN
15 |
16 |
17 | /**
18 | * Represents a declaration block (or rule set) in a stylesheet.
19 | */
20 | @interface ISSPropertyDeclarations : NSObject
21 |
22 | @property (nonatomic, readonly, nullable) ISSSelectorChain* extendedDeclarationSelectorChain;
23 | @property (nonatomic, weak, nullable) ISSPropertyDeclarations* extendedDeclaration;
24 |
25 | @property (nonatomic, readonly) NSArray* selectorChains;
26 | @property (nonatomic, readonly, nullable) NSArray* properties;
27 | @property (nonatomic, readonly) NSString* displayDescription;
28 | @property (nonatomic, readonly) BOOL containsPseudoClassSelector;
29 | @property (nonatomic, readonly) BOOL containsPseudoClassSelectorOrDynamicProperties;
30 | @property (nonatomic, readonly) NSUInteger specificity;
31 |
32 | @property (nonatomic, weak) ISSStyleSheetScope* scope; // The scope used by the parent stylesheet...
33 |
34 | - (id) initWithSelectorChains:(NSArray*)selectorChains andProperties:(nullable NSArray*)properties;
35 | - (id) initWithSelectorChains:(NSArray*)selectorChains andProperties:(nullable NSArray*)properties extendedDeclarationSelectorChain:(nullable ISSSelectorChain*)extendedDeclarationSelectorChain;
36 |
37 | - (BOOL) matchesElement:(ISSUIElementDetails*)elementDetails stylingContext:(ISSStylingContext*)stylingContext;
38 | - (nullable ISSPropertyDeclarations*) propertyDeclarationsMatchingElement:(ISSUIElementDetails*)elementDetails stylingContext:(ISSStylingContext*)stylingContext;
39 |
40 | - (BOOL) containsSelectorChain:(ISSSelectorChain*)selectorChain;
41 |
42 | - (NSString*) displayDescription:(BOOL)withProperties;
43 |
44 | @end
45 |
46 |
47 | NS_ASSUME_NONNULL_END
48 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSPropertyDeclarations.m:
--------------------------------------------------------------------------------
1 | //
2 | // ISSPropertyDeclarations.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSPropertyDeclarations.h"
10 |
11 | #import "ISSSelectorChain.h"
12 | #import "ISSUIElementDetails.h"
13 | #import "ISSStylingContext.h"
14 | #import "ISSPropertyDeclaration.h"
15 |
16 |
17 | @implementation ISSPropertyDeclarations {
18 | NSArray* _properties;
19 | }
20 |
21 | #pragma mark - ISSPropertyDeclarations interface
22 |
23 |
24 | - (id) initWithSelectorChains:(NSArray*)selectorChains andProperties:(NSArray*)properties {
25 | return [self initWithSelectorChains:selectorChains andProperties:properties extendedDeclarationSelectorChain:nil];
26 | }
27 |
28 | - (id) initWithSelectorChains:(NSArray*)selectorChains andProperties:(NSArray*)properties extendedDeclarationSelectorChain:(ISSSelectorChain*)extendedDeclarationSelectorChain {
29 | if( self = [super init] ) {
30 | _selectorChains = selectorChains;
31 | _properties = properties;
32 | _extendedDeclarationSelectorChain = extendedDeclarationSelectorChain;
33 |
34 | for(ISSSelectorChain* chain in selectorChains) {
35 | if( chain.hasPseudoClassSelector ) {
36 | _containsPseudoClassSelector = _containsPseudoClassSelectorOrDynamicProperties = YES;
37 | break;
38 | }
39 | }
40 | if( !_containsPseudoClassSelectorOrDynamicProperties ) {
41 | for(ISSPropertyDeclaration* decl in properties) {
42 | if( decl.dynamicValue ) {
43 | _containsPseudoClassSelectorOrDynamicProperties = YES;
44 | break;
45 | }
46 | }
47 | }
48 | }
49 | return self;
50 | }
51 |
52 | - (NSArray*) properties {
53 | if ( _extendedDeclaration && _extendedDeclaration != self ) {
54 | return [_extendedDeclaration.properties arrayByAddingObjectsFromArray:_properties];
55 | } else {
56 | return _properties;
57 | }
58 | }
59 |
60 | - (BOOL) matchesElement:(ISSUIElementDetails*)elementDetails stylingContext:(ISSStylingContext*)stylingContext {
61 | for(ISSSelectorChain* selectorChain in _selectorChains) {
62 | if ( [selectorChain matchesElement:elementDetails stylingContext:stylingContext] ) return YES;
63 | }
64 | return NO;
65 | }
66 |
67 | - (ISSPropertyDeclarations*) propertyDeclarationsMatchingElement:(ISSUIElementDetails*)elementDetails stylingContext:(ISSStylingContext*)stylingContext {
68 | NSMutableArray* matchingChains = self.containsPseudoClassSelector ? [NSMutableArray array] : nil;
69 | for(ISSSelectorChain* selectorChain in _selectorChains) {
70 | if ( [selectorChain matchesElement:elementDetails stylingContext:stylingContext] ) {
71 | if( !self.containsPseudoClassSelector ) {
72 | return self; // If this style sheet declarations block doesn't contain any pseudo classes - return the declarations object itself directly when first selector chain match is found (since no additional matching needs to be done)
73 | }
74 | [matchingChains addObject:selectorChain];
75 | }
76 | }
77 | if( matchingChains.count ) return [[ISSPropertyDeclarations alloc] initWithSelectorChains:matchingChains andProperties:self.properties];
78 | else return nil;
79 | }
80 |
81 | - (BOOL) containsSelectorChain:(ISSSelectorChain*)selectorChain {
82 | for(ISSSelectorChain* ruleSetSelectorChain in _selectorChains) {
83 | if ( [ruleSetSelectorChain isEqual:selectorChain] ) {
84 | return YES;
85 | }
86 | }
87 | return NO;
88 | }
89 |
90 | - (NSUInteger) specificity {
91 | NSUInteger specificity = 0;
92 | for(ISSSelectorChain* selectorChain in _selectorChains) {
93 | specificity += selectorChain.specificity;
94 | }
95 | return specificity;
96 | }
97 |
98 | - (NSString*) displayDescription:(BOOL)withProperties {
99 | NSMutableArray* chainsCopy = [_selectorChains mutableCopy];
100 | [chainsCopy enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { chainsCopy[idx] = [obj displayDescription]; }];
101 | NSString* chainsDescription = [chainsCopy componentsJoinedByString:@", "];
102 |
103 | if( withProperties ) return [NSString stringWithFormat:@"%@ : %@", chainsDescription, _properties];
104 | else return chainsDescription;
105 | }
106 |
107 | - (NSString*) displayDescription {
108 | return [self displayDescription:YES];
109 | }
110 |
111 |
112 | #pragma mark - NSObject overrides
113 |
114 |
115 | - (NSString*) description {
116 | return [NSString stringWithFormat:@"ISSPropertyDeclarations[%@]", self.displayDescription];
117 | }
118 |
119 | - (BOOL) isEqual:(id)object {
120 | if( object == self ) return YES;
121 | else return [object isKindOfClass:ISSPropertyDeclarations.class] && [_selectorChains isEqualToArray:[object selectorChains]] &&
122 | [_properties isEqualToArray:[(ISSPropertyDeclarations*)object properties]];
123 | }
124 |
125 | - (NSUInteger) hash {
126 | return self.description.hash;
127 | }
128 |
129 |
130 | @end
131 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSPropertyDefinition.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSPropertyDefinition.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | @class ISSPropertyDefinition;
15 |
16 | typedef void (^PropertySetterBlock)(ISSPropertyDefinition* property, id viewObject, id _Nullable value, NSArray* _Nullable parameters) __deprecated;
17 |
18 | typedef BOOL (^ISSPropertySetterBlock)(ISSPropertyDefinition* property, id viewObject, id _Nullable value, NSArray* _Nullable parameters);
19 |
20 |
21 | typedef NS_ENUM(NSInteger, ISSPropertyType) {
22 | ISSPropertyTypeString,
23 | ISSPropertyTypeAttributedString,
24 | ISSPropertyTypeBool,
25 | ISSPropertyTypeNumber,
26 | ISSPropertyTypeOffset,
27 | ISSPropertyTypeRect,
28 | ISSPropertyTypeLayout,
29 | ISSPropertyTypeSize,
30 | ISSPropertyTypePoint,
31 | ISSPropertyTypeEdgeInsets,
32 | ISSPropertyTypeColor,
33 | ISSPropertyTypeCGColor,
34 | ISSPropertyTypeTransform,
35 | ISSPropertyTypeFont,
36 | ISSPropertyTypeImage,
37 | ISSPropertyTypeEnumType,
38 | };
39 |
40 | /**
41 | * Represents the definition of a property that can be declared in a stylesheet. This class is also the repository for all available property definitions
42 | * supported by InterfaCSS.
43 | */
44 | @interface ISSPropertyDefinition : NSObject
45 |
46 | @property (nonatomic, readonly) NSString* name;
47 | @property (nonatomic, readonly) BOOL nameIsKeyPath; // Indicates weather this property definition refers to a property in a nested property, i.e. the name field contains a property name prefix
48 | @property (nonatomic, readonly) BOOL anonymous;
49 | @property (nonatomic, readonly) NSSet* allNames; // lowercase names/aliases
50 |
51 |
52 | @property (nonatomic, readonly) ISSPropertyType type;
53 | @property (nonatomic, readonly) NSString* typeDescription;
54 | @property (nonatomic, readonly) NSString* uniqueTypeDescription;
55 | @property (nonatomic, readonly) BOOL supportsDynamicValue; // Indicates weather the value of this property may be dynamic, i.e. may need to be re-evaluated every time styles are applied
56 |
57 | @property (nonatomic, readonly, nullable) NSDictionary* parameterEnumValues;
58 | @property (nonatomic, readonly, nullable) NSDictionary* enumValues;
59 | @property (nonatomic, readonly) BOOL enumBitMaskType;
60 |
61 | @property (nonatomic, readonly) BOOL useIntrospection;
62 |
63 | @property (nonatomic, copy, readonly, nullable) ISSPropertySetterBlock propertySetterBlock;
64 |
65 | @property (nonatomic, readonly) BOOL isParameterizedProperty;
66 |
67 | @property (nonatomic, readonly) NSString* displayDescription;
68 |
69 | @property (nonatomic, strong, nullable) ISSPropertyDefinition* overriddenDefinition;
70 |
71 |
72 | /**
73 | * Creates a temporary, anonymous, property definition.
74 | */
75 | - (id) initAnonymousPropertyDefinitionWithType:(ISSPropertyType)type;
76 |
77 | /**
78 | * Creates a simple property definition.
79 | */
80 | - (id) initWithName:(NSString*)name type:(ISSPropertyType)type;
81 |
82 | /**
83 | * Creates a simple property definition that optionally can set it's value via introspection (i.e. use declared or default setter method for property), instead of using KVC.
84 | */
85 | - (id) initWithName:(NSString *)name type:(ISSPropertyType)type useIntrospection:(BOOL)useIntrospection;
86 |
87 | /**
88 | * Creates a property definition with an optional number of aliases.
89 | */
90 | - (id) initWithName:(NSString*)name aliases:(nullable NSArray*)aliases type:(ISSPropertyType)type;
91 |
92 | /**
93 | * Creates a property definition with an optional number of aliases.
94 | * If this is an enum property, specify the enum values in the `enumValues` parameter. If the enum values are of a bit mask type, specify `YES` in the `enumBitMaskType` parameter.
95 | */
96 | - (id) initWithName:(NSString*)name aliases:(nullable NSArray*)aliases type:(ISSPropertyType)type enumValues:(nullable NSDictionary*)enumValues enumBitMaskType:(BOOL)enumBitMaskType;
97 |
98 | /**
99 | * Creates a property definition with an optional number of aliases.
100 | * If this is an enum property, specify the enum values in the `enumValues` parameter. If the enum values are of a bit mask type, specify `YES` in the `enumBitMaskType` parameter.
101 | * If this is a parameterized property, specify the parameter value transformation dictionary in `parameterEnumValues`.
102 | * To use a custom handling for setting the property value - specify a property setter block in the `setterBlock` parameter.
103 | */
104 | - (id) initWithName:(NSString*)name aliases:(nullable NSArray*)aliases type:(ISSPropertyType)type enumValues:(nullable NSDictionary*)enumValues
105 | enumBitMaskType:(BOOL)enumBitMaskType setterBlock:(nullable PropertySetterBlock)setterBlock parameterEnumValues:(nullable NSDictionary*)parameterEnumValues
106 | __deprecated_msg("Due to deprecation of setter block type`");
107 |
108 | /**
109 | * Creates a property definition with an optional number of aliases, that optionally can set it's value via introspection (i.e. use declared or default setter method for property), instead of using KVC.
110 | * If this is an enum property, specify the enum values in the `enumValues` parameter. If the enum values are of a bit mask type, specify `YES` in the `enumBitMaskType` parameter.
111 | * If this is a parameterized property, specify the parameter value transformation dictionary in `parameterEnumValues`.
112 | * To use a custom handling for setting the property value - specify a property setter block in the `setterBlock` parameter.
113 | */
114 | - (id) initWithName:(NSString*)name aliases:(nullable NSArray*)aliases type:(ISSPropertyType)type enumValues:(nullable NSDictionary*)enumValues
115 | enumBitMaskType:(BOOL)enumBitMaskType setterBlock:(nullable ISSPropertySetterBlock)setterBlock parameterEnumValues:(nullable NSDictionary*)parameterEnumValues useIntrospection:(BOOL)useIntrospection;
116 |
117 |
118 | /**
119 | * Sets the value of the property represented by this object, on the specified target.
120 | */
121 | - (BOOL) setValue:(nullable id)value onTarget:(nullable id)target andParameters:(nullable NSArray*)params;
122 |
123 | - (NSComparisonResult) compareByName:(nullable ISSPropertyDefinition*)other;
124 |
125 | @end
126 |
127 | NS_ASSUME_NONNULL_END
128 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSPropertyRegistry.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSPropertyRegistry.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSPropertyDefinition.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | /**
15 | * The property registry keeps track on all properties that can be set through stylesheets.
16 | */
17 | @interface ISSPropertyRegistry : NSObject
18 |
19 | @property (nonatomic, strong, readonly) NSSet* propertyDefinitions;
20 | @property (nonatomic, strong, readonly) NSDictionary* propertyDefinitionsForClass;
21 |
22 | @property (nonatomic, strong, readonly) NSDictionary* validPrefixKeyPaths;
23 |
24 | - (NSSet*) propertyDefinitionsForType:(ISSPropertyType)propertyType;
25 | - (NSSet*) propertyDefinitionsForViewClass:(Class)viewClass;
26 | - (nullable ISSPropertyDefinition*) propertyDefinitionForProperty:(NSString*)propertyName inClass:(Class)viewClass;
27 |
28 | - (NSSet*) typePropertyDefinitions:(ISSPropertyType)propertyType;
29 |
30 | /**
31 | * Returns the canonical type class for the given class, i.e. the closest super class that represents a valid type selector. For instance, for all `UIView`
32 | * subclasses, this would by default be `UIView`.
33 | */
34 | - (nullable Class) canonicalTypeClassForClass:(Class)clazz;
35 | - (nullable NSString*) canonicalTypeForClass:(Class)clazz;
36 | - (nullable Class) canonicalTypeClassForType:(NSString*)type registerIfNotFound:(BOOL)registerIfNotFound;
37 | - (nullable Class) canonicalTypeClassForType:(NSString*)type;
38 |
39 |
40 | /**
41 | * Registers a class for use as a valid type selector in stylesheets. Note: this happens automatically whenever an unknown, but valid, class name is encountered
42 | * in a type selector in a stylesheet. This method exist to be able to register all custom canonical type classes before stylesheet parsing occurs, and to also
43 | * enable case-insensitive matching of type name -> class.
44 | *
45 | * @see canonicalTypeClassForClass:
46 | */
47 | - (void) registerCanonicalTypeClass:(Class)clazz;
48 |
49 | /**
50 | * Registers a custom property with the specified name and type, that can then be used in stylesheets.
51 | */
52 | - (ISSPropertyDefinition*) registerCustomProperty:(NSString*)propertyName propertyType:(ISSPropertyType)propertyType;
53 |
54 | /**
55 | * Registers a custom property definition.
56 | */
57 | - (void) registerCustomProperty:(ISSPropertyDefinition*)propertyDefinition;
58 |
59 | /**
60 | * Registers a valid property prefix key path (i.e. nested element key path), which can be used in stylesheets to set properties on child elements of a particular element.
61 | */
62 | - (void) registerValidPrefixKeyPath:(NSString*)prefix;
63 |
64 | /**
65 | * Registers a set of valid property prefixes (i.e. nested element key paths), which can be used in stylesheets to set properties on child elements of a particular element.
66 | */
67 | - (void) registerValidPrefixKeyPaths:(NSArray*)prefixes;
68 |
69 | /**
70 | * Finds the subset of valid property prefix key paths that are supported by the specified class.
71 | */
72 | - (NSSet*) validPrefixKeyPathsForClass:(Class)clazz;
73 |
74 | #if DEBUG == 1
75 | - (NSString*) propertyDescriptionsForMarkdown;
76 | #endif
77 |
78 | @end
79 |
80 |
81 | NS_ASSUME_NONNULL_END
82 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSPseudoClass.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSPseudoClass.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 | #import
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 |
15 | @class ISSUIElementDetails;
16 |
17 | typedef NS_ENUM(NSInteger, ISSPseudoClassType) {
18 | #if TARGET_OS_TV == 0
19 | // User interface orientation and traits
20 | ISSPseudoClassTypeInterfaceOrientationLandscape,
21 | ISSPseudoClassTypeInterfaceOrientationLandscapeLeft,
22 | ISSPseudoClassTypeInterfaceOrientationLandscapeRight,
23 | ISSPseudoClassTypeInterfaceOrientationPortrait,
24 | ISSPseudoClassTypeInterfaceOrientationPortraitUpright,
25 | ISSPseudoClassTypeInterfaceOrientationPortraitUpsideDown,
26 | #endif
27 |
28 | // Device
29 | ISSPseudoClassTypeUserInterfaceIdiomPad,
30 | ISSPseudoClassTypeUserInterfaceIdiomPhone,
31 | #if TARGET_OS_TV == 1
32 | ISSPseudoClassTypeUserInterfaceIdiomTV,
33 | #endif
34 | ISSPseudoClassTypeMinOSVersion,
35 | ISSPseudoClassTypeMaxOSVersion,
36 | ISSPseudoClassTypeDeviceModel,
37 | ISSPseudoClassTypeScreenWidth,
38 | ISSPseudoClassTypeScreenWidthLessThan,
39 | ISSPseudoClassTypeScreenWidthGreaterThan,
40 | ISSPseudoClassTypeScreenHeight,
41 | ISSPseudoClassTypeScreenHeightLessThan,
42 | ISSPseudoClassTypeScreenHeightGreaterThan,
43 |
44 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0
45 | ISSPseudoClassTypeHorizontalSizeClassRegular,
46 | ISSPseudoClassTypeHorizontalSizeClassCompact,
47 | ISSPseudoClassTypeVerticalSizeClassRegular,
48 | ISSPseudoClassTypeVerticalSizeClassCompact,
49 | #endif
50 |
51 | // UI element state
52 | ISSPseudoClassTypeStateEnabled,
53 | ISSPseudoClassTypeStateDisabled,
54 | ISSPseudoClassTypeStateSelected,
55 | ISSPseudoClassTypeStateHighlighted,
56 |
57 | // Structural
58 | ISSPseudoClassTypeRoot,
59 | ISSPseudoClassTypeNthChild,
60 | ISSPseudoClassTypeNthLastChild,
61 | ISSPseudoClassTypeOnlyChild,
62 | ISSPseudoClassTypeFirstChild,
63 | ISSPseudoClassTypeLastChild,
64 | ISSPseudoClassTypeNthOfType,
65 | ISSPseudoClassTypeNthLastOfType,
66 | ISSPseudoClassTypeOnlyOfType,
67 | ISSPseudoClassTypeFirstOfType,
68 | ISSPseudoClassTypeLastOfType,
69 | ISSPseudoClassTypeEmpty
70 | };
71 |
72 | @interface ISSPseudoClass : NSObject
73 |
74 | @property (nonatomic, readonly) NSString* displayDescription;
75 |
76 | - (instancetype) initStructuralPseudoClassWithA:(NSInteger)a b:(NSInteger)b type:(ISSPseudoClassType)pseudoClassType;
77 | + (instancetype) structuralPseudoClassWithA:(NSInteger)a b:(NSInteger)b type:(ISSPseudoClassType)pseudoClassType;
78 | + (instancetype) pseudoClassWithType:(ISSPseudoClassType)pseudoClassType;
79 | + (instancetype) pseudoClassWithType:(ISSPseudoClassType)pseudoClassType andParameter:(NSString*)parameter;
80 | + (instancetype) pseudoClassWithTypeString:(NSString*)typeAsString;
81 | + (instancetype) pseudoClassWithTypeString:(NSString*)typeAsString andParameter:(NSString*)parameter;
82 |
83 | + (ISSPseudoClassType) pseudoClassTypeFromString:(NSString*)typeAsString;
84 |
85 | - (BOOL) matchesElement:(ISSUIElementDetails*)elementDetails;
86 |
87 | @end
88 |
89 |
90 | NS_ASSUME_NONNULL_END
91 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSRectValue.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSRectValue.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 | #import
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 |
15 | typedef NS_ENUM(NSInteger, ISSRectValueType) {
16 | ISSRectValueTypeStandard,
17 | ISSRectValueTypeParentInsets,
18 | ISSRectValueTypeParentRelative,
19 | ISSRectValueTypeParentRelativeSizeToFit,
20 | ISSRectValueTypeWindowInsets,
21 | };
22 |
23 |
24 | extern CGFloat const ISSRectValueAuto;
25 |
26 |
27 | @interface ISSRectValue : NSObject
28 |
29 | @property (nonatomic, readonly) ISSRectValueType type;
30 | @property (nonatomic, readonly) CGRect rect;
31 | @property (nonatomic, readonly) UIEdgeInsets insets;
32 |
33 | + (ISSRectValue*) zeroRect;
34 | + (ISSRectValue*) rectWithRect:(CGRect)rect;
35 |
36 | + (ISSRectValue*) parentRect;
37 | + (ISSRectValue*) parentInsetRectWithSize:(CGSize)size;
38 | + (ISSRectValue*) parentInsetRectWithInsets:(UIEdgeInsets)insets;
39 | + (ISSRectValue*) parentRelativeRectWithSize:(CGSize)size relativeWidth:(BOOL)relativeWidth relativeHeight:(BOOL)relativeHeight;
40 | + (ISSRectValue*) parentRelativeSizeToFitRectWithSize:(CGSize)size relativeWidth:(BOOL)relativeWidth relativeHeight:(BOOL)relativeHeight;
41 |
42 | + (ISSRectValue*) windowRect;
43 | + (ISSRectValue*) windowInsetRectWithSize:(CGSize)size;
44 | + (ISSRectValue*) windowInsetRectWithInsets:(UIEdgeInsets)insets;
45 |
46 | - (void) setLeftInset:(CGFloat)inset relative:(BOOL)relative;
47 | - (void) setRightInset:(CGFloat)inset relative:(BOOL)relative;
48 | - (void) setTopInset:(CGFloat)inset relative:(BOOL)relative;
49 | - (void) setBottomInset:(CGFloat)inset relative:(BOOL)relative;
50 |
51 | - (CGRect) rectForView:(UIView*)view;
52 |
53 | @end
54 |
55 |
56 | NS_ASSUME_NONNULL_END
57 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSRemoteFont.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSRemoteFont.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 | #import
11 |
12 | #import "ISSUpdatableValue.h"
13 |
14 | NS_ASSUME_NONNULL_BEGIN
15 |
16 |
17 | @class ISSDownloadableResource;
18 |
19 | @interface ISSRemoteFont : ISSUpdatableValue
20 |
21 | @property (nonatomic, strong, readonly) ISSDownloadableResource* remoteFont;
22 | @property (nonatomic, readonly) CGFloat fontSize;
23 |
24 | + (instancetype) remoteFontWithResource:(ISSDownloadableResource*)remoteFont fontSize:(CGFloat)fontSize;
25 | + (instancetype) remoteFontWithURL:(NSURL*)url fontSize:(CGFloat)fontSize;
26 |
27 | @end
28 |
29 |
30 | NS_ASSUME_NONNULL_END
31 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSRemoteFont.m:
--------------------------------------------------------------------------------
1 | //
2 | // ISSRemoteFont.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSRemoteFont.h"
10 | #import "ISSDownloadableResource.h"
11 |
12 | @implementation ISSRemoteFont
13 |
14 | - (instancetype) initWithRemoteFont:(ISSDownloadableResource*)remoteFont fontSize:(CGFloat)fontSize {
15 | if ( self = [super init] ) {
16 | _remoteFont = remoteFont;
17 | _fontSize = fontSize;
18 |
19 | [_remoteFont addValueUpdateObserver:self selector:@selector(remoteFontUpdated:)];
20 | }
21 | return self;
22 | }
23 |
24 | + (instancetype) remoteFontWithResource:(ISSDownloadableResource*)remoteFont fontSize:(CGFloat)fontSize {
25 | return [[self alloc] initWithRemoteFont:remoteFont fontSize:fontSize];
26 | }
27 |
28 | + (instancetype) remoteFontWithURL:(NSURL*)url fontSize:(CGFloat)fontSize {
29 | return [self remoteFontWithResource:[ISSDownloadableResource downloadableFontWithURL:url] fontSize:fontSize];
30 | }
31 |
32 | - (void) dealloc {
33 | [_remoteFont removeValueUpdateObserver:self];
34 | }
35 |
36 |
37 | #pragma mark - Notifications
38 |
39 | - (void) remoteFontUpdated:(NSNotification*)notification {
40 | [self valueUpdated];
41 | }
42 |
43 |
44 | #pragma mark - ISSUpdatableValue
45 |
46 | - (void) requestUpdate {
47 | [self.remoteFont requestUpdate];
48 | }
49 |
50 | - (id) lastValue {
51 | if( self.remoteFont.cachedResource ) return [UIFont fontWithName:self.remoteFont.cachedResource size:self.fontSize];
52 | else return nil;
53 | }
54 |
55 |
56 | #pragma mark - NSObject overrides
57 |
58 | - (BOOL) isEqual:(id)object {
59 | if( object == self ) return YES;
60 | else if( [object isKindOfClass:ISSRemoteFont.class] ) {
61 | return [self.remoteFont isEqual:((ISSRemoteFont*)object).remoteFont] && self.fontSize == ((ISSRemoteFont*)object).fontSize;
62 | }
63 | return NO;
64 | }
65 |
66 | - (NSUInteger) hash {
67 | return 31 * self.remoteFont.hash + (NSUInteger)self.fontSize;
68 | }
69 |
70 | - (NSString*) description {
71 | if( self.remoteFont.cachedResource ) return [NSString stringWithFormat:@"%@[%@, %@]", NSStringFromClass(self.class), self.remoteFont.resourceURL.lastPathComponent, self.lastValue];
72 | else return [NSString stringWithFormat:@"%@[%@, size: %f]", NSStringFromClass(self.class), self.remoteFont.resourceURL.lastPathComponent, self.fontSize];
73 | }
74 |
75 | @end
76 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSSelector.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSSelector.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | @class ISSPseudoClass;
15 | @class ISSUIElementDetails;
16 | @class ISSStylingContext;
17 |
18 |
19 | typedef NS_ENUM(NSInteger, ISSSelectorCombinator) {
20 | ISSSelectorCombinatorDescendant,
21 | ISSSelectorCombinatorChild,
22 | ISSSelectorCombinatorAdjacentSibling,
23 | ISSSelectorCombinatorGeneralSibling,
24 | };
25 |
26 | @interface ISSSelector : NSObject
27 |
28 | @property (nonatomic, readonly, nullable) Class type;
29 | @property (nonatomic, readonly, nullable) NSString* elementId;
30 | @property (nonatomic, readonly, nullable) NSString* styleClass; // Returns the first style class
31 | @property (nonatomic, readonly, nullable) NSArray* styleClasses;
32 | @property (nonatomic, readonly, nullable) NSArray* pseudoClasses;
33 |
34 | @property (nonatomic, readonly) NSUInteger specificity;
35 |
36 | @property (nonatomic, readonly) NSString* displayDescription;
37 |
38 | + (nullable instancetype) selectorWithType:(nullable NSString*)type elementId:(nullable NSString*)elementId pseudoClasses:(nullable NSArray*)pseudoClasses;
39 | + (nullable instancetype) selectorWithType:(nullable NSString*)type styleClass:(nullable NSString*)styleClass pseudoClasses:(nullable NSArray*)pseudoClasses;
40 | + (nullable instancetype) selectorWithType:(nullable NSString*)type styleClasses:(nullable NSArray*)styleClasses pseudoClasses:(nullable NSArray*)pseudoClasses;
41 | + (nullable instancetype) selectorWithType:(nullable NSString*)type elementId:(nullable NSString*)elementId styleClass:(nullable NSString*)styleClass pseudoClasses:(nullable NSArray*)pseudoClasses;
42 | + (nullable instancetype) selectorWithType:(nullable NSString*)type elementId:(nullable NSString*)elementId styleClasses:(nullable NSArray*)styleClasses pseudoClasses:(nullable NSArray*)pseudoClasses;
43 |
44 | - (BOOL) matchesElement:(ISSUIElementDetails*)elementDetails stylingContext:(ISSStylingContext*)stylingContext;
45 |
46 | @end
47 |
48 |
49 | NS_ASSUME_NONNULL_END
50 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSSelectorChain.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSSelectorChain.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | @class ISSSelector;
15 | @class ISSUIElementDetails;
16 | @class ISSStylingContext;
17 |
18 |
19 | @interface ISSSelectorChain : NSObject
20 |
21 | @property (nonatomic, readonly) NSArray* selectorComponents;
22 | @property (nonatomic, readonly) NSString* displayDescription;
23 | @property (nonatomic, readonly) BOOL hasPseudoClassSelector;
24 | @property (nonatomic, readonly) NSUInteger specificity;
25 |
26 | + (nullable instancetype) selectorChainWithSelector:(ISSSelector*)selector;
27 | + (nullable instancetype) selectorChainWithComponents:(NSArray*)selectorComponents;
28 |
29 | - (ISSSelectorChain*) selectorChainByAddingDescendantSelector:(ISSSelector*)selector;
30 | - (ISSSelectorChain*) selectorChainByAddingDescendantSelectorChain:(ISSSelectorChain*)selectorChain;
31 |
32 | - (BOOL) matchesElement:(ISSUIElementDetails*)elementDetails stylingContext:(ISSStylingContext*)stylingContext;
33 |
34 | @end
35 |
36 |
37 | NS_ASSUME_NONNULL_END
38 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSStyleSheet.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSStyleSheet.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 | #import "ISSRefreshableResource.h"
12 |
13 | NS_ASSUME_NONNULL_BEGIN
14 |
15 |
16 | @protocol ISSStyleSheetParser;
17 | @class ISSUIElementDetails;
18 | @class ISSStylingContext;
19 | @class ISSPropertyDeclarations;
20 | @class ISSSelectorChain;
21 |
22 |
23 | typedef BOOL (^ISSStyleSheetScopeMatcher)(ISSUIElementDetails* elementDetails);
24 |
25 | extern NSString* const ISSStyleSheetRefreshedNotification;
26 | extern NSString* const ISSStyleSheetRefreshFailedNotification;
27 |
28 |
29 |
30 | /**
31 | * Class representing a scope for limiting to which views styles in a stylesheet should be applied.
32 | */
33 | @interface ISSStyleSheetScope : NSObject
34 |
35 | /** Scope limited to views under a view with the specified element ID. */
36 | + (ISSStyleSheetScope*) scopeWithElementId:(NSString*)elementId;
37 |
38 | /** Scope limited to views in the direct view hierarchy (i.e. excluding child view controllers) of view controllers with the specified class. */
39 | + (ISSStyleSheetScope*) scopeWithViewControllerClass:(Class)viewControllerClass;
40 |
41 | /** Scope limited to views in the view hierarchy of view controllers with the specified class. If `includeChildViewControllers` is `NO`, the scope is limited
42 | * to the direct view hierarchy of the view controller - if `YES`, views in child view controllers are also included. */
43 | + (ISSStyleSheetScope*) scopeWithViewControllerClass:(Class)viewControllerClass includeChildViewControllers:(BOOL)includeChildViewControllers;
44 |
45 | /** Scope limited to views in the direct view hierarchy (i.e. excluding child view controllers) of view controllers with the specified classes. */
46 | + (ISSStyleSheetScope*) scopeWithViewControllerClasses:(NSArray*)viewControllerClasses;
47 |
48 | /** Scope limited to views in the view hierarchy of view controllers with the specified classes. If `includeChildViewControllers` is `NO`, the scope is limited
49 | * to the direct view hierarchy of the view controller - if `YES`, views in child view controllers are also included. */
50 | + (ISSStyleSheetScope*) scopeWithViewControllerClasses:(NSArray*)viewControllerClasses includeChildViewControllers:(BOOL)includeChildViewControllers;
51 |
52 | /** Creates a scope with a custom matcher. */
53 | + (ISSStyleSheetScope*) scopeWithMatcher:(ISSStyleSheetScopeMatcher)matcher;
54 |
55 | - (BOOL) elementInScope:(ISSUIElementDetails*)elementDetails;
56 |
57 | @end
58 |
59 |
60 | /**
61 | * Represents a loaded stylesheet.
62 | */
63 | @interface ISSStyleSheet : ISSRefreshableResource
64 |
65 | @property (nonatomic, readonly) NSURL* styleSheetURL;
66 | @property (nonatomic, readonly, nullable) NSArray* declarations; // ISSPropertyDeclarations
67 | @property (nonatomic) BOOL active;
68 | @property (nonatomic, readonly) BOOL refreshable;
69 | @property (nonatomic, readonly) NSString* displayDescription;
70 | @property (nonatomic, strong, nullable) ISSStyleSheetScope* scope;
71 |
72 | - (id) initWithStyleSheetURL:(NSURL*)styleSheetURL declarations:(nullable NSArray*)declarations;
73 | - (id) initWithStyleSheetURL:(NSURL*)styleSheetURL declarations:(nullable NSArray*)declarations refreshable:(BOOL)refreshable;
74 | - (id) initWithStyleSheetURL:(NSURL*)styleSheetURL declarations:(nullable NSArray*)declarations refreshable:(BOOL)refreshable scope:(nullable ISSStyleSheetScope*)scope;
75 |
76 | - (nullable NSArray*) declarationsMatchingElement:(ISSUIElementDetails*)elementDetails stylingContext:(ISSStylingContext*)stylingContext;
77 |
78 | - (nullable ISSPropertyDeclarations*) findPropertyDeclarationsWithSelectorChain:(ISSSelectorChain*)selectorChain;
79 |
80 | - (void) refreshStylesheetWithCompletionHandler:(void (^)(void))completionHandler force:(BOOL)force;
81 |
82 | @end
83 |
84 |
85 | NS_ASSUME_NONNULL_END
86 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSStylingContext.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSStylingContext.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | @interface ISSStylingContext : NSObject
15 |
16 | @property (nonatomic) BOOL ignorePseudoClasses;
17 |
18 | @property (nonatomic) BOOL containsPartiallyMatchedDeclarations;
19 |
20 | + (instancetype) contextIgnoringPseudoClasses;
21 |
22 | @end
23 |
24 |
25 | NS_ASSUME_NONNULL_END
26 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSStylingContext.m:
--------------------------------------------------------------------------------
1 | //
2 | // ISSStylingContext.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSStylingContext.h"
10 |
11 | @implementation ISSStylingContext
12 |
13 | + (instancetype) contextIgnoringPseudoClasses {
14 | ISSStylingContext* context = [[self alloc] init];
15 | context.ignorePseudoClasses = YES;
16 | return context;
17 | }
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSUIElementDetails.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSUIElementDetails.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "InterfaCSS.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | @class ISSLayout, ISSUpdatableValue, ISSPropertyDeclaration;
15 |
16 |
17 | extern NSString* const ISSIndexPathKey;
18 | extern NSString* const ISSPrototypeViewInitializedKey;
19 |
20 |
21 | typedef id _Nullable (^ISSUIElementDetailsVisitorBlock)(ISSUIElementDetails* elementDetails);
22 |
23 |
24 | @interface NSObject (ISSUIElementDetails)
25 | @property (nonatomic, strong, nullable) ISSUIElementDetails* elementDetailsISS;
26 | @end
27 |
28 |
29 | // InterfaCSS class extension
30 | @interface InterfaCSS ()
31 | - (ISSUIElementDetails*) detailsForUIElement:(id)uiElement;
32 | @end
33 |
34 |
35 | @interface ISSUIElementDetails : NSObject
36 |
37 | @property (nonatomic, weak, readonly, nullable) id uiElement;
38 | @property (nonatomic, weak, readonly, nullable) UIView* view; // uiElement, if instance of UIView, otherwise nil
39 | @property (nonatomic, weak, readonly, nullable) id parentElement;
40 | @property (nonatomic, weak, nullable) id ownerElement; // Element holding a property reference (which is defined validNestedElements) to this element, otherwise parentElement
41 | @property (nonatomic, weak, readonly, nullable) UIView* parentView; // parentElement, if instance of UIView, otherwise nil
42 |
43 | @property (nonatomic, weak, readonly, nullable) UIViewController* parentViewController; // Direct parent view controller of element, i.e. parentElement, if instance of UIViewController, otherwise nil
44 |
45 | @property (nonatomic, weak, readonly, nullable) UIViewController* closestViewController; // Closest ancestor view controller
46 |
47 | @property (nonatomic, readonly, nullable) NSArray* childElementsForElement;
48 | @property (nonatomic, readonly, nullable) NSDictionary* validNestedElements;
49 |
50 | @property (nonatomic, strong, nullable) NSString* elementId;
51 | @property (nonatomic, strong, nullable) NSString* nestedElementKeyPath; // The key path / property name by which this element is know as in the ownerElement
52 |
53 | @property (nonatomic, strong, nullable) ISSLayout* layout;
54 |
55 | @property (nonatomic, readonly) BOOL addedToViewHierarchy;
56 | @property (nonatomic, readonly) BOOL stylesCacheable;
57 | @property (nonatomic) BOOL cachedStylingInformationDirty;
58 |
59 | @property (nonatomic, strong, readonly, nullable) NSString* elementStyleIdentityPath;
60 | @property (nonatomic, readonly) BOOL ancestorHasElementId;
61 | @property (nonatomic, strong, nullable) NSString* customElementStyleIdentity;
62 | @property (nonatomic, readonly) BOOL ancestorUsesCustomElementStyleIdentity;
63 |
64 | @property (nonatomic, weak, nullable) NSMutableArray* cachedDeclarations; // Optimization for quick access to cached declarations
65 | @property (nonatomic) BOOL stylesFullyResolved;
66 |
67 | @property (nonatomic, weak, nullable) Class canonicalType;
68 | @property (nonatomic, strong, nullable) NSSet* styleClasses;
69 |
70 | @property (nonatomic) BOOL stylingApplied; // Indicates if styles have been applied to element
71 | @property (nonatomic) BOOL stylingDisabled;
72 | @property (nonatomic, readonly) BOOL stylingAppliedAndDisabled;
73 | @property (nonatomic) BOOL stylesContainPseudoClassesOrDynamicProperties;
74 | @property (nonatomic, readonly) BOOL stylingAppliedAndStatic; // If YES, Indicates that styles have been applied to element and that there are no pseudo classes
75 |
76 | @property (nonatomic, copy, nullable) ISSWillApplyStylingNotificationBlock willApplyStylingBlock;
77 | @property (nonatomic, copy, nullable) ISSDidApplyStylingNotificationBlock didApplyStylingBlock;
78 |
79 | @property (nonatomic, strong, readonly, nullable) NSSet* disabledProperties;
80 |
81 | @property (nonatomic, strong, readonly, nullable) NSMutableDictionary* additionalDetails;
82 |
83 | @property (nonatomic, strong, readonly, nullable) NSMutableDictionary* prototypes;
84 |
85 | @property (nonatomic, readonly) BOOL isVisiting;
86 |
87 |
88 | - (id) initWithUIElement:(id)uiElement;
89 |
90 | - (BOOL) checkForUpdatedParentElement;
91 |
92 | + (void) resetAllCachedData;
93 | - (void) resetCachedData;
94 | - (void) resetCachedData:(BOOL)resetTypeRelatedInformation;
95 |
96 | - (void) typeQualifiedPositionInParent:(NSInteger*)position count:(NSInteger*)count;
97 |
98 | - (void) addDisabledProperty:(ISSPropertyDefinition*)disabledProperty;
99 | - (void) removeDisabledProperty:(ISSPropertyDefinition*)disabledProperty;
100 | - (BOOL) hasDisabledProperty:(ISSPropertyDefinition*)disabledProperty;
101 | - (void) clearDisabledProperties;
102 |
103 | - (nullable id) childElementForKeyPath:(NSString*)keyPath;
104 |
105 | - (void) observeUpdatableValue:(ISSUpdatableValue*)value forProperty:(ISSPropertyDeclaration*)propertyDeclaration;
106 | - (void) stopObservingUpdatableValueForProperty:(ISSPropertyDeclaration*)propertyDeclaration;
107 |
108 | - (nullable id) visitExclusivelyWithScope:(const void*)scope visitorBlock:(ISSUIElementDetailsVisitorBlock)visitorBlock;
109 |
110 | @end
111 |
112 |
113 | NS_ASSUME_NONNULL_END
114 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSUpdatableValue.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSUpdatableValue.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | extern NSString* const ISSUpdatableValueUpdatedNotification;
15 |
16 |
17 | @interface ISSUpdatableValue : NSObject
18 |
19 | @property (nonatomic, weak, readonly, nullable) id lastValue;
20 |
21 | - (void) requestUpdate;
22 |
23 | - (void) addValueUpdateObserver:(id)observer selector:(SEL)selector;
24 | - (void) removeValueUpdateObserver:(id)observer;
25 |
26 | - (void) valueUpdated;
27 |
28 | @end
29 |
30 |
31 | NS_ASSUME_NONNULL_END
32 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSUpdatableValue.m:
--------------------------------------------------------------------------------
1 | //
2 | // ISSUpdatableValue.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSUpdatableValue.h"
10 |
11 |
12 | NSString* const ISSUpdatableValueUpdatedNotification = @"ISSUpdatableValueUpdatedNotification";
13 |
14 |
15 | @implementation ISSUpdatableValue
16 |
17 | - (void) requestUpdate {}
18 |
19 | - (void) addValueUpdateObserver:(id)observer selector:(SEL)selector {
20 | [[NSNotificationCenter defaultCenter] addObserver:observer selector:selector name:ISSUpdatableValueUpdatedNotification object:self];
21 | }
22 |
23 | - (void) removeValueUpdateObserver:(id)observer {
24 | [[NSNotificationCenter defaultCenter] removeObserver:observer name:ISSUpdatableValueUpdatedNotification object:self];
25 | }
26 |
27 | - (void) valueUpdated {
28 | [[NSNotificationCenter defaultCenter] postNotificationName:ISSUpdatableValueUpdatedNotification object:self];
29 | }
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSViewPrototype.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSViewPrototype.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | typedef UIView* _Nullable (^ViewBuilderBlock)(UIView* _Nullable superview);
15 |
16 | /**
17 | * Represents a registered view prototype.
18 | */
19 | @interface ISSViewPrototype : NSObject
20 |
21 | @property (nonatomic, strong, readonly, nullable) NSString* name;
22 |
23 | @property (nonatomic, strong, readonly, nullable) NSString* propertyName;
24 | @property (nonatomic) BOOL implicitPropertyName;
25 | @property (nonatomic, readonly) BOOL addAsSubView;
26 |
27 | @property (nonatomic, copy, readonly) ViewBuilderBlock viewBuilderBlock;
28 | @property (nonatomic, strong) NSArray* subviewPrototypes;
29 |
30 | @property (nonatomic) BOOL prototypeScopeParent;
31 |
32 | + (instancetype) prototypeWithName:(nullable NSString*)name propertyName:(nullable NSString*)propertyName addAsSubView:(BOOL)addAsSubView viewBuilderBlock:(ViewBuilderBlock)viewBuilderBlock;
33 |
34 | - (nullable UIView*) createViewObjectFromPrototypeWithParent:(nullable id)parentObject;
35 |
36 | @end
37 |
38 |
39 | NS_ASSUME_NONNULL_END
40 |
--------------------------------------------------------------------------------
/InterfaCSS/Model/ISSViewPrototype.m:
--------------------------------------------------------------------------------
1 | //
2 | // ISSViewPrototype.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSViewPrototype.h"
10 | #import "ISSViewHierarchyParser.h"
11 | #import "NSString+ISSStringAdditions.h"
12 | #import "NSObject+ISSLogSupport.h"
13 |
14 |
15 | @implementation ISSViewPrototype
16 |
17 | + (ISSViewPrototype*) prototypeWithName:(NSString*)name propertyName:(NSString*)propertyName addAsSubView:(BOOL)addAsSubView viewBuilderBlock:(ViewBuilderBlock)viewBuilderBlock {
18 | return [[self alloc] initWithName:name propertyName:propertyName addAsSubView:addAsSubView viewBuilderBlock:viewBuilderBlock];
19 | }
20 |
21 | - (instancetype) initWithName:(NSString*)name propertyName:(NSString*)propertyName addAsSubView:(BOOL)addAsSubView viewBuilderBlock:(ViewBuilderBlock)viewBuilderBlock {
22 | if ( self = [super init] ) {
23 | _name = name;
24 | _propertyName = propertyName;
25 | _addAsSubView = addAsSubView;
26 | _viewBuilderBlock = viewBuilderBlock;
27 | _subviewPrototypes = @[];
28 | }
29 | return self;
30 | }
31 |
32 | - (UIView*) createViewObjectFromPrototypeWithParent:(id)parentObject {
33 | if( parentObject ) return [self createViewObjectFromPrototypeWithViewStack:@[parentObject]];
34 | else return [self createViewObjectFromPrototypeWithViewStack:@[]];
35 | }
36 |
37 | - (UIView*) createViewObjectFromPrototypeWithViewStack:(NSArray*)viewStack {
38 | UIView* view = _viewBuilderBlock([viewStack lastObject]);
39 | if( !view ) {
40 | ISSLogWarning(@"View builder block returned nil view");
41 | return nil;
42 | }
43 |
44 | if( [_propertyName iss_hasData] ) {
45 | BOOL propertyFound = NO;
46 | for(UIView* parentObject in viewStack.reverseObjectEnumerator) {
47 | if( [ISSViewHierarchyParser setViewObjectPropertyValue:view withName:_propertyName inParent:parentObject orFileOwner:nil silent:YES] ) {
48 | propertyFound = YES;
49 | break;
50 | }
51 | }
52 | if( !propertyFound && !self.implicitPropertyName ) {
53 | ISSLogWarning(@"Property '%@' not found in any ancestor of prototype!", _propertyName);
54 | }
55 | }
56 |
57 | viewStack = [viewStack arrayByAddingObject:view];
58 |
59 | for (ISSViewPrototype* subviewPrototype in self.subviewPrototypes) {
60 | UIView* subview = [subviewPrototype createViewObjectFromPrototypeWithViewStack:viewStack];
61 | if( subview && subviewPrototype.addAsSubView ) [view addSubview:subview];
62 | }
63 | return view;
64 | }
65 |
66 |
67 | #pragma mark - NSObject overrides
68 |
69 | - (NSString*) description {
70 | return [NSString stringWithFormat:@"ISSViewPrototype(%@)", _name ?: @"n/a"];
71 | }
72 |
73 | @end
74 |
--------------------------------------------------------------------------------
/InterfaCSS/Parser/ISSDefaultStyleSheetParser.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSDefaultStyleSheetParser.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSStyleSheetParser.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | @interface ISSDefaultStyleSheetParser : NSObject
15 |
16 | @end
17 |
18 |
19 | NS_ASSUME_NONNULL_END
20 |
--------------------------------------------------------------------------------
/InterfaCSS/Parser/ISSParser+CSS.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSParser+CSS.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSParser.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | @interface ISSParser (CSS)
15 |
16 | + (ISSParser*) iss_anythingButBasicControlChars:(NSUInteger)minCount;
17 |
18 | + (ISSParser*) iss_anythingButBasicControlCharsExceptColon:(NSUInteger)minCount;
19 |
20 | + (ISSParser*) iss_anythingButWhiteSpaceAndExtendedControlChars:(NSUInteger)minCount;
21 |
22 | + (NSCharacterSet*) iss_validIdentifierCharsSet;
23 |
24 | + (ISSParser*) iss_validIdentifierChars:(NSUInteger)minCount;
25 |
26 | + (ISSParser*) iss_validIdentifierChars:(NSUInteger)minCount onlyAlphpaAndUnderscore:(BOOL)onlyAlphpaAndUnderscore;
27 |
28 | + (ISSParser*) iss_logicalExpressionParser;
29 |
30 | + (ISSParser*) iss_mathExpressionParser;
31 |
32 | + (id) iss_parseMathExpression:(NSString*)value;
33 |
34 | + (ISSParser*) iss_parameterStringWithPrefixes:(NSArray*)prefixes;
35 |
36 | + (ISSParser*) iss_parameterStringWithPrefix:(nullable NSString*)prefix;
37 |
38 | + (ISSParser*) iss_parameterString;
39 |
40 | + (ISSParser*) iss_twoParameterFunctionParserWithName:(NSString*)name leftParameterParser:(ISSParser*)left rightParameterParser:(ISSParser*)right;
41 |
42 | + (ISSParser*) iss_singleParameterFunctionParserWithName:(NSString*)name parameterParser:(ISSParser*)parameterParser;
43 |
44 | + (ISSParser*) iss_singleParameterFunctionParserWithNames:(NSArray*)names parameterParser:(ISSParser*)parameterParser;
45 |
46 | + (ISSParser*) iss_parseLineUpToInvalidCharactersInString:(NSString*)invalid;
47 |
48 | + (ISSParser*) iss_commentParser;
49 |
50 | + (ISSParser*) iss_propertyPairParser:(BOOL)forVariableDefinition;
51 |
52 | @end
53 |
54 |
55 | NS_ASSUME_NONNULL_END
56 |
--------------------------------------------------------------------------------
/InterfaCSS/Parser/ISSParser.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSParser.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | // Inspired by Parcoa (https://github.com/brotchie/Parcoa).
5 | //
6 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
7 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
8 | //
9 |
10 | #import
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 |
15 | #define ISSParserSkipSpaceAndNewLines(input) while( i < input.length && [[NSCharacterSet whitespaceAndNewlineCharacterSet] characterIsMember:[input characterAtIndex:i]] ) i++;
16 |
17 |
18 | typedef struct ISSParserStatus {
19 | BOOL match;
20 | NSUInteger index;
21 | } ISSParserStatus;
22 |
23 |
24 | typedef id _Nonnull (^ISSParserBlock)(NSString* input, ISSParserStatus* status);
25 | typedef BOOL (^ISSParserMatchCondition)(unichar c);
26 | typedef id _Nonnull (^ISSParserTransformerBlock)(id value);
27 |
28 |
29 | /**
30 | * A simple and generic parser builder that uses an API similar to that of the Parcoa parser, but with a different and more performance focused implementation.
31 | */
32 | @interface ISSParser : NSObject
33 |
34 | + (ISSParser*) parserWithBlock:(ISSParserBlock)block andName:(NSString*)name;
35 |
36 | - (id) parse:(NSString*)string status:(ISSParserStatus*)status;
37 |
38 |
39 | #pragma mark - Combinators
40 |
41 | + (ISSParser*) choice:(NSArray*)parsers;
42 | - (ISSParser*) parserOr:(ISSParser*)parser;
43 |
44 | + (ISSParser*) sequential:(NSArray*)parsers;
45 |
46 | + (ISSParser*) optional:(ISSParser*)parser;
47 | + (ISSParser*) optional:(ISSParser*)parser defaultValue:(id)defaultValue;
48 |
49 | - (ISSParser*) then:(ISSParser*)parser;
50 |
51 | - (ISSParser*) keepLeft:(ISSParser*)parser;
52 |
53 | - (ISSParser*) keepRight:(ISSParser*)parser;
54 |
55 | - (ISSParser*) between:(ISSParser*)left and:(ISSParser*)right;
56 |
57 | - (ISSParser*) many;
58 | - (ISSParser*) many1;
59 | - (ISSParser*) manyActualValues;
60 | - (ISSParser*) many1ActualValues;
61 |
62 | - (ISSParser*) sepBy:(ISSParser*)delimiterParser;
63 | - (ISSParser*) sepBy1:(ISSParser*)delimiterParser;
64 | - (ISSParser*) sepByKeep:(ISSParser*)delimiterParser;
65 | - (ISSParser*) sepBy1Keep:(ISSParser*)delimiterParser;
66 |
67 | - (ISSParser*) concat;
68 | - (ISSParser*) concatMany;
69 | - (ISSParser*) concatMany1;
70 |
71 |
72 | #pragma mark - Transform
73 |
74 | - (ISSParser*) transform:(ISSParserTransformerBlock)transformer;
75 | - (ISSParser*) transform:(ISSParserTransformerBlock)transformer name:(NSString*)name;
76 |
77 |
78 | #pragma mark - Matchers
79 |
80 | + (ISSParser*) unichar:(unichar)c;
81 | + (ISSParser*) unichar:(unichar)c skipSpaces:(BOOL)skipSpaces;
82 |
83 | + (ISSParser*) charInSet:(NSCharacterSet*)set;
84 | + (ISSParser*) charInSet:(NSCharacterSet*)set skipSpaces:(BOOL)skipSpaces;
85 |
86 | + (ISSParser*) stringEQIgnoringCase:(NSString*)matcherString;
87 |
88 | + (ISSParser*) space;
89 | + (ISSParser*) spaces;
90 | + (ISSParser*) spaces:(NSUInteger)minCount;
91 | - (ISSParser*) skipSurroundingSpaces;
92 |
93 | + (ISSParser*) digit;
94 |
95 | + (ISSParser*) charMatching:(ISSParserMatchCondition)matcher skipSpaces:(BOOL)skipSpaces name:(NSString*)name;
96 |
97 |
98 | #pragma mark - Extractors
99 |
100 | + (ISSParser*) stringWithEscapesUpToUnichar:(unichar)c;
101 |
102 | + (ISSParser*) takeUntilInSet:(NSCharacterSet*)characterSet;
103 | + (ISSParser*) takeUntilInSet:(NSCharacterSet*)characterSet minCount:(NSUInteger)minCount;
104 |
105 | + (ISSParser*) takeWhileInSet:(NSCharacterSet*)characterSet;
106 | + (ISSParser*) takeWhileInSet:(NSCharacterSet*)characterSet minCount:(NSUInteger)minCount;
107 | + (ISSParser*) takeWhileInSet:(NSCharacterSet*)characterSet initialCharSet:(nullable NSCharacterSet*)initialCharSet minCount:(NSUInteger)minCount;
108 |
109 | + (ISSParser*) takeUntilChar:(unichar)character;
110 | + (ISSParser*) takeUntilChar:(unichar)character andSkip:(BOOL)skip minCount:(NSUInteger)minCount;
111 |
112 | + (ISSParser*) takeWhileCharMatches:(ISSParserMatchCondition)matcher initialCharMatcher:(nullable ISSParserMatchCondition)initialCharMatcher minCount:(NSUInteger)minCount skipPastEndChar:(BOOL)skipPastEndChar name:(NSString*)name;
113 |
114 | @end
115 |
116 |
117 | @interface ISSParserWrapper : ISSParser
118 | @property (nonatomic, strong) ISSParser* wrappedParser;
119 | @end
120 |
121 |
122 | NS_ASSUME_NONNULL_END
123 |
--------------------------------------------------------------------------------
/InterfaCSS/Parser/ISSStyleSheetParser.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSStyleSheetParser.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSPropertyDefinition.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 |
14 | @class ISSStyleSheet;
15 | @class ISSPropertyDefinition;
16 |
17 | /**
18 | * Protocol for stylesheet parser implementations.
19 | */
20 | @protocol ISSStyleSheetParser
21 |
22 | /**
23 | * Parses the specified stylesheet data into an array of `ISSPropertyDeclarations` objects.
24 | */
25 | - (nullable NSMutableArray*) parse:(NSString*)styleSheetData;
26 |
27 | /**
28 | * Transforms the specified value, using the specified propertyType. Any variable references in `value` will be replaced with their corresponding values.
29 | */
30 | - (nullable id) transformValue:(NSString*)value asPropertyType:(ISSPropertyType)propertyType;
31 |
32 | /**
33 | * Transforms the specified value, using the specified propertyType. Optionally replaces variable references in `value` with the corresponding values.
34 | */
35 | - (nullable id) transformValue:(NSString*)value asPropertyType:(ISSPropertyType)propertyType replaceVariableReferences:(BOOL)replaceVariableReferences;
36 |
37 | /**
38 | * Transforms the specified value, using the specified propertyDefinition. Any variable references in `value` will be replaced with their corresponding values.
39 | */
40 | - (nullable id) transformValue:(NSString*)value forPropertyDefinition:(ISSPropertyDefinition*)propertyDefinition;
41 |
42 | /**
43 | * Transforms the specified value, using the specified propertyDefinition. Optionally replaces variable references in `value` with the corresponding values.
44 | */
45 | - (nullable id) transformValue:(NSString*)value forPropertyDefinition:(ISSPropertyDefinition*)propertyDefinition replaceVariableReferences:(BOOL)replaceVariableReferences;
46 |
47 | @end
48 |
49 |
50 | NS_ASSUME_NONNULL_END
51 |
--------------------------------------------------------------------------------
/InterfaCSS/Parser/ISSViewHierarchyParser.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSViewHierarchyParser.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 | #import
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 |
15 | @class ISSRootView;
16 | @class ISSViewHierarchyParser;
17 |
18 |
19 | extern NSString* const ISSViewDefinitionFileAttributeId;
20 | extern NSString* const ISSViewDefinitionFileAttributeClass;
21 | extern NSString* const ISSViewDefinitionFileAttributeProperty;
22 | extern NSString* const ISSViewDefinitionFileAttributePrototype;
23 | extern NSString* const ISSViewDefinitionFileAttributePrototypeScope;
24 | extern NSString* const ISSViewDefinitionFileAttributeAddAsSubview;
25 | extern NSString* const ISSViewDefinitionFileAttributeImplementationClass;
26 | extern NSString* const ISSViewDefinitionFileAttributeCollectionViewLayoutClass;
27 |
28 |
29 | /**
30 | * Protocol for view definition file parser delegates.
31 | */
32 | @protocol ISSViewHierarchyParserDelegate
33 |
34 | /**
35 | * Called after a view defined in the view definition file has been created. The `attributes` parameter will contain all the attributes specified on the XML tag
36 | * (canonical names will be used for standard InterfaCSS attributes, see `ISSViewDefinitionFileAttributeId` etc).
37 | *
38 | * Note: for prototype views, this callback will be invoked when a view is created from the prototype (i.e. using `-[InterfaCSS viewFromPrototypeWithName:]`),
39 | * and not during parsing of the view definition file.
40 | */
41 | - (void) viewHierarchyParser:(ISSViewHierarchyParser*)viewHierarchyParser didBuildView:(UIView*)view parent:(nullable UIView*)parentView elementName:(NSString*)elementName attributes:(NSDictionary*)attributes;
42 |
43 | @end
44 |
45 |
46 | /**
47 | * Parser implementation for XML based view definition files.
48 | */
49 | @interface ISSViewHierarchyParser : NSObject
50 |
51 | @property (nonatomic, readonly, weak, nullable) id fileOwner;
52 | @property (nonatomic, readonly, weak, nullable) id delegate;
53 |
54 |
55 | /**
56 | * Parses a view hierarchy from the specified file data. Specifying a value for the `fileOwner` will enable setting properties identified in the file.
57 | * If the fileOwner implements the `ISSViewHierarchyParserDelegate` protocol, it will also be used as the delegate.
58 | */
59 | + (nullable ISSRootView*) parseViewHierarchyFromData:(NSData*)fileData fileOwner:(nullable id)fileOwner wrapRoot:(BOOL)wrapRoot;
60 |
61 | /**
62 | * Parses a view hierarchy from the specified file data. Specifying a value for the `fileOwner` will enable setting properties identified in the file.
63 | * Specifying a value for the `delegate` will enable post processing of views and XML attributes.
64 | */
65 | + (nullable ISSRootView*) parseViewHierarchyFromData:(NSData*)fileData fileOwner:(nullable id)fileOwner wrapRoot:(BOOL)wrapRoot delegate:(nullable id)delegate;
66 |
67 | /**
68 | * Utility method for setting the value of a property in either a parent element or a file owner object.
69 | */
70 | + (BOOL) setViewObjectPropertyValue:(nullable id)value withName:(NSString*)propertyName inParent:(nullable id)parent orFileOwner:(nullable id)fileOwner silent:(BOOL)silent;
71 |
72 | /**
73 | * Returns the view class that corresponds to the specified XML element name.
74 | */
75 | - (nullable Class) elementNameToViewClass:(NSString*)elementName;
76 |
77 | @end
78 |
79 |
80 | NS_ASSUME_NONNULL_END
81 |
--------------------------------------------------------------------------------
/InterfaCSS/UI/ISSLayoutContextView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSLayoutContextView.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @class ISSLayout;
13 |
14 |
15 | NS_ASSUME_NONNULL_BEGIN
16 |
17 |
18 | typedef void (^ISSLayoutProcessingBlock)(UIView* view, ISSLayout* _Nullable layout);
19 |
20 |
21 | /**
22 | * ISSLayoutContextView handles processing of any `ISSLayout`s defined in subviews. To enable use of `ISSLayout` is a view controller, use this class
23 | * (or a subclass such as `ISSRootView`) as the root view .
24 | */
25 | @interface ISSLayoutContextView : UIView
26 |
27 | /** Pre processing block for any additional customization of layout before layout is resolved. */
28 | @property (nonatomic, copy, nullable) ISSLayoutProcessingBlock layoutPreProcessingBlock;
29 |
30 | /** Post processing block for any additional customization of frame after layout has been resolved. */
31 | @property (nonatomic, copy, nullable) ISSLayoutProcessingBlock layoutPostProcessingBlock;
32 |
33 | @end
34 |
35 |
36 | NS_ASSUME_NONNULL_END
37 |
--------------------------------------------------------------------------------
/InterfaCSS/UI/ISSLayoutContextView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ISSLayoutContextView.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSLayoutContextView.h"
10 |
11 | #import "ISSUIElementDetails.h"
12 | #import "ISSLayout.h"
13 |
14 |
15 | @implementation ISSLayoutContextView {
16 | BOOL didLayoutOnce;
17 | }
18 |
19 | - (void) setupSubviewDetailsWithLayouts:(NSMutableArray*)subviewsDetails andResolvedElements:(NSMutableDictionary*)resolvedElements forView:(UIView*)view {
20 | ISSUIElementDetails* details = [[InterfaCSS sharedInstance] detailsForUIElement:view];
21 |
22 | // If element has layout - add to array
23 | if( details.layout ) {
24 | [subviewsDetails addObject:details];
25 | }
26 |
27 | // Add elementId to elementDetails mapping to resolvedElements dictionary - but only do it for elements without layout here (i.e. elements with known frames)
28 | if( details.elementId && !details.layout ) {
29 | resolvedElements[details.elementId] = details;
30 | }
31 |
32 | // Drill down
33 | for (UIView* subview in view.subviews) {
34 | [self setupSubviewDetailsWithLayouts:subviewsDetails andResolvedElements:resolvedElements forView:subview];
35 | }
36 | }
37 |
38 | - (NSMutableArray*) resolveLayouts:(NSArray*)subviewsDetails resolvedElements:(NSMutableDictionary*)resolvedElements layoutGuideInsets:(UIEdgeInsets)layoutGuideInsets shouldContinueResolve:(BOOL*)shouldContinueResolve {
39 | BOOL didResolveElements = NO;
40 | NSMutableArray* unresolved = [NSMutableArray array];
41 |
42 | for(ISSUIElementDetails* elementDetails in subviewsDetails) {
43 | // Get layout for element
44 | ISSLayout* layout = elementDetails.layout;
45 |
46 | // Execute layout pre processing block, to enable additional customization of layout before layout is resolved
47 | if( self.layoutPreProcessingBlock ) {
48 | self.layoutPreProcessingBlock(elementDetails.view, elementDetails.layout);
49 | }
50 |
51 | // Attempt resolve of layout to frame
52 | if( [layout resolveRectForView:elementDetails.view withResolvedElements:resolvedElements andLayoutGuideInsets:(UIEdgeInsets)layoutGuideInsets] ) {
53 | // Execute layout post processing block, to enable additional customization of frame
54 | if( self.layoutPostProcessingBlock ) {
55 | self.layoutPostProcessingBlock(elementDetails.view, elementDetails.layout);
56 | }
57 | if( elementDetails.elementId ) {
58 | resolvedElements[elementDetails.elementId] = elementDetails;
59 | }
60 | didResolveElements = YES;
61 | } else {
62 | [unresolved addObject:elementDetails];
63 | }
64 | }
65 |
66 | *shouldContinueResolve = didResolveElements && unresolved.count > 0;
67 |
68 | return unresolved;
69 | }
70 |
71 | - (void) didMoveToSuperview {
72 | [super didMoveToSuperview];
73 | if( !self.superview ) didLayoutOnce = NO;
74 | }
75 |
76 | - (void) layoutSubviews {
77 | [super layoutSubviews];
78 |
79 | ISSUIElementDetails* selfDetails = [[InterfaCSS sharedInstance] detailsForUIElement:self];
80 |
81 | if( !didLayoutOnce ) { // Make sure styling is applied before proceeding (this is not just important for ISSLayout, but for the use of relative ISSRectValue objects as well)
82 | if ( ![InterfaCSS sharedInstance].useManualStyling ) {
83 | [self applyStylingISS];
84 | }
85 | didLayoutOnce = YES;
86 | }
87 |
88 | // Get top and bottom layout guides (thank you Apple)
89 | UIViewController* parentViewController = selfDetails.closestViewController;
90 | id topLayoutGuide = [parentViewController respondsToSelector:@selector(topLayoutGuide)] ? parentViewController.topLayoutGuide : nil;
91 | id bottomLayoutGuide = [parentViewController respondsToSelector:@selector(bottomLayoutGuide)] ? parentViewController.bottomLayoutGuide : nil;
92 | UIEdgeInsets layoutGuideInsets = UIEdgeInsetsMake(topLayoutGuide.length, 0, bottomLayoutGuide.length, 0);
93 |
94 | // Gather up details for all views with layouts, and setup mappings of elementId to element details
95 | NSMutableArray* unresolvedElementDetails = [NSMutableArray array];
96 | NSMutableDictionary* resolvedElements = [NSMutableDictionary dictionary];
97 | [self setupSubviewDetailsWithLayouts:unresolvedElementDetails andResolvedElements:resolvedElements forView:self];
98 |
99 | // Make several passes over elementDetails array, to make sure all layouts are resolved
100 | BOOL shouldContinueResolve = NO;
101 | do {
102 | unresolvedElementDetails = [self resolveLayouts:unresolvedElementDetails resolvedElements:resolvedElements layoutGuideInsets:layoutGuideInsets shouldContinueResolve:&shouldContinueResolve];
103 | } while (shouldContinueResolve);
104 |
105 | if( unresolvedElementDetails.count ) {
106 | ISSLogWarning(@"Still %d elements with unresolved layouts after execution of layoutSubviews!", unresolvedElementDetails.count);
107 | NSMutableArray* unresolvedLayoutsDescriptions = [NSMutableArray array];
108 | for(ISSUIElementDetails* details in unresolvedElementDetails) {
109 | [unresolvedLayoutsDescriptions addObject:[NSString stringWithFormat:@"%@: %@", details, details.layout]];
110 | }
111 | ISSLogDebug(@"Elements with unresolved layouts: %@", unresolvedLayoutsDescriptions);
112 | }
113 | }
114 |
115 | @end
116 |
--------------------------------------------------------------------------------
/InterfaCSS/UI/ISSRootView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSRootView.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSLayoutContextView.h"
10 |
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 |
15 | /**
16 | * UIView subclass that makes sure that styles are (re)applied every time the view is moved to a new superview, window or when it's frame is modified. Useful
17 | * as a the root view of a view controller, or for views that you don't add to the view hierarchy yourself (for instance cells or header views in table
18 | * views etc).
19 | */
20 | @interface ISSRootView : ISSLayoutContextView
21 |
22 | @property (nonatomic, weak, nullable) UIView* wrappedRootView;
23 |
24 | /**
25 | * Creates an ISSRootView that will serve as a wrapper view for the specified view.
26 | */
27 | - (id) initWithView:(UIView*)view;
28 |
29 | @end
30 |
31 |
32 | NS_ASSUME_NONNULL_END
33 |
--------------------------------------------------------------------------------
/InterfaCSS/UI/ISSRootView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ISSRootView.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSRootView.h"
10 |
11 | #import "UIView+InterfaCSS.h"
12 | #import "ISSRectValue.h"
13 |
14 |
15 | @implementation ISSRootView
16 |
17 | - (void) commonInitWithView:(UIView*)view {
18 | self.wrappedRootView = view;
19 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
20 | }
21 |
22 | - (id) init {
23 | if ( self = [super init] ) {
24 | [self commonInitWithView:nil];
25 | self.frame = [[ISSRectValue windowRect] rectForView:self];
26 | }
27 | return self;
28 | }
29 |
30 | - (id) initWithFrame:(CGRect)frame {
31 | if ( self = [super initWithFrame:frame] ) {
32 | [self commonInitWithView:nil];
33 | }
34 | return self;
35 | }
36 |
37 | - (id) initWithView:(UIView*)view {
38 | if ( self = [super init] ) {
39 | [self commonInitWithView:view];
40 | self.frame = [[ISSRectValue windowRect] rectForView:self];
41 | }
42 | return self;
43 | }
44 |
45 | - (void) setWrappedRootView:(UIView*)wrappedRootView {
46 | if( wrappedRootView == _wrappedRootView ) return;
47 | [_wrappedRootView removeFromSuperview];
48 | _wrappedRootView = wrappedRootView;
49 | if( _wrappedRootView ) [self addSubview:_wrappedRootView];
50 | }
51 |
52 | - (void) setFrame:(CGRect)frame {
53 | BOOL frameModified = !CGRectEqualToRect(self.frame, frame);
54 | [super setFrame:frame];
55 | _wrappedRootView.frame = self.bounds;
56 | if( frameModified && ![InterfaCSS sharedInstance].useManualStyling ) [self scheduleApplyStylingISS]; // Note: This is only really needed if element contains relative ISSRectValue/ISSPointValue
57 | }
58 |
59 | - (void) didMoveToSuperview {
60 | [super didMoveToSuperview];
61 | if( self.superview && ![InterfaCSS sharedInstance].useManualStyling ) [self scheduleApplyStylingISS];
62 | }
63 |
64 | - (void) didMoveToWindow {
65 | [super didMoveToWindow];
66 | if( self.window && ![InterfaCSS sharedInstance].useManualStyling ) [self applyStylingISS];
67 | }
68 |
69 | @end
70 |
--------------------------------------------------------------------------------
/InterfaCSS/UI/UICollectionView+InterfaCSS.h:
--------------------------------------------------------------------------------
1 | //
2 | // UICollectionView+InterfaCSS.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | NS_ASSUME_NONNULL_BEGIN
10 |
11 | /**
12 | * Category that adds InterfaCSS integration to `UICollectionView`.
13 | */
14 | @interface UICollectionView (InterfaCSS)
15 |
16 | /**
17 | * Dequeues a collection view cell (using `-[UICollectionView dequeueReusableCellWithReuseIdentifier:forIndexPath:]`) and associates it with the specified indexPath.
18 | * This is necessary when using structural pseudo class selectors for table view cell.
19 | */
20 | - (id) dequeueReusableCellWithReuseIdentifierISS:(NSString*)reuseIdentifier forIndexPath:(NSIndexPath*)indexPath;
21 |
22 | /**
23 | * Dequeues a collection view cell (using `dequeueReusableCellWithReuseIdentifierISS:forIndexPath:`), and initializes it from a registered prototype.
24 | */
25 | - (id) dequeueReusablePrototypeCellWithReuseIdentifierISS:(NSString*)prototypeName forIndexPath:(NSIndexPath*)indexPath;
26 |
27 | /**
28 | * Dequeues a collection view supplementary view (using `-[UICollectionView dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:]`) and associates it with the specified indexPath.
29 | * This is necessary when using structural pseudo class selectors for table view cell.
30 | */
31 | - (id) dequeueReusableSupplementaryViewOfKindISS:(NSString*)elementKind withReuseIdentifier:(NSString*)reuseIdentifier forIndexPath:(NSIndexPath*)indexPath;
32 |
33 | /**
34 | * Dequeues a collection view supplementary view (using `dequeueReusableSupplementaryViewOfKindISS:withReuseIdentifier:forIndexPath:`), and initializes it from a registered prototype.
35 | */
36 | - (id) dequeueReusableSupplementaryPrototypeViewOfKindISS:(NSString*)elementKind withReuseIdentifier:(NSString*)prototypeName forIndexPath:(NSIndexPath*)indexPath;
37 |
38 | @end
39 |
40 | NS_ASSUME_NONNULL_END
41 |
--------------------------------------------------------------------------------
/InterfaCSS/UI/UICollectionView+InterfaCSS.m:
--------------------------------------------------------------------------------
1 | //
2 | // UICollectionView+InterfaCSS.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "UICollectionView+InterfaCSS.h"
10 |
11 | #import "ISSUIElementDetails.h"
12 | #import "UIView+ISSPrototypeReusableView.h"
13 |
14 | @implementation UICollectionView (InterfaCSS)
15 |
16 | - (id) dequeueReusableCellWithReuseIdentifierISS:(NSString*)reuseIdentifier forIndexPath:(NSIndexPath*)indexPath {
17 | id cell = [self dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
18 | ISSUIElementDetails* elementDetails = [[InterfaCSS sharedInstance] detailsForUIElement:cell];
19 | elementDetails.additionalDetails[ISSIndexPathKey] = indexPath;
20 | return cell;
21 | }
22 |
23 | - (id) dequeueReusablePrototypeCellWithReuseIdentifierISS:(NSString*)prototypeName forIndexPath:(NSIndexPath*)indexPath {
24 | UIView* cell = [self dequeueReusableCellWithReuseIdentifierISS:prototypeName forIndexPath:indexPath];
25 | [cell setupViewFromPrototypeRegisteredInViewISS:self];
26 | return cell;
27 | }
28 |
29 | - (id) dequeueReusableSupplementaryViewOfKindISS:(NSString*)elementKind withReuseIdentifier:(NSString*)reuseIdentifier forIndexPath:(NSIndexPath*)indexPath {
30 | id cell = [self dequeueReusableSupplementaryViewOfKind:elementKind withReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
31 | ISSUIElementDetails* elementDetails = [[InterfaCSS sharedInstance] detailsForUIElement:cell];
32 | elementDetails.additionalDetails[ISSIndexPathKey] = indexPath;
33 | return cell;
34 | }
35 |
36 | - (id) dequeueReusableSupplementaryPrototypeViewOfKindISS:(NSString*)elementKind withReuseIdentifier:(NSString*)prototypeName forIndexPath:(NSIndexPath*)indexPath {
37 | UIView* cell = [self dequeueReusableSupplementaryViewOfKindISS:elementKind withReuseIdentifier:prototypeName forIndexPath:indexPath];
38 | [cell setupViewFromPrototypeRegisteredInViewISS:self];
39 | return cell;
40 | }
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/InterfaCSS/UI/UITableView+InterfaCSS.h:
--------------------------------------------------------------------------------
1 | //
2 | // UITableView+InterfaCSS.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 | #import
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 | /**
15 | * Category that adds InterfaCSS integration to `UITableView`.
16 | */
17 | @interface UITableView (InterfaCSS)
18 |
19 | /**
20 | * Dequeues a table view cell (using `-[UITableView dequeueReusableCellWithIdentifier:forIndexPath:]`) and associates it with the specified indexPath.
21 | * This is necessary when using structural pseudo class selectors for table view cell.
22 | */
23 | - (id) dequeueReusableCellWithIdentifierISS:(NSString*)reuseIdentifier forIndexPath:(NSIndexPath*)indexPath;
24 |
25 | /**
26 | * Dequeues a table view cell (using `dequeueReusableCellWithIdentifierISS:forIndexPath:`), and initializes it from a registered prototype.
27 | */
28 | - (id) dequeueReusablePrototypeCellWithIdentifierISS:(NSString*)prototypeName forIndexPath:(NSIndexPath*)indexPath;
29 |
30 | /**
31 | * Dequeues a table view header/footer (using `-[UITableView dequeueReusableHeaderFooterViewWithIdentifier:]`), or creates one based on the prototype with the
32 | * specified name, using the method `-[InterfaCSS viewFromPrototypeWithName:]`.
33 | */
34 | - (id) dequeueReusablePrototypeHeaderFooterViewWithIdentifierISS:(NSString*)prototypeName;
35 |
36 | @end
37 |
38 | NS_ASSUME_NONNULL_END
39 |
--------------------------------------------------------------------------------
/InterfaCSS/UI/UITableView+InterfaCSS.m:
--------------------------------------------------------------------------------
1 | //
2 | // UITableView+InterfaCSS.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "UITableView+InterfaCSS.h"
10 |
11 | #import "InterfaCSS.h"
12 | #import "ISSUIElementDetails.h"
13 | #import "UIView+ISSPrototypeReusableView.h"
14 |
15 | @implementation UITableView (InterfaCSS)
16 |
17 | - (id) dequeueReusableCellWithIdentifierISS:(NSString*)reuseIdentifier forIndexPath:(NSIndexPath*)indexPath {
18 | id cell = [self dequeueReusableCellWithIdentifier:reuseIdentifier forIndexPath:indexPath];
19 | ISSUIElementDetails* elementDetails = [[InterfaCSS sharedInstance] detailsForUIElement:cell];
20 | elementDetails.additionalDetails[ISSIndexPathKey] = indexPath;
21 | return cell;
22 | }
23 |
24 | - (id) dequeueReusablePrototypeCellWithIdentifierISS:(NSString*)prototypeName forIndexPath:(NSIndexPath*)indexPath {
25 | UIView* cell = [self dequeueReusableCellWithIdentifierISS:prototypeName forIndexPath:indexPath];
26 | [cell setupViewFromPrototypeRegisteredInViewISS:self];
27 | return cell;
28 | }
29 |
30 | - (id) dequeueReusablePrototypeHeaderFooterViewWithIdentifierISS:(NSString*)prototypeName {
31 | UIView* view = [self dequeueReusableHeaderFooterViewWithIdentifier:prototypeName];
32 | [view setupViewFromPrototypeRegisteredInViewISS:self];
33 | return view;
34 | }
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/InterfaCSS/UI/UIView+ISSPrototypeReusableView.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+ISSPrototypeReusableView.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 | #import
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 | @interface UIView (ISSPrototypeReusableView)
15 |
16 | @property (nonatomic) BOOL initializedFromPrototypeISS;
17 |
18 | - (void) setupViewFromPrototypeISS;
19 | - (void) setupViewFromPrototypeRegisteredInViewISS:(nullable UIView*)registeredInView;
20 |
21 | @end
22 |
23 | NS_ASSUME_NONNULL_END
24 |
--------------------------------------------------------------------------------
/InterfaCSS/UI/UIView+ISSPrototypeReusableView.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+ISSPrototypeReusableView.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "UIView+ISSPrototypeReusableView.h"
10 |
11 | #import "InterfaCSS.h"
12 | #import "ISSUIElementDetails.h"
13 |
14 |
15 | @implementation UIView (ISSPrototypeReusableView)
16 |
17 | - (BOOL) initializedFromPrototypeISS {
18 | ISSUIElementDetails* elementDetails = [[InterfaCSS sharedInstance] detailsForUIElement:self];
19 | NSNumber* cellInitializedISS = elementDetails.additionalDetails[ISSPrototypeViewInitializedKey];
20 | return [cellInitializedISS boolValue];
21 | }
22 |
23 | - (void) setInitializedFromPrototypeISS:(BOOL)initializedFromPrototype {
24 | ISSUIElementDetails* elementDetails = [[InterfaCSS sharedInstance] detailsForUIElement:self];
25 | elementDetails.additionalDetails[ISSPrototypeViewInitializedKey] = @(initializedFromPrototype);
26 | }
27 |
28 | - (void) setupViewFromPrototypeISS {
29 | [self setupViewFromPrototypeRegisteredInViewISS:nil];
30 | }
31 |
32 | - (void) setupViewFromPrototypeRegisteredInViewISS:(UIView*)registeredInView {
33 | NSString* prototypeName = nil;
34 | if( [self respondsToSelector:@selector(reuseIdentifier)] ) {
35 | prototypeName = [(id)self performSelector:@selector(reuseIdentifier)];
36 | }
37 |
38 | if( prototypeName && !self.initializedFromPrototypeISS ) {
39 | [[InterfaCSS sharedInstance] viewFromPrototypeWithName:prototypeName registeredInElement:registeredInView prototypeParent:self];
40 | self.initializedFromPrototypeISS = YES;
41 | }
42 | }
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/ISSDateUtils.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSDateUtils.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 |
12 | @interface ISSDateUtils : NSObject
13 |
14 | + (NSDate*) parseHttpDate:(NSString*)string;
15 |
16 | + (NSString*) formatHttpDate:(NSDate*)date;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/ISSDateUtils.m:
--------------------------------------------------------------------------------
1 | //
2 | // ISSDateUtils.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSDateUtils.h"
10 |
11 |
12 | static NSDateFormatter* rfc1123DateFormatter = nil;
13 | static NSDateFormatter* rfc850DateFormatter = nil;
14 | static NSDateFormatter* asctimeFormatter = nil;
15 |
16 |
17 | @implementation ISSDateUtils
18 |
19 | + (NSDateFormatter*) httpDateFormatterWithFormat:(NSString*)format {
20 | NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
21 | dateFormatter.dateFormat = format;
22 | dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
23 | dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
24 | return dateFormatter;
25 | }
26 |
27 | + (NSDate*) parseHttpDate:(NSString*)string {
28 | NSDate* date = nil;
29 |
30 | static dispatch_once_t rfc1123DateFormatterOnceToken;
31 | dispatch_once(&rfc1123DateFormatterOnceToken, ^{
32 | rfc1123DateFormatter = [self httpDateFormatterWithFormat:@"EEE',' dd MMM yyyy HH':'mm':'ss z"];
33 | });
34 | date = [rfc1123DateFormatter dateFromString:string];
35 |
36 | if ( !date ) {
37 | static dispatch_once_t rfc850DateFormatterOnceToken;
38 | dispatch_once(&rfc850DateFormatterOnceToken, ^{
39 | rfc850DateFormatter = [self httpDateFormatterWithFormat:@"EEEE',' dd'-'MMM'-'yy HH':'mm':'ss z"];
40 | });
41 | date = [rfc850DateFormatter dateFromString:string];
42 |
43 | if ( !date ) {
44 | static dispatch_once_t asctimeFormatterOnceToken;
45 | dispatch_once(&asctimeFormatterOnceToken, ^{
46 | asctimeFormatter = [self httpDateFormatterWithFormat:@"EEE MMM d HH':'mm':'ss yyyy"];
47 | });
48 | date = [asctimeFormatter dateFromString:string];
49 | }
50 | }
51 |
52 | return date;
53 | }
54 |
55 | + (NSString*) formatHttpDate:(NSDate*)date {
56 | if ( !rfc1123DateFormatter ) rfc1123DateFormatter = [self httpDateFormatterWithFormat:@"EEE',' dd MMM yyyy HH':'mm':'ss z"];
57 | return [rfc1123DateFormatter stringFromDate:date];
58 | }
59 |
60 | @end
--------------------------------------------------------------------------------
/InterfaCSS/Util/ISSDownloadableResource.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSDownloadableResource.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSUpdatableValue.h"
10 |
11 |
12 | extern NSString* const ISSResourceDownloadedNotification;
13 | extern NSString* const ISSResourceDownloadFailedNotification;
14 |
15 |
16 | @interface ISSDownloadableResource : ISSUpdatableValue
17 |
18 | @property (nonatomic, readonly) NSURL* resourceURL;
19 | @property (nonatomic, weak, readonly) id cachedResource;
20 |
21 | + (instancetype) downloadableFontWithURL:(NSURL*)url;
22 | + (instancetype) downloadableImageWithURL:(NSURL*)url;
23 |
24 | + (void) clearCaches;
25 |
26 | - (void) download:(BOOL)force;
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/ISSDownloadableResource.m:
--------------------------------------------------------------------------------
1 | //
2 | // ISSDownloadableResource.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "ISSDownloadableResource.h"
10 |
11 | #import
12 |
13 | #import "NSObject+ISSLogSupport.h"
14 |
15 |
16 | NSString* const ISSResourceDownloadedNotification = @"ISSResourceDownloadedNotification";
17 | NSString* const ISSResourceDownloadFailedNotification = @"ISSResourceDownloadFailedNotification";
18 |
19 |
20 | static NSMapTable* activeDownloadableResources;
21 | static NSCache* downloadableResourceCache;
22 |
23 |
24 | @interface ISSDownloadableResource()
25 |
26 | @property (nonatomic) BOOL downloading;
27 | @property (nonatomic, weak, readwrite) id cachedResource;
28 |
29 | - (id) resourceWithData:(NSData*)data;
30 |
31 | @end
32 |
33 |
34 | @interface ISSDownloadableFontResource : ISSDownloadableResource
35 |
36 | @property (nonatomic, strong) id loadedFont;
37 |
38 | @end
39 | @implementation ISSDownloadableFontResource
40 |
41 | - (id) resourceWithData:(NSData*)data {
42 | if( self.loadedFont ) CTFontManagerUnregisterGraphicsFont((__bridge CGFontRef)self.loadedFont, nil);
43 |
44 | CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
45 | CGFontRef font = CGFontCreateWithDataProvider(provider);
46 | self.loadedFont = (__bridge id)font;
47 | NSString* fontName = nil;
48 | if ( font ) {
49 | CFErrorRef error;
50 | if ( CTFontManagerRegisterGraphicsFont(font, &error) ) {
51 | fontName = CFBridgingRelease(CGFontCopyPostScriptName(font));
52 | [self iss_logDebug:@"Loaded font: %@", fontName];
53 | }
54 | CFRelease(font);
55 | }
56 | CFRelease(provider);
57 |
58 | if ( fontName ) return fontName;
59 | else {
60 | [self iss_logWarning:@"Failed to create font from downloaded data!"];
61 | return [UIFont systemFontOfSize:1].fontName;
62 | }
63 | }
64 |
65 | @end
66 |
67 |
68 | @interface ISSDownloadableImageResource : ISSDownloadableResource
69 | @end
70 | @implementation ISSDownloadableImageResource
71 |
72 | - (id) resourceWithData:(NSData*)data {
73 | UIImage* image = [UIImage imageWithData:data];
74 | if( image ) return image;
75 | else {
76 | [self iss_logWarning:@"Failed to create image from downloaded data!"];
77 | return [[UIImage alloc] init];
78 | }
79 | }
80 |
81 | @end
82 |
83 |
84 | @implementation ISSDownloadableResource
85 |
86 | + (void) load {
87 | downloadableResourceCache = [[NSCache alloc] init];
88 | activeDownloadableResources = [NSMapTable strongToWeakObjectsMapTable];
89 | }
90 |
91 | + (void) clearCaches {
92 | [downloadableResourceCache removeAllObjects];
93 | }
94 |
95 | + (instancetype) downloadableFontWithURL:(NSURL*)url {
96 | return [ISSDownloadableFontResource downloadableResourceWithURL:url];
97 | }
98 |
99 | + (instancetype) downloadableImageWithURL:(NSURL*)url {
100 | return [ISSDownloadableImageResource downloadableResourceWithURL:url];
101 | }
102 |
103 | + (instancetype) downloadableResourceWithURL:(NSURL*)url {
104 | ISSDownloadableResource* resource = [activeDownloadableResources objectForKey:url];
105 | if( resource ) return resource;
106 | else return [[self alloc] initWithURL:url];
107 | }
108 |
109 | - (instancetype) initWithURL:(NSURL*)url {
110 | if( self = [super init] ) {
111 | _resourceURL = url;
112 | [activeDownloadableResources setObject:self forKey:url];
113 | }
114 | return self;
115 | }
116 |
117 | - (id) cachedResource {
118 | return [downloadableResourceCache objectForKey:self.resourceURL];
119 | }
120 |
121 | - (void) setCachedResource:(id)cachedResource {
122 | if( cachedResource ) {
123 | [downloadableResourceCache setObject:cachedResource forKey:self.resourceURL];
124 | } else {
125 | [downloadableResourceCache removeObjectForKey:self.resourceURL];
126 | }
127 | }
128 |
129 | - (void) download:(BOOL)force {
130 | if( !force && (self.downloading || self.cachedResource) ) return;
131 |
132 | self.downloading = YES;
133 |
134 | NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:self.resourceURL];
135 | if( force ) {
136 | [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
137 | }
138 |
139 | __weak ISSDownloadableResource* weakSelf = self;
140 | NSURLSession* urlSession = [NSURLSession sharedSession];
141 | NSURLSessionDataTask* dataDownloadTask = [urlSession dataTaskWithRequest:request completionHandler:^(NSData* data, NSURLResponse* response, NSError* error) {
142 | dispatch_async(dispatch_get_main_queue(), ^{
143 | self.downloading = NO;
144 | __strong ISSDownloadableResource* self = weakSelf;
145 | if( error || !data ) {
146 | [self iss_logDebug:@"Error downloading resource - %@", error];
147 | [[NSNotificationCenter defaultCenter] postNotificationName:ISSResourceDownloadFailedNotification object:weakSelf];
148 | } else {
149 | [self iss_logDebug:@"Resource downloaded (%d bytes)", data.length];
150 | __strong id cachedResource = [self resourceWithData:data]; // Store in local strong ref, just to make sure cachedResource doesn't go away (since it's stored as weak ref in NSMapTable)
151 | self.cachedResource = cachedResource;
152 | [[NSNotificationCenter defaultCenter] postNotificationName:ISSResourceDownloadedNotification object:weakSelf];
153 | [self valueUpdated];
154 | }
155 | });
156 | }];
157 | [dataDownloadTask resume];
158 | }
159 |
160 | - (id) resourceWithData:(NSData*)data { return nil; }
161 |
162 |
163 | #pragma mark - ISSUpdatableValue
164 |
165 | - (void) requestUpdate {
166 | [self download:NO];
167 | }
168 |
169 | - (id) lastValue {
170 | return self.cachedResource;
171 | }
172 |
173 |
174 | #pragma mark - NSObject overrides
175 |
176 | - (BOOL) isEqual:(id)object {
177 | if( object == self ) return YES;
178 | else if( [object isKindOfClass:ISSDownloadableResource.class] ) {
179 | return [self.resourceURL isEqual:((ISSDownloadableResource*)object).resourceURL];
180 | }
181 | return NO;
182 | }
183 |
184 | - (NSUInteger) hash {
185 | return self.resourceURL.hash;
186 | }
187 |
188 | - (NSString*) description {
189 | if( self.cachedResource ) return [NSString stringWithFormat:@"%@[%@, cachedResource: %@]", NSStringFromClass(self.class), self.resourceURL.lastPathComponent, self.cachedResource];
190 | else return [NSString stringWithFormat:@"%@[%@]", NSStringFromClass(self.class), self.resourceURL.lastPathComponent];
191 | }
192 |
193 | @end
194 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/ISSRefreshableResource.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSRefreshableResource.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 |
12 | extern NSString* const ISSRefreshableResourceErrorDomain;
13 |
14 |
15 | typedef void (^ISSRefreshableResourceLoadCompletionBlock)(BOOL success, NSString* responseString, NSError* error);
16 |
17 |
18 | @interface ISSRefreshableResource : NSObject
19 |
20 | @property (nonatomic, readonly) NSURL* resourceURL;
21 | @property (nonatomic, readonly) BOOL usingLocalFileChangeMonitoring;
22 | @property (nonatomic, readonly) BOOL hasErrorOccurred;
23 | @property (nonatomic, readonly) NSError* lastError;
24 |
25 |
26 | - (instancetype) initWithURL:(NSURL*)url;
27 |
28 | - (void) startMonitoringLocalFileChanges:(void (^)(ISSRefreshableResource*))callbackBlock;
29 | - (void) endMonitoringLocalFileChanges;
30 |
31 | - (void) refreshWithCompletionHandler:(ISSRefreshableResourceLoadCompletionBlock)completionHandler force:(BOOL)force;
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/ISSRuntimeIntrospectionUtils.h:
--------------------------------------------------------------------------------
1 | //
2 | // ISSRuntimeIntrospectionUtils.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 |
12 | @interface ISSRuntimeIntrospectionUtils : NSObject
13 |
14 | + (void) clearCaches;
15 |
16 | + (SEL) findSelectorWithCaseInsensitiveName:(NSString*)name inClass:(Class)clazz;
17 |
18 | + (void) invokeSingleObjectArgumentSelector:(SEL)selector inObject:(id)object parameter:(id)parameter;
19 |
20 | + (NSSet*) propertyNamesForClass:(Class)class;
21 |
22 | + (BOOL) doesClass:(Class)clazz havePropertyWithName:(NSString*)propertyName;
23 |
24 | + (BOOL) doesClassOrSuperClass:(Class)clazz havePropertyWithName:(NSString*)propertyName excludingRootClass:(Class)rootClass;
25 |
26 | + (NSString*) actualPropertyNameForCaseInsensitiveName:(NSString*)caseInsensitivePropertyName inClass:(Class)class;
27 |
28 | + (NSString*) validKeyPathForCaseInsensitivePath:(NSString*)caseInsensitiveKeyPath inClass:(Class)class;
29 |
30 | + (NSInvocation*) findSetterForProperty:(NSString*)propertyName inObject:(id)object;
31 |
32 | + (BOOL) invokeSetterForProperty:(NSString*)propertyName withValue:(id)value inObject:(id)object;
33 |
34 | + (id) invokeGetterForKeyPath:(NSString*)keyPath inObject:(id)object;
35 |
36 | + (id) invokeGetterForProperty:(NSString*)propertyName inObject:(id)object;
37 |
38 | + (Class) classWithName:(NSString*)className;
39 |
40 | + (BOOL) klaatuVerataNikto:(Class)clazz selector:(SEL)originalSelector replacement:(IMP)replacement originalPointer:(IMP*)originalPointer;
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/NSArray+ISSAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSArray+ISSAdditions.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT - http://www.github.com/tolo/InterfaCSS/blob/master/LICENSE
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface NSArray (ISSAdditions)
14 |
15 | - (NSArray*) iss_flattened;
16 |
17 | @end
18 |
19 | NS_ASSUME_NONNULL_END
20 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/NSArray+ISSAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSArray+ISSAdditions.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT - http://www.github.com/tolo/InterfaCSS/blob/master/LICENSE
7 | //
8 |
9 | #import "NSArray+ISSAdditions.h"
10 |
11 | #import "NSString+ISSStringAdditions.h"
12 |
13 | static NSArray* flattenArray(NSArray* array) {
14 | NSMutableArray* flattened = [NSMutableArray array];
15 | for(id e in array) {
16 | if( [e isKindOfClass:NSArray.class] ) {
17 | [flattened addObjectsFromArray:flattenArray(e)];
18 | } else if( e != [NSNull null] ) {
19 | [flattened addObject:e];
20 | }
21 | }
22 | return [flattened copy];
23 | }
24 |
25 |
26 | @implementation NSArray (ISSAdditions)
27 |
28 | - (NSArray*) iss_flattened {
29 | return flattenArray(self);
30 | }
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/NSAttributedString+ISSAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSAttributedString+ISSAdditions.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 | @interface NSAttributedString (ISSAdditions)
12 |
13 | - (BOOL) iss_hasAttributes;
14 |
15 | @end
--------------------------------------------------------------------------------
/InterfaCSS/Util/NSAttributedString+ISSAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSAttributedString+ISSAdditions.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "NSAttributedString+ISSAdditions.h"
10 |
11 |
12 | @implementation NSAttributedString (ISSAdditions)
13 |
14 | - (BOOL) iss_hasAttributes {
15 | __block BOOL hasAttributes = NO;
16 | [self enumerateAttributesInRange:NSMakeRange(0, self.length) options:0 usingBlock:^(NSDictionary* attrs, NSRange range, BOOL* stop) {
17 | if( attrs.count > 0 ) {
18 | hasAttributes = YES;
19 | *stop = YES;
20 | }
21 | }];
22 | return hasAttributes;
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/NSDictionary+ISSDictionaryAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionary+ISSDictionaryAdditions.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 | @interface NSDictionary (ISSDictionaryAdditions)
12 |
13 | - (NSDictionary*) iss_dictionaryWithLowerCaseKeys;
14 |
15 | @end
--------------------------------------------------------------------------------
/InterfaCSS/Util/NSDictionary+ISSDictionaryAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionary+ISSDictionaryAdditions.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "NSDictionary+ISSDictionaryAdditions.h"
10 |
11 | @implementation NSDictionary (ISSDictionaryAdditions)
12 |
13 | - (NSDictionary*) iss_dictionaryWithLowerCaseKeys {
14 | NSMutableDictionary* result = [[NSMutableDictionary alloc] initWithCapacity:self.count];
15 | [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL* stop) {
16 | result[[key lowercaseString]] = obj;
17 | }];
18 | return result;
19 | }
20 |
21 | @end
--------------------------------------------------------------------------------
/InterfaCSS/Util/NSMutableArray+ISSAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSArray+ISSAdditions.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 | @interface NSMutableArray (ISSAdditions)
12 |
13 | - (void) iss_addAndReplaceUniqueObjectsInArray:(NSArray*)array;
14 |
15 | @end
--------------------------------------------------------------------------------
/InterfaCSS/Util/NSMutableArray+ISSAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSArray+ISSAdditions.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "NSMutableArray+ISSAdditions.h"
10 |
11 | @implementation NSMutableArray (ISSAdditions)
12 |
13 | - (void) iss_addAndReplaceUniqueObjectsInArray:(NSArray*)array {
14 | for(id element in array) {
15 | [self removeObject:element];
16 | [self addObject:element];
17 | }
18 | }
19 |
20 | @end
--------------------------------------------------------------------------------
/InterfaCSS/Util/NSObject+ISSLogSupport.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+ISSLogSupport.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 |
12 | #define ISS_ISEQUAL(x,y) ((x == y) || (x != nil && [x isEqual:y]))
13 |
14 | #define ISS_LOG_LEVEL_NONE 0
15 | #define ISS_LOG_LEVEL_WARNING 1
16 | #define ISS_LOG_LEVEL_DEBUG 2
17 | #define ISS_LOG_LEVEL_TRACE 3
18 |
19 | #define ISSLogTrace(__FORMAT__, ...) [self iss_logTrace:__FORMAT__, ##__VA_ARGS__]
20 | #define ISSLogDebug(__FORMAT__, ...) [self iss_logDebug:__FORMAT__, ##__VA_ARGS__]
21 | #define ISSLogWarning(__FORMAT__, ...) [self iss_logWarning:__FORMAT__, ##__VA_ARGS__]
22 |
23 | @interface NSObject (ISSLogSupport)
24 |
25 | /**
26 | * Sets the logging level for InterfaCSS - valid values are ISS_LOG_LEVEL_NONE, ISS_LOG_LEVEL_WARNING, ISS_LOG_LEVEL_DEBUG and ISS_LOG_LEVEL_TRACE.
27 | */
28 | + (void) iss_setLogLevel:(NSInteger)logLevel;
29 |
30 | - (void) iss_logTrace:(NSString*)format, ...;
31 | - (void) iss_logDebug:(NSString*)format, ...;
32 | - (void) iss_logWarning:(NSString*)format, ...;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/NSObject+ISSLogSupport.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+ISSLogSupport.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "NSObject+ISSLogSupport.h"
10 |
11 | static NSInteger ISSLogLevel;
12 |
13 | @implementation NSObject (ISSLogSupport)
14 |
15 | + (void) load {
16 | #if DEBUG == 1
17 | [self iss_setLogLevel:ISS_LOG_LEVEL_DEBUG];
18 | #else
19 | [self iss_setLogLevel:ISS_LOG_LEVEL_WARNING];
20 | #endif
21 | }
22 |
23 | + (void) iss_setLogLevel:(NSInteger)logLevel {
24 | ISSLogLevel = logLevel;
25 | }
26 |
27 | - (void) iss_log:(NSString*)level format:(NSString*)format withParameters:(va_list)vl {
28 | NSString* logMessage = [[NSString alloc] initWithFormat:format arguments:vl];
29 | NSLog(@"%@InterfaCSS: %@ - %@", level, self, logMessage);
30 | }
31 |
32 | - (void) iss_logTrace:(NSString*)format, ... {
33 | if( ISSLogLevel >= ISS_LOG_LEVEL_TRACE ) {
34 | va_list vl;
35 | va_start(vl, format);
36 | [self iss_log:@"[TRACE] " format:format withParameters:vl];
37 | va_end(vl);
38 | }
39 | }
40 |
41 | - (void) iss_logDebug:(NSString*)format, ... {
42 | if( ISSLogLevel >= ISS_LOG_LEVEL_DEBUG ) {
43 | va_list vl;
44 | va_start(vl, format);
45 | [self iss_log:@"[DEBUG] " format:format withParameters:vl];
46 | va_end(vl);
47 | }
48 | }
49 |
50 | - (void) iss_logWarning:(NSString*)format, ... {
51 | if( ISSLogLevel >= ISS_LOG_LEVEL_WARNING ) {
52 | va_list vl;
53 | va_start(vl, format);
54 | [self iss_log:@"[WARNING] " format:format withParameters:vl];
55 | va_end(vl);
56 | }
57 | }
58 |
59 | @end
60 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/NSString+ISSStringAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+ISSStringAdditions.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 |
11 | @interface NSString (ISSStringAdditions)
12 |
13 | + (BOOL) iss_string:(NSString*)string1 isEqualToString:(NSString*)string2;
14 |
15 | - (BOOL) iss_isEmpty;
16 | - (BOOL) iss_hasData;
17 |
18 | - (NSString*) iss_trim;
19 | - (NSString*) iss_trimQuotes;
20 | - (NSArray*) iss_trimmedSplit:(NSString*)sep;
21 | - (NSArray*) iss_trimmedSplitWithSet:(NSCharacterSet*)characterSet;
22 | - (NSArray*) iss_splitOnSpaceOrComma;
23 |
24 | - (NSString*) iss_stringBySeparatingCamelCaseComponentsWithDash;
25 |
26 | - (BOOL) iss_isNumeric;
27 |
28 | - (BOOL) iss_isEqualIgnoreCase:(NSString*)otherString;
29 |
30 | - (NSDate*) iss_parseHttpDate;
31 |
32 |
33 | - (NSString*) iss_stringByReplacingUnicodeSequences;
34 | - (NSString*) iss_unicodeCharacterStringFromSequenceString;
35 | - (UTF32Char) iss_unicodeCharacterFromSequenceString;
36 | + (NSString*) iss_stringFromUTF32Char:(UTF32Char)unicodeChar;
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/NSString+ISSStringAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+ISSStringAdditions.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "NSString+ISSStringAdditions.h"
10 |
11 | #import "ISSDateUtils.h"
12 |
13 |
14 | @implementation NSString (ISSStringAdditions)
15 |
16 | + (BOOL) iss_string:(NSString*)string1 isEqualToString:(NSString*)string2 {
17 | return string1 == string2 || [string1 isEqualToString:string2];
18 | }
19 |
20 | - (BOOL) iss_isEmpty {
21 | return [[self iss_trim] length] == 0;
22 | }
23 |
24 | - (BOOL) iss_hasData {
25 | return ![self iss_isEmpty];
26 | }
27 |
28 | - (NSString*) iss_trim {
29 | return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
30 | }
31 |
32 | - (NSString*) iss_trimQuotes {
33 | return [[self iss_trim] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\"\'"]];
34 | }
35 |
36 | - (NSArray*) iss_trimmedSplit:(NSString*)sep {
37 | NSMutableArray* vals = [[self componentsSeparatedByString:sep] mutableCopy];
38 | for (unsigned int i=0; i> 10); // use top ten bits
171 | highSurrogate += 0xD800;
172 | unichar lowSurrogate = (unichar)(unicodeChar & 0x3FF); // use low ten bits
173 | lowSurrogate += 0xDC00;
174 | return [NSString stringWithCharacters:(unichar[]){highSurrogate, lowSurrogate} length:2];
175 | } else {
176 | return [NSString stringWithCharacters:(unichar[]){(unichar)unicodeChar} length:1];
177 | }
178 | }
179 |
180 | @end
181 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/UIColor+ISSColorAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+ISSColorAdditions.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface UIColor (ISSColorAdditions)
13 |
14 | + (UIColor*) iss_colorWithR:(NSInteger)r G:(NSInteger)g B:(NSInteger)b;
15 | + (UIColor*) iss_colorWithR:(NSInteger)r G:(NSInteger)g B:(NSInteger)b A:(float)a;
16 | + (UIColor*) iss_colorWithHexString:(NSString*)hex;
17 |
18 | - (NSArray*) iss_rgbaComponents;
19 |
20 | - (UIColor*) iss_colorByIncreasingBrightnessBy:(CGFloat)amount;
21 | - (UIColor*) iss_colorByIncreasingSaturationBy:(CGFloat)amount;
22 | - (UIColor*) iss_colorByIncreasingAlphaBy:(CGFloat)amount;
23 |
24 | + (UIImage*) iss_colorAsUIImage:(UIColor*)color;
25 | - (UIImage*) iss_asUIImage;
26 |
27 | - (UIImage*) iss_topDownLinearGradientImageToColor:(UIColor*)color height:(CGFloat)height;
28 | - (UIColor*) iss_topDownLinearGradientToColor:(UIColor*)color height:(CGFloat)height;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/UIColor+ISSColorAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+ISSColorAdditions.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "UIColor+ISSColorAdditions.h"
10 |
11 | #import "NSString+ISSStringAdditions.h"
12 |
13 |
14 | static inline CGFloat adjustWithAbsoluteAmount(CGFloat value, CGFloat adjustAmount) {
15 | return MIN(MAX(0.0f, value + value * adjustAmount / 100.0f), 1.0f);
16 | }
17 |
18 | @implementation UIColor (ISSColorAdditions)
19 |
20 | + (UIColor*) iss_colorWithR:(NSInteger)r G:(NSInteger)g B:(NSInteger)b {
21 | return [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:1];
22 | }
23 |
24 | + (UIColor*) iss_colorWithR:(NSInteger)r G:(NSInteger)g B:(NSInteger)b A:(float)a {
25 | return [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a];
26 | }
27 |
28 | + (UIColor*) iss_colorWithHexString:(NSString*)hex {
29 | hex = [hex iss_trim];
30 | BOOL withAlpha = hex.length == 4 || hex.length == 8;
31 | BOOL compact = hex.length == 3 || hex.length == 4;
32 |
33 | if ( hex.length == 6 || compact || withAlpha ) {
34 | NSScanner* scanner = [NSScanner scannerWithString:hex];
35 | unsigned int cc = 0;
36 | unsigned int alphaOffset = withAlpha ? (compact ? 4 : 8) : 0;
37 | unsigned int chanelOffset = compact ? 4 : 8;
38 | unsigned int mask = compact ? 0x0F : 0xFF;
39 | unsigned int multiplier = 0xFF/mask;
40 |
41 | if( [scanner scanHexInt:&cc] ) {
42 | NSInteger r = ((cc >> (2*chanelOffset + alphaOffset)) & mask) * multiplier;
43 | NSInteger g = ((cc >> (chanelOffset + alphaOffset)) & mask) * multiplier;
44 | NSInteger b = ((cc >> alphaOffset) & mask) * multiplier;
45 | if( withAlpha ) {
46 | float a = (cc & mask) / (float)mask;
47 | return [self iss_colorWithR:r G:g B:b A:a];
48 | } else {
49 | return [self iss_colorWithR:r G:g B:b];
50 | }
51 | }
52 | }
53 | return [UIColor magentaColor];
54 | }
55 |
56 | - (NSArray*) iss_rgbaComponents {
57 | CGFloat r,g,b,a;
58 | if( ![self getRed:&r green:&g blue:&b alpha:&a] ) {
59 | if( [self getWhite:&r alpha:&a] ) { // Grayscale
60 | return @[ @(r), @(r), @(r), @(a) ];
61 | }
62 | }
63 | return @[ @(r), @(g), @(b), @(a) ];
64 | }
65 |
66 | - (UIColor*) iss_colorByIncreasingBrightnessBy:(CGFloat)amount {
67 | CGFloat h,s,b,a;
68 | if( [self getHue:&h saturation:&s brightness:&b alpha:&a] ) { // RGB or HSB
69 | b = adjustWithAbsoluteAmount(b, amount);
70 | return [UIColor colorWithHue:h saturation:s brightness:b alpha:a];
71 | } else if( [self getWhite:&b alpha:&a] ) { // Grayscale
72 | b = adjustWithAbsoluteAmount(b, amount);
73 | return [UIColor colorWithWhite:b alpha:a];
74 | } else return self;
75 | }
76 |
77 | - (UIColor*) iss_colorByIncreasingSaturationBy:(CGFloat)amount {
78 | CGFloat h,s,b,a;
79 | if( [self getHue:&h saturation:&s brightness:&b alpha:&a] ) { // RGB or HSB
80 | s = adjustWithAbsoluteAmount(s, amount);
81 | return [UIColor colorWithHue:h saturation:s brightness:b alpha:a];
82 | } else return self;
83 | }
84 |
85 | - (UIColor*) iss_colorByIncreasingAlphaBy:(CGFloat)amount {
86 | CGFloat h,s,b,a;
87 | if( [self getHue:&h saturation:&s brightness:&b alpha:&a] ) { // RGB or HSB
88 | a = adjustWithAbsoluteAmount(a, amount);
89 | return [UIColor colorWithHue:h saturation:s brightness:b alpha:a];
90 | } else if( [self getWhite:&b alpha:&a] ) { // Grayscale
91 | a = adjustWithAbsoluteAmount(a, amount);
92 | return [UIColor colorWithWhite:b alpha:a];
93 | } else return self;
94 | }
95 |
96 | + (UIImage*) iss_colorAsUIImage:(UIColor*)color {
97 | CGRect rect = CGRectMake(0, 0, 1, 1);
98 |
99 | UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
100 | [color setFill];
101 | UIRectFill(rect);
102 | UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
103 | UIGraphicsEndImageContext();
104 |
105 | return image;
106 | }
107 |
108 | - (UIImage*) iss_asUIImage {
109 | return [self.class iss_colorAsUIImage:self];
110 | }
111 |
112 | - (UIImage*) iss_topDownLinearGradientImageToColor:(UIColor*)color height:(CGFloat)height {
113 | CGSize size = CGSizeMake(1, height);
114 |
115 | UIGraphicsBeginImageContextWithOptions(size, NO, 0);
116 |
117 | CGContextRef context = UIGraphicsGetCurrentContext();
118 |
119 | CGFloat locations[2] = {0.0, 1.0};
120 | CGFloat components[8];
121 | NSArray* colorComponents = [self iss_rgbaComponents];
122 | for (NSUInteger i = 0; i < colorComponents.count; i++) components[i] = [colorComponents[i] floatValue];
123 | colorComponents = [color iss_rgbaComponents];
124 | for (NSUInteger i = 0; i < colorComponents.count; i++) components[i + 4] = [colorComponents[i] floatValue];
125 |
126 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
127 | CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, 2);
128 |
129 | CGContextDrawLinearGradient(context, gradient, CGPointMake(0, 0), CGPointMake(0, size.height), 0);
130 |
131 | CGColorSpaceRelease(colorSpace);
132 | CGGradientRelease(gradient);
133 |
134 | UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
135 | UIGraphicsEndImageContext();
136 |
137 | return image;
138 | }
139 |
140 | - (UIColor*) iss_topDownLinearGradientToColor:(UIColor*)color height:(CGFloat)height {
141 | return [UIColor colorWithPatternImage:[self iss_topDownLinearGradientImageToColor:color height:height]];
142 | }
143 |
144 | @end
145 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/UIDevice+ISSAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIDevice+ISSAdditions.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface UIDevice (ISSAdditions)
13 |
14 | + (NSString*) iss_deviceModelId;
15 |
16 | + (BOOL) iss_versionGreaterOrEqualTo:(NSString*)version;
17 |
18 | + (BOOL) iss_versionLessOrEqualTo:(NSString*)version;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/InterfaCSS/Util/UIDevice+ISSAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIDevice+ISSAdditions.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Copyright (c) Tobias Löfstrand, Leafnode AB.
6 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
7 | //
8 |
9 | #import "UIDevice+ISSAdditions.h"
10 | #import "NSObject+ISSLogSupport.h"
11 |
12 | #include
13 | #include
14 | #include
15 |
16 |
17 | static NSString* cachedDeviceModelId;
18 |
19 |
20 | @implementation UIDevice (ISSAdditions)
21 |
22 | + (NSString*) iss_loadDeviceModelId {
23 | @try {
24 | int mib[2];
25 |
26 | mib[0] = CTL_HW;
27 | mib[1] = HW_MACHINE;
28 | size_t len;
29 | sysctl(mib, 2, NULL, &len, NULL, 0);
30 | char* machine = malloc(len);
31 | if( machine ) {
32 | sysctl(mib, 2, machine, &len, NULL, 0);
33 | NSString* platform = @(machine);
34 | free(machine);
35 | return platform;
36 | } else {
37 | ISSLogWarning(@"Unable to load device model ID (unable to allocate memory)!");
38 | }
39 | } @catch (NSException* exception) {
40 | ISSLogWarning(@"Unable to load device model ID (%@)!", exception);
41 | }
42 | return @"";
43 | }
44 |
45 | + (void) load {
46 | static dispatch_once_t onceToken;
47 | dispatch_once(&onceToken, ^{
48 | cachedDeviceModelId = [[self iss_loadDeviceModelId] lowercaseString];
49 | });
50 | }
51 |
52 | + (NSString*) iss_deviceModelId {
53 | return cachedDeviceModelId;
54 | }
55 |
56 | + (BOOL) iss_versionGreaterOrEqualTo:(NSString*)version {
57 | NSString* systemVersion = [[UIDevice currentDevice] systemVersion];
58 | return [systemVersion compare:version options:NSNumericSearch] != NSOrderedAscending;
59 | }
60 |
61 | + (BOOL) iss_versionLessOrEqualTo:(NSString*)version {
62 | NSString* systemVersion = [[UIDevice currentDevice] systemVersion];
63 | return [systemVersion compare:version options:NSNumericSearch] != NSOrderedDescending;
64 | }
65 |
66 | @end
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2012-2016 Tobias Löfstrand, Leafnode AB.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all 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,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Resources/InterfaCSS-title-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tolo/InterfaCSS/1b6b18a15239d7b9382d895252ebd9f4cda1aa5a/Resources/InterfaCSS-title-logo.png
--------------------------------------------------------------------------------
/Samples/HelloISSLayout/HelloISSLayout.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Samples/HelloISSLayout/HelloISSLayout.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Samples/HelloISSLayout/ISSLayout/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // ISSLayout
4 | //
5 | // Created by Tobias Löfstrand on 2015-05-01.
6 | // Copyright (c) 2015 Leafnode. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import InterfaCSS
11 |
12 | @UIApplicationMain
13 | class AppDelegate: UIResponder, UIApplicationDelegate {
14 |
15 | var window: UIWindow?
16 |
17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
18 | let iss:InterfaCSS = InterfaCSS.sharedInstance()
19 |
20 | iss.loadStyleSheetFromMainBundleFile("styles.css")
21 |
22 | let mainWindow = UIWindow(frame: UIScreen.mainScreen().bounds)
23 | mainWindow.rootViewController = ViewController()
24 | mainWindow.makeKeyAndVisible()
25 |
26 | window = mainWindow
27 |
28 | return true
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Samples/HelloISSLayout/ISSLayout/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Samples/HelloISSLayout/ISSLayout/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/Samples/HelloISSLayout/ISSLayout/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | se.leafnode.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | NSAppTransportSecurity
26 |
27 | NSAllowsArbitraryLoads
28 |
29 |
30 | UILaunchStoryboardName
31 | LaunchScreen
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UIStatusBarHidden
37 |
38 | UISupportedInterfaceOrientations
39 |
40 | UIInterfaceOrientationPortrait
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Samples/HelloISSLayout/ISSLayout/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // ISSLayout
4 | //
5 | // Created by Tobias Löfstrand on 2015-05-01.
6 | // Copyright (c) 2015 Leafnode. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import InterfaCSS
11 |
12 | class ViewController: UIViewController {
13 |
14 | // Properties auto populated by ISSViewBuilder (when using elementId):
15 | var button: UIButton?
16 | var label: UILabel?
17 | var rootView:ISSLayoutContextView?
18 |
19 | var buttonCenterLayoutValueDefault : CGFloat?
20 |
21 |
22 | override func loadView() {
23 | // Setup view hierarchy - two options available:
24 |
25 |
26 | // *** OPTION 1 - Using view builder and layout specified in stylesheet ***
27 | /*InterfaCSS.sharedInstance().loadStyleSheetFromMainBundleFile("layout.css")
28 | self.view = ISSViewBuilder.rootViewWithId("rootView", withOwner: self, andSubViews: {
29 | return [
30 | ISSViewBuilder.labelWithId("marginLabel"),
31 | ISSViewBuilder.labelWithId("layoutGuideLabel"),
32 |
33 | ISSViewBuilder.viewOfClass(UIButton.self, withId: "button"),
34 | ISSViewBuilder.viewWithId("view1"),
35 | ISSViewBuilder.viewWithId("view2"),
36 | ISSViewBuilder.viewWithId("view3"),
37 | ISSViewBuilder.viewWithId("view4"),
38 | ISSViewBuilder.labelWithId("label")
39 | ];
40 | })*/
41 |
42 | // *** OPTION 2 - Load both view hierachy and layout from a view definition file ('layout.xml') ***
43 | self.view = ISSViewBuilder.loadViewHierarchyFromMainBundleFile("layout.xml", fileOwner: self)
44 |
45 | /*
46 | if let b = button {
47 | // Initialize default value for layout attribute that we'll need later
48 | b.applyStylingISS() // Make sure styling has been applied first (only really needed for option 1)
49 | self.buttonCenterLayoutValueDefault = b.layoutISS.valueForLayoutAttribute(.CenterY).constant
50 |
51 | b.setTitle("Tap Me", forState: .Normal)
52 | b.addTarget(self, action: "moveMe", forControlEvents: .TouchDown)
53 | }
54 | if let l = label {
55 | l.text = "Hello ISSLayout World!"
56 | }
57 | */
58 |
59 | // Example of how additional layout pre/post processing / validation / customization can be applied:
60 | if let layoutContextView = self.rootView {
61 | // Example of pre processing block, to customize layout before it's applied to view (in this case, used to adjust layout attribute value based on active class):
62 | layoutContextView.layoutPreProcessingBlock = { (view: UIView!, layout: ISSLayout!) -> Void in
63 | if view.elementIdISS == "button" {
64 | if view.hasStyleClassISS("moveMe") {
65 | layout.valueForLayoutAttribute(.CenterY).constant = 100
66 | } else {
67 | layout.valueForLayoutAttribute(.CenterY).constant = self.buttonCenterLayoutValueDefault!
68 | }
69 | }
70 | }
71 | // Example of post processing block, using class function
72 | layoutContextView.layoutPostProcessingBlock = ViewController.layoutPostProcessingBlock
73 | }
74 | }
75 |
76 | // Class function used as layout post processing block, to customize frame after layoyt has been applied (in this case, to calculate some custom weird frame value for view4):
77 | class func layoutPostProcessingBlock(view: UIView!, layout: ISSLayout!) {
78 | if view.elementIdISS == "view4" {
79 | let vf = view.frame
80 | if vf.origin.y > (UIScreen.mainScreen().bounds.size.height * 2 / 3) {
81 | view.frame = CGRectMake(vf.origin.x - vf.size.width, vf.origin.y - vf.size.height, vf.size.width, vf.size.height)
82 | }
83 | }
84 | }
85 |
86 | // Action handler method for button
87 | func moveMe() {
88 | let hasClass: Bool = self.button?.hasStyleClassISS("moveMe") as Bool!
89 |
90 | UIView.animateWithDuration(0.3, delay: 0, options: [.BeginFromCurrentState, .LayoutSubviews], animations: { () -> Void in
91 | if( hasClass ) {
92 | self.button?.removeStyleClassISS("moveMe")
93 | } else {
94 | self.button?.addStyleClassISS("moveMe")
95 | }
96 | self.button?.applyStylingISS()
97 | // Force re-layout of root view:
98 | self.view.setNeedsLayout()
99 | self.view.layoutIfNeeded()
100 | }, completion: nil)
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/Samples/HelloISSLayout/ISSLayout/layout.css:
--------------------------------------------------------------------------------
1 |
2 | /**
3 |
4 | Note: This demo uses a separate stylesheet file for specifying the layout. This is not actually necessary - it's only done this way for demonstration purposes.
5 |
6 | **/
7 |
8 | #marginLabel {
9 | layout: left(parent.leftMargin), top(50); /* Placing label at left layout margin of parent and using intrinsic content size of label */
10 | }
11 |
12 | #layoutGuideLabel {
13 | layout: top(guide.top + 1), centerX(parent); /* Placing label at top layout guide (with offset) and using intrinsic content size of label */
14 | }
15 |
16 | #button {
17 | layout: size(100, 100), center(parent, parent - 60); /* Using implicit/default parent relations that evaluates to parent.centerX / parent.centerY (same attributes used) */
18 | }
19 |
20 | /*
21 | // We could of course adjust the layout this way, instead of how it's currently being done in ViewController.swift, but it wouldn't be as much fun
22 | #button.moveMe {
23 | layout: size(100, 100), center(parent, parent + 100);
24 | }
25 | */
26 |
27 | #view1 {
28 | layout: size(25, 25), bottomRight(button - 30, button - 30); /* Using implicit/default element relations that in this case evaluates to button.left/button.top (opposing attributes used) */
29 | }
30 |
31 | #view2 {
32 | layout: size(25, 25),
33 | bottomLeft(button + 30, button - 30); /* Different attributes in the layout can be separated by either a dot or a comma, and newlines are also allowed before/after separator */
34 | }
35 |
36 | #view3 {
37 | layout: size(25, 25),
38 | topRight(button - 30, button + 30);
39 | }
40 |
41 | #view4 {
42 | layout: size(25, 25),
43 | topLeft(button + 30, button + 30);
44 | }
45 |
46 | #label {
47 | layout: top(button.top - 20),
48 | centerX(parent); /* Using intrinsic content size of label */
49 | }
50 |
--------------------------------------------------------------------------------
/Samples/HelloISSLayout/ISSLayout/layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
64 |
--------------------------------------------------------------------------------
/Samples/HelloISSLayout/Podfile:
--------------------------------------------------------------------------------
1 | source 'https://github.com/CocoaPods/Specs.git'
2 |
3 | platform :ios, '7.0'
4 | xcodeproj 'HelloISSLayout'
5 | use_frameworks!
6 |
7 | pod 'InterfaCSS', :path => './../../'
8 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/Podfile:
--------------------------------------------------------------------------------
1 | source 'https://github.com/CocoaPods/Specs.git'
2 |
3 | platform :ios, '8.0'
4 | use_frameworks!
5 |
6 | xcodeproj 'SimpleSample'
7 |
8 | pod 'InterfaCSS', :path => './../../'
9 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Created by Tobias Löfstrand on 2012-02-24.
6 | // Copyright (c) 2012 Leafnode AB.
7 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
8 | //
9 |
10 | @class SimpleSampleViewController;
11 |
12 | @interface AppDelegate : UIResponder
13 |
14 | @property (strong, nonatomic) UIWindow *window;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Created by Tobias Löfstrand on 2012-02-24.
6 | // Copyright (c) 2012 Leafnode AB.
7 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
8 | //
9 |
10 | #import "AppDelegate.h"
11 |
12 | #import
13 | #import "SimpleSampleViewController.h"
14 | #import "PrototypeExampleViewController.h"
15 | #import "IBViewController.h"
16 |
17 | @implementation AppDelegate
18 |
19 |
20 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
21 | // If you really want to get the log messages flowing, uncomment below:
22 | //[NSObject iss_setLogLevel:ISS_LOG_LEVEL_TRACE];
23 |
24 | [[InterfaCSS interfaCSS] loadStyleSheetFromMainBundleFile:@"constants.css"];
25 | [[InterfaCSS interfaCSS] loadStyleSheetFromMainBundleFile:@"main.css"];
26 |
27 | // When developing your app, consider using an auto refreshable stylesheet that is loaded from a web server (or perhaps a cloud service like Dropbox,
28 | // Sugarsync etc) or the local file system.
29 | //#if DEBUG
30 | //#if TARGET_IPHONE_SIMULATOR
31 | // [[InterfaCSS interfaCSS] loadRefreshableStyleSheetFromLocalFile:@"/Users/user/Documents/myprettystyles.css"];
32 | //#else
33 | // [[InterfaCSS interfaCSS] loadRefreshableStyleSheetFromURL:[NSURL URLWithString:@"http://someserver/myprettystyles.css"]];
34 | //#endif
35 | //#endif
36 |
37 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
38 |
39 | SimpleSampleViewController* viewController = [[SimpleSampleViewController alloc] init];
40 | PrototypeExampleViewController* prototypeExampleViewController = [[PrototypeExampleViewController alloc] init];
41 | IBViewController* ibViewController = [[IBViewController alloc] init];
42 |
43 | UITabBarController* tabBarController = [[UITabBarController alloc] init];
44 | tabBarController.tabBar.translucent = NO;
45 | tabBarController.tabBar.styleClassISS = @"tabBarStyle1";
46 | tabBarController.viewControllers = @[viewController, prototypeExampleViewController, ibViewController];
47 | tabBarController.selectedIndex = 0;
48 |
49 | self.window.rootViewController = tabBarController;
50 | [self.window makeKeyAndVisible];
51 |
52 | return YES;
53 | }
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tolo/InterfaCSS/1b6b18a15239d7b9382d895252ebd9f4cda1aa5a/Samples/SimpleSample/SimpleSample/Default-568h@2x.png
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/IBViewController.css:
--------------------------------------------------------------------------------
1 |
2 | .IBViewControllerRoot {
3 | backgroundColor: #dbdad8;
4 | }
5 |
6 | .IBViewControllerLabel {
7 | textColor: darkgray;
8 | layout: left(parent.leftMargin), right(parent.rightMargin), height(60), centerY(parent - 40);
9 | text: "View loaded from XIB, and styled using IBInspectable property";
10 | numberOfLines: 0;
11 | }
12 |
13 | #IBViewControllerButton {
14 | layout: centerX(parent), centerY(parent);
15 | titleColor: red;
16 | backgroundImage: clear;
17 | backgroundImage(highlighted): clear;
18 | borderWidth: 0;
19 | }
20 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/IBViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // IBViewController.h
3 | // SimpleSample
4 | //
5 | // Created by PMB on 2015-10-17.
6 | // Copyright © 2015 Leafnode AB. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface IBViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/IBViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // IBViewController.m
3 | // SimpleSample
4 | //
5 | // Created by PMB on 2015-10-17.
6 | // Copyright © 2015 Leafnode AB. All rights reserved.
7 | //
8 |
9 | #import "IBViewController.h"
10 |
11 | #import
12 |
13 | @implementation IBViewController
14 |
15 | - (instancetype) initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil {
16 | if( [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil] ) {
17 | self.title = @"iBuilder";
18 |
19 | // To prevent a lot of up front loading when application starts, loading of a stylesheet can be postponed until it's actually needed.
20 | // Additionally, a scope can be attached to the stylesheet, to limit styles to only be processed while in a particular view controller for instance
21 | ISSStyleSheetScope* scope = [ISSStyleSheetScope scopeWithViewControllerClass:self.class];
22 | [[InterfaCSS interfaCSS] loadStyleSheetFromMainBundleFile:@"IBViewController.css" withScope:scope];
23 | }
24 | return self;
25 | }
26 |
27 | - (void) viewDidLoad {
28 | [super viewDidLoad];
29 |
30 |
31 | }
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/IBViewController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
28 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/PrototypeExampleViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // PrototypeExampleViewController.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Created by Tobias Löfstrand on 2014-02-09.
6 | // Copyright (c) 2014 Leafnode AB.
7 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
8 | //
9 |
10 | @interface PrototypeExampleViewController : UIViewController
11 |
12 | @property (nonatomic, strong) UITableView* tableView;
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/PrototypeExampleViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // PrototypeExampleViewController.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Created by Tobias Löfstrand on 2014-02-09.
6 | // Copyright (c) 2014 Leafnode AB.
7 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
8 | //
9 |
10 | #import "PrototypeExampleViewController.h"
11 |
12 | #import
13 | #import
14 | #import
15 | #import
16 |
17 |
18 | @interface PrototypeExampleCell : UITableViewCell
19 | @property (nonatomic, strong) UILabel* label1;
20 | @property (nonatomic, strong) UILabel* label3;
21 | @end
22 |
23 | @implementation PrototypeExampleCell
24 | @end
25 |
26 |
27 |
28 | @interface PrototypeExampleViewController ()
29 |
30 | @property (nonatomic, strong) UILabel* mainTitleLabel;
31 | @property (nonatomic, strong) UIButton* mainTitleBtn;
32 |
33 | @end
34 |
35 |
36 | @implementation PrototypeExampleViewController {
37 | NSArray* items;
38 | }
39 |
40 | - (id)init {
41 | self = [super init];
42 | if (self) {
43 | self.title = @"Prototype";
44 |
45 | items = @[
46 | @[@"ágætis byrjun", @"ágætis byrjun", @"1999"],
47 | @[@"flugufrelsarinn", @"ágætis byrjun", @"1999"],
48 | @[@"olsen olsen", @"ágætis byrjun", @"1999"],
49 | @[@"starálfur", @"ágætis byrjun", @"1999"],
50 | @[@"svefn-g-englar", @"ágætis byrjun", @"1999"],
51 | @[@"popplagið", @"()", @"2002"],
52 | @[@"samskeyti", @"()", @"2002"],
53 | @[@"vaka", @"()", @"2002"],
54 | @[@"glósóli", @"takk", @"2005"],
55 | @[@"hoppípolla", @"takk", @"2005"],
56 | @[@"ára bátur", @"með suð í eyrum við spilum endalaust", @"2008"],
57 | @[@"fljótavík", @"með suð í eyrum við spilum endalaust", @"2008"],
58 | @[@"ekki múkk", @"Valtari", @"2012"],
59 | @[@"varúð", @"Valtari", @"2012"],
60 | @[@"hrafntinna", @"Kveikur", @"2013"],
61 | @[@"ísjaki", @"Kveikur", @"2013"],
62 | ];
63 | }
64 | return self;
65 | }
66 |
67 | - (void) loadView {
68 | // To prevent a lot of up front loading when application starts, loading of a stylesheet can be postponed until it's actually needed.
69 | // Additionally, a scope can be attached to the stylesheet, to limit styles to only be processed while in a particular view controller for instance
70 | ISSStyleSheetScope* scope = [ISSStyleSheetScope scopeWithViewControllerClass:self.class];
71 | [[InterfaCSS interfaCSS] loadStyleSheetFromMainBundleFile:@"prototypeExample.css" withScope:scope];
72 |
73 | // Load the complete view hierarchy for this view controller from the view definition file 'views.xml'
74 | self.view = [ISSViewBuilder loadViewHierarchyFromMainBundleFile:@"views.xml" fileOwner:self];
75 |
76 | [self.mainTitleBtn setTitle:@"Sample button" forState:UIControlStateNormal];
77 | }
78 |
79 | - (NSUInteger) supportedInterfaceOrientations {
80 | return UIInterfaceOrientationMaskAll;
81 | }
82 |
83 |
84 | #pragma mark - Table View
85 |
86 |
87 | - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
88 | return items.count;
89 | }
90 |
91 | - (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
92 | PrototypeExampleCell* cell = [tableView dequeueReusablePrototypeCellWithIdentifierISS:@"prototypeExampleCell" forIndexPath:indexPath];
93 |
94 | NSArray* item = items[indexPath.row];
95 |
96 | cell.label1.text = item[0];
97 |
98 | // Testing the use of an element Id for this label
99 | UILabel* label2 = [cell subviewWithElementId:@"label2"];
100 | label2.text = item[1];
101 |
102 | cell.label3.text = item[2];
103 |
104 | return cell;
105 | }
106 |
107 | - (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
108 | [cell applyStylingISS];
109 | }
110 |
111 | - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
112 | UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
113 | [cell.selectedBackgroundView applyStylingWithAnimationISS];
114 | }
115 |
116 | @end
117 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/SimpleSample-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | com.leafnode.se.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.0
25 | LSRequiresIPhoneOS
26 |
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 | UIInterfaceOrientationPortraitUpsideDown
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/SimpleSample-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_3_0
10 | #warning "This project uses features only available in iOS SDK 3.0 and later."
11 | #endif
12 |
13 | #ifdef __OBJC__
14 | #import
15 | #import
16 | #endif
17 |
18 | #import
19 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/SimpleSampleViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // SimpleSampleViewController.h
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Created by Tobias Löfstrand on 2012-02-24.
6 | // Copyright (c) 2012 Leafnode AB.
7 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
8 | //
9 |
10 | @interface SimpleSampleViewController : UIViewController
11 |
12 | @end
13 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/SimpleSampleViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // SimpleSampleViewController.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Created by Tobias Löfstrand on 2012-02-24.
6 | // Copyright (c) 2012 Leafnode AB.
7 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
8 | //
9 |
10 | #import "SimpleSampleViewController.h"
11 |
12 | // Define this to enable using ISSViewBuilder shorthand macros:
13 | //#define ISS_VIEW_BUILDER_SHORTHAND_ENABLED
14 |
15 | #import
16 | #import
17 |
18 |
19 | @interface SimpleSampleViewController ()
20 |
21 | @property (nonatomic, strong) UILabel* mainTitleLabel;
22 | @property (nonatomic, strong) UIButton* mainTitleButton;
23 |
24 | @property (nonatomic, strong) UILabel* contentTitleLabel;
25 | @property (nonatomic, strong) UILabel* contentSubtitleLabel;
26 |
27 | @property (nonatomic, strong) UIView* simpleSampleContentView;
28 | @property (nonatomic, strong) UIButton* mainButtonTop;
29 | @property (nonatomic, strong) UIButton* mainButton;
30 |
31 | @end
32 |
33 |
34 |
35 | @implementation SimpleSampleViewController
36 |
37 |
38 | #pragma mark - Lifecycle
39 |
40 | - (id)init {
41 | self = [super init];
42 | if (self) {
43 | self.title = @"Simple";
44 | }
45 | return self;
46 | }
47 |
48 | - (void) loadView {
49 | // Construct the view hierachy for this view controller using ISSViewBuilder
50 | self.view = [ISSViewBuilder rootViewWithStyle:@"simpleSampleMainView" andSubViews:^{
51 | return @[
52 | self.mainTitleLabel = [ISSViewBuilder labelWithStyle:@"mainTitleLabel"],
53 | self.mainTitleButton = [ISSViewBuilder buttonWithStyle:@"mainTitleButton"],
54 | self.simpleSampleContentView = [ISSViewBuilder viewWithStyle:@"simpleSampleContentView" andSubViews:^{ return @[
55 | self.contentTitleLabel = [ISSViewBuilder labelWithStyle:@"simpleSampleContentTitleLabel"],
56 | self.contentSubtitleLabel = [ISSViewBuilder labelWithStyle:@"simpleSampleContentSubtitleLabel"],
57 | // You can also add and setup an already existing view object using the view builder:
58 | [ISSViewBuilder setupView:[[UIView alloc] init] withStyleClass:@"simpleSampleButtonContainer" andSubViews:^{
59 | return @[
60 | self.mainButtonTop = [ISSViewBuilder buttonWithStyle:@"simpleSampleMainButton1"],
61 | self.mainButton = [ISSViewBuilder buttonWithStyle:@"simpleSampleMainButton2"],
62 | [ISSViewBuilder buttonWithStyle:@"simpleSampleMainButton3"]];
63 | }] ];
64 | }] ];
65 | }];
66 |
67 | [self.mainButton addTarget:self action:@selector(touchedButton:event:) forControlEvents:UIControlEventAllTouchEvents];
68 |
69 | // NOTE: Uncomment below to disable styling of cornerRadius (just to test what disabling a property feels like)
70 | //[self.mainButton disableStylingForPropertyISS:@"cornerRadius"];
71 |
72 | [self.mainTitleButton setTitle:@"Sample button" forState:UIControlStateNormal];
73 |
74 | self.contentTitleLabel.text = @"Content Main";
75 | self.contentSubtitleLabel.text = @"Content Sub";
76 |
77 | // Setup notification blocks to get notified when styles are applied to mainButton
78 | self.mainButton.willApplyStylingBlockISS = ^(NSArray* styles) {
79 | // Use this block to for instance override which style properties are allowed to be set at the moment.
80 | //NSLog(@"Will apply styles to mainButton - %lu properties", (unsigned long)styles.count);
81 | return styles;
82 | };
83 | self.mainButton.didApplyStylingBlockISS = ^(NSArray* styles) {
84 | // In this block it's possible to for instance update any derived styling properties, or override values set during styling.
85 | //NSLog(@"Did apply styles to mainButton - %lu properties", (unsigned long)styles.count);
86 | };
87 |
88 | // Apply styling only once as startup to mainButtonTop, then disable automatic re-styling, to make it possible do adjust styling manually in code.
89 | [self.mainButtonTop applyStylingOnceISS];
90 |
91 | // Add custom style to tab bar item
92 | [[InterfaCSS sharedInstance] addStyleClass:@"tab1" forUIElement:self.tabBarItem];
93 | }
94 |
95 | - (NSUInteger) supportedInterfaceOrientations {
96 | return UIInterfaceOrientationMaskAll;
97 | }
98 |
99 | - (void) viewDidAppear:(BOOL)animated {
100 | [super viewDidAppear:animated];
101 |
102 | // Debug log matching styles for self.mainTitleLabel:
103 | #if DEBUG == 1
104 | [[InterfaCSS interfaCSS] logMatchingStyleDeclarationsForUIElement:self.mainTitleLabel];
105 | #endif
106 |
107 | [self performSelector:@selector(animateSimpleSampleContentView) withObject:nil afterDelay:.0f];
108 | }
109 |
110 | - (void) viewWillDisappear:(BOOL)animated {
111 | [super viewWillDisappear:animated];
112 |
113 | [self.simpleSampleContentView removeStyleClassISS:@"simpleSampleContentViewAtRest" scheduleStyling:NO];
114 | }
115 |
116 | - (void) animateSimpleSampleContentView {
117 | [UIView animateWithDuration:1.0f delay:.0f usingSpringWithDamping:0.25 initialSpringVelocity:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
118 | [self.simpleSampleContentView addStyleClassISS:@"simpleSampleContentViewAtRest" scheduleStyling:NO];
119 | [self.simpleSampleContentView applyStylingISS];
120 | } completion:nil];
121 | }
122 |
123 |
124 | #if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000
125 |
126 | - (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
127 | [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
128 |
129 | // Debug log matching styles for self.mainTitleLabel:
130 | [[InterfaCSS interfaCSS] logMatchingStyleDeclarationsForUIElement:self.mainTitleLabel];
131 | }
132 |
133 | #else
134 |
135 | - (void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator {
136 | [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
137 |
138 | // Debug log matching styles for self.mainTitleLabel:
139 | [self iss_logDebug:@"Matching declarations before rotation:"];
140 | [[InterfaCSS interfaCSS] logMatchingStyleDeclarationsForUIElement:self.mainTitleLabel];
141 | [coordinator animateAlongsideTransition:nil completion:^(id context) {
142 | [self iss_logDebug:@"Matching declarations after rotation:"];
143 | [[InterfaCSS interfaCSS] logMatchingStyleDeclarationsForUIElement:self.mainTitleLabel];
144 | }];
145 | }
146 |
147 | #endif
148 |
149 |
150 | #pragma mark - Actions
151 |
152 | - (void) touchedButton:(id)btn event:(UIEvent*)event {
153 | UITouch* touch = [event.allTouches anyObject];
154 | if( touch.phase == UITouchPhaseBegan ) {
155 | NSString* title;
156 | if( [self.mainButtonTop.currentTitle hasPrefix:@"T"] ) title = [self.mainButtonTop.currentTitle lowercaseString];
157 | else title = [self.mainButtonTop.currentTitle uppercaseString];
158 | [self.mainButtonTop setTitle:title forState:UIControlStateNormal];
159 |
160 | [self.mainButton addStyleClassISS:@"touched" animated:YES];
161 | } else if( touch.phase == UITouchPhaseEnded || touch.phase == UITouchPhaseCancelled ) {
162 | [self.mainButton removeStyleClassISS:@"touched" animated:YES];
163 | }
164 | }
165 |
166 |
167 | @end
168 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/constants.css:
--------------------------------------------------------------------------------
1 |
2 | /* Constants: */
3 |
4 | @stdHeadingLabel: AvenirNextCondensed-DemiBold 20;
5 | @stdTitleLabel: Avenir-Black 15;
6 | @stdTitleColor: #5f5f5f;
7 | @stdSubTitleLabel: Avenir-Light 14;
8 | @stdButtonFont: HelveticaNeue-Light 14;
9 |
10 | @stdColor1: rgb(16, 109, 255);
11 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tolo/InterfaCSS/1b6b18a15239d7b9382d895252ebd9f4cda1aa5a/Samples/SimpleSample/SimpleSample/image.png
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/main.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* "Reset" default styles */
4 |
5 | UIButton {
6 | backgroundImage: #e0e0e0; // Color as background image
7 | backgroundImage(highlighted): #7f7f7f;
8 | borderColor: #7f7f7f;
9 | borderWidth: 0.5;
10 | cornerRadius: 6;
11 | clipsToBounds: YES;
12 | titleColor: #303030;
13 | titleColor(highlighted): white;
14 | font: @stdButtonFont;
15 | }
16 |
17 |
18 |
19 | /* Common stuff */
20 |
21 | .tabBarStyle1 UITabBarItem {
22 | font: Avenir-Light 20;
23 | textColor: lightGray;
24 | textColor(selected): #b300fd;
25 | titlePositionAdjustment: offset(0, -10);
26 | }
27 |
28 | UITabBarItem.tab1 {
29 | font: Avenir-Heavy 20;
30 | }
31 |
32 | #mainTitleLabel, .mainTitleLabel {
33 | frame: sizeToFit(160, 50).left(15).top(30);
34 | textColor: rgb(255, 255, 255);
35 | font: @stdHeadingLabel;
36 | alpha: 1;
37 | backgroundColor: fadeout(lightGray, 75%);
38 | cornerRadius: 5;
39 | clipsToBounds: YES;
40 | attributedText: "Simple" (foregroundColor: #e1881e), " Sample " (foregroundColor: #3f3f3f), "Main" (foregroundColor: #ab45ec);
41 | }
42 |
43 | #mainTitleLabel:landscape, .mainTitleLabel:landscape { // Landscape orientation
44 | alpha: 0.5;
45 | textAlignment: center;
46 | }
47 |
48 |
49 |
50 | /* SimpleSampleViewController */
51 |
52 |
53 | .simpleSampleMainView { // Root view of SimpleSampleViewController
54 | autoresizingMask: width height;
55 | backgroundColor: gradient(darken(magenta, 50%), #e4e1e6);
56 | }
57 |
58 | .simpleSampleMainView .mainTitleLabel {
59 | shadowColor: fadeout(black, 50%);
60 | shadowOffset: size(1,1);
61 | }
62 |
63 | .mainTitleButton {
64 | frame: rect(15, 60, 120, 30);
65 | }
66 |
67 |
68 | // Content view and labels:
69 |
70 | .simpleSampleContentView {
71 | bounds: size(200, 230);
72 | center: parent(0, 0);
73 | backgroundColor: desaturate(fadeout(@stdColor1, 50%), 30%);
74 | layer.cornerRadius: 10;
75 | clipsToBounds: YES;
76 | anchorPoint: point(0, 0);
77 | transform: rotate(-25);
78 | }
79 |
80 | .simpleSampleContentViewAtRest {
81 | transform: identity;
82 | }
83 |
84 | .simpleSampleContentTitleLabel {
85 | frame: sizeToFit(140, 30).left(auto).right(auto).top(10); // Size to fit and center horizontally
86 | textColor: rgb(255, 255, 255);
87 | font: smaller(@stdTitleLabel, 2);
88 | }
89 |
90 | .simpleSampleContentSubtitleLabel {
91 | frame: rect(20, 40, 160, 20);
92 | textColor: rgb(228, 228, 228);
93 | font: smaller(@stdSubTitleLabel, 3);
94 | }
95 |
96 |
97 | // Content buttons:
98 |
99 | .simpleSampleButtonContainer {
100 | frame: rect(10, 80, 180, 140);
101 | backgroundColor: #88cc44;
102 | }
103 |
104 | .simpleSampleButtonContainer UIButton {
105 | backgroundImage: fadeout(white, 33%);
106 | }
107 |
108 | .simpleSampleMainButton1 {
109 | frame: size(160, 30).top(10).left(10);
110 | title: Top Button;
111 | font: AvenirNextCondensed-UltraLight 22;
112 | }
113 |
114 | .simpleSampleMainButton2 {
115 | bounds: size(160, 30);
116 | center: parent(0, 0);
117 | titleColor(highlighted): #b300fd;
118 | backgroundImage(highlighted): #d0d0d0;
119 | title: MainButton;
120 | transform: identity;
121 | }
122 |
123 | .simpleSampleMainButton3 {
124 | frame: size(160, 30).top(100).left(10);
125 | title: Bottom Button;
126 | font: HelveticaNeue-CondensedBold 14;
127 | }
128 |
129 | uibutton.touched {
130 | transform: rotate(180);
131 | }
132 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // Part of InterfaCSS - http://www.github.com/tolo/InterfaCSS
4 | //
5 | // Created by Tobias Löfstrand on 2012-02-24.
6 | // Copyright (c) 2012 Leafnode AB.
7 | // License: MIT (http://www.github.com/tolo/InterfaCSS/LICENSE)
8 | //
9 |
10 | #import
11 |
12 | #import "AppDelegate.h"
13 |
14 | int main(int argc, char * argv[])
15 | {
16 | @autoreleasepool {
17 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/prototypeExample.css:
--------------------------------------------------------------------------------
1 |
2 | /* PrototypeExampleViewController */
3 |
4 | .prototypeExampleMainView {
5 | autoresizingMask: width height;
6 | backgroundColor: #f0f0f0;
7 |
8 | #mainTitleLabel {
9 | textColor: #b300fd;
10 | }
11 |
12 | .mainTitleButton {
13 | frame: rect(15, 60, 120, 30);
14 | backgroundImage(highlighted): #f0f0f0;
15 | titleColor(highlighted): #b300fd;
16 | }
17 |
18 | .mainTitleButton:landscape {
19 | frame: rect(200, 30, 120, 30);
20 | }
21 |
22 | .prototypeExampleTable {
23 | frame: parent(100, 10, 10, 10);
24 | clipsToBounds: YES;
25 | cornerRadius: 6;
26 | borderColor: darkGray;
27 | borderWidth: 1;
28 |
29 | .cellBackgroundView {
30 | frame: parent;
31 | backgroundColor: #fcfcfc;
32 | }
33 |
34 | .cellBackgroundViewSelected {
35 | frame: parent;
36 | backgroundColor: fadeout(desaturate(#b300fd, 80%), 50%);
37 | }
38 |
39 | .prototypeExampleCellLabel1, .prototypeExampleCellLabel2, .prototypeExampleCellLabel3 {
40 | textColor: #4f4f4f;
41 | }
42 |
43 | .prototypeExampleCellLabel1 {
44 | frame: rect(5, 2, 120, 21);
45 | font: @stdTitleLabel;
46 | textColor: @stdTitleColor;
47 | }
48 |
49 | .prototypeExampleCellLabel2 {
50 | frame: rect(5, 21, 120, 21);
51 | font: @stdSubTitleLabel;
52 | }
53 |
54 | .prototypeExampleCellLabel3 {
55 | frame: size(auto, auto).left(50%).right(3%);
56 | font: HelveticaNeue-UltraLight 36;
57 | adjustsFontSizeToFitWidth: YES;
58 | minimumScaleFactor: 0.5;
59 | textAlignment: right;
60 | }
61 |
62 |
63 | /* Examples on how to use pseudo classes to apply conditional styling based on row numer in UITableView: */
64 |
65 | .prototypeExampleCell:nthOfType(even) .prototypeExampleCellLabel3 {
66 | textColor: darken(green, 25%);
67 | }
68 |
69 | .prototypeExampleCell:nthOfType(odd) .prototypeExampleCellLabel3 {
70 | textColor: darken(blue, 25%);
71 | }
72 |
73 | .prototypeExampleCell:firstOfType UILabel {
74 | textColor: darken(red, 15%);
75 | }
76 |
77 | .prototypeExampleCell:lastOfType UILabel {
78 | textColor: orange;
79 | }
80 | }
81 | }
82 |
83 | // Landscape orientation adjustment for tableview:
84 | .prototypeExampleTable:landscape {
85 | frame: parent(80, 10, 10, 10);
86 | }
87 |
--------------------------------------------------------------------------------
/Samples/SimpleSample/SimpleSample/views.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------