under-os 0.0.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +16 -0
  5. data/README.md +70 -0
  6. data/Rakefile +24 -0
  7. data/app/config.rb +4 -0
  8. data/app/layouts/alerts.html +8 -0
  9. data/app/layouts/calculator.html +26 -0
  10. data/app/layouts/collections.html +7 -0
  11. data/app/layouts/home.html +14 -0
  12. data/app/layouts/http.html +8 -0
  13. data/app/layouts/inputs.html +44 -0
  14. data/app/layouts/lockers.html +6 -0
  15. data/app/layouts/navbar.html +9 -0
  16. data/app/layouts/scrolls.html +42 -0
  17. data/app/layouts/sidebars.html +17 -0
  18. data/app/pages/alerts_page.rb +14 -0
  19. data/app/pages/calculator_page.rb +36 -0
  20. data/app/pages/collections_page.rb +9 -0
  21. data/app/pages/home_page.rb +11 -0
  22. data/app/pages/http_page.rb +33 -0
  23. data/app/pages/inputs_page.rb +9 -0
  24. data/app/pages/lockers_page.rb +16 -0
  25. data/app/pages/navbar_page.rb +19 -0
  26. data/app/pages/scrolls_page.rb +5 -0
  27. data/app/pages/sidebars_page.rb +42 -0
  28. data/app/pages/stuff_page.rb +35 -0
  29. data/app/styles/application.css +25 -0
  30. data/app/styles/calculator.css +37 -0
  31. data/app/styles/collections.css +19 -0
  32. data/app/styles/home.css +0 -0
  33. data/app/styles/http.css +24 -0
  34. data/app/styles/inputs.css +47 -0
  35. data/app/styles/scrolls.css +67 -0
  36. data/app/styles/sidebars.css +19 -0
  37. data/lib/assets/fontawesome-webfont.ttf +0 -0
  38. data/lib/assets/under-os.css +115 -0
  39. data/lib/under-os.rb +9 -1
  40. data/lib/under_os/app.rb +33 -0
  41. data/lib/under_os/color.rb +176 -0
  42. data/lib/under_os/config.rb +28 -1
  43. data/lib/under_os/core/kernel.rb +16 -0
  44. data/lib/under_os/core/numeric.rb +23 -0
  45. data/lib/under_os/core/string.rb +40 -0
  46. data/lib/under_os/delegate.rb +3 -2
  47. data/lib/under_os/events.rb +85 -0
  48. data/lib/under_os/file.rb +110 -0
  49. data/lib/under_os/history.rb +50 -0
  50. data/lib/under_os/http/receiver.rb +44 -0
  51. data/lib/under_os/http/request.rb +89 -0
  52. data/lib/under_os/http/response.rb +24 -0
  53. data/lib/under_os/http/session.rb +49 -0
  54. data/lib/under_os/http.rb +5 -0
  55. data/lib/under_os/page/builder.rb +96 -0
  56. data/lib/under_os/page/layout.rb +43 -0
  57. data/lib/under_os/page/matcher.rb +83 -0
  58. data/lib/under_os/page/stylesheet.rb +67 -0
  59. data/lib/under_os/page.rb +153 -0
  60. data/lib/under_os/parser/css.rb +37 -0
  61. data/lib/under_os/parser/html.rb +97 -0
  62. data/lib/under_os/parser.rb +24 -0
  63. data/lib/under_os/point.rb +47 -0
  64. data/lib/under_os/screen.rb +9 -0
  65. data/lib/under_os/timer.rb +65 -0
  66. data/lib/under_os/ui/alert.rb +52 -0
  67. data/lib/under_os/ui/button.rb +22 -0
  68. data/lib/under_os/ui/collection/cell.rb +21 -0
  69. data/lib/under_os/ui/collection/delegate.rb +68 -0
  70. data/lib/under_os/ui/collection/item.rb +32 -0
  71. data/lib/under_os/ui/collection/layout.rb +43 -0
  72. data/lib/under_os/ui/collection/styles.rb +15 -0
  73. data/lib/under_os/ui/collection.rb +63 -0
  74. data/lib/under_os/ui/icon/awesome.rb +376 -0
  75. data/lib/under_os/ui/icon/engine.rb +10 -0
  76. data/lib/under_os/ui/icon.rb +42 -0
  77. data/lib/under_os/ui/image.rb +30 -0
  78. data/lib/under_os/ui/input.rb +41 -0
  79. data/lib/under_os/ui/label.rb +21 -0
  80. data/lib/under_os/ui/locker.rb +42 -0
  81. data/lib/under_os/ui/navbar.rb +115 -0
  82. data/lib/under_os/ui/progress.rb +17 -0
  83. data/lib/under_os/ui/scroll.rb +41 -0
  84. data/lib/under_os/ui/select.rb +98 -0
  85. data/lib/under_os/ui/sidebar.rb +45 -0
  86. data/lib/under_os/ui/slider.rb +49 -0
  87. data/lib/under_os/ui/spinner.rb +23 -0
  88. data/lib/under_os/ui/style/fonts.rb +60 -0
  89. data/lib/under_os/ui/style/margins.rb +160 -0
  90. data/lib/under_os/ui/style/outlining.rb +98 -0
  91. data/lib/under_os/ui/style/positioning.rb +169 -0
  92. data/lib/under_os/ui/style.rb +21 -0
  93. data/lib/under_os/ui/switch.rb +29 -0
  94. data/lib/under_os/ui/textarea.rb +14 -0
  95. data/lib/under_os/ui/utils/animation.rb +99 -0
  96. data/lib/under_os/ui/utils/commons.rb +70 -0
  97. data/lib/under_os/ui/utils/dimensions.rb +37 -0
  98. data/lib/under_os/ui/utils/editable.rb +43 -0
  99. data/lib/under_os/ui/utils/events.rb +75 -0
  100. data/lib/under_os/ui/utils/manipulation.rb +44 -0
  101. data/lib/under_os/ui/utils/position.rb +21 -0
  102. data/lib/under_os/ui/utils/size.rb +21 -0
  103. data/lib/under_os/ui/utils/styles.rb +89 -0
  104. data/lib/under_os/ui/utils/traversing.rb +44 -0
  105. data/lib/under_os/ui/utils/wrap.rb +77 -0
  106. data/lib/under_os/ui/view.rb +31 -0
  107. data/lib/under_os/ui.rb +3 -0
  108. data/lib/under_os.rb +2 -2
  109. data/resources/Default-568h@2x.png +0 -0
  110. data/resources/test.png +0 -0
  111. data/spec/assets/app.css +13 -0
  112. data/spec/assets/test.css +7 -0
  113. data/spec/assets/test.html +3 -0
  114. data/spec/assets/test_page.rb +2 -0
  115. data/spec/lib/core/numeric_spec.rb +37 -0
  116. data/spec/lib/core/string_spec.rb +87 -0
  117. data/spec/lib/under_os/color_spec.rb +133 -0
  118. data/spec/lib/under_os/events_spec.rb +71 -0
  119. data/spec/lib/under_os/file_spec.rb +98 -0
  120. data/spec/lib/under_os/page/builder_spec.rb +128 -0
  121. data/spec/lib/under_os/page/layout_spec.rb +18 -0
  122. data/spec/lib/under_os/page/matcher_spec.rb +154 -0
  123. data/spec/lib/under_os/page/stylesheet_spec.rb +83 -0
  124. data/spec/lib/under_os/page_spec.rb +5 -0
  125. data/spec/lib/under_os/parser/css_spec.rb +77 -0
  126. data/spec/lib/under_os/parser/html_spec.rb +152 -0
  127. data/spec/lib/under_os/parser_spec.rb +16 -0
  128. data/spec/lib/under_os/point_spec.rb +54 -0
  129. data/spec/lib/under_os/screen_spec.rb +11 -0
  130. data/spec/lib/under_os/timer_spec.rb +93 -0
  131. data/spec/lib/under_os/ui/button_spec.rb +5 -0
  132. data/spec/lib/under_os/ui/collection_spec.rb +19 -0
  133. data/spec/lib/under_os/ui/icon_spec.rb +26 -0
  134. data/spec/lib/under_os/ui/image_spec.rb +39 -0
  135. data/spec/lib/under_os/ui/input_spec.rb +77 -0
  136. data/spec/lib/under_os/ui/label_spec.rb +22 -0
  137. data/spec/lib/under_os/ui/locker_spec.rb +31 -0
  138. data/spec/lib/under_os/ui/progress_spec.rb +31 -0
  139. data/spec/lib/under_os/ui/scroll_spec.rb +40 -0
  140. data/spec/lib/under_os/ui/select_spec.rb +131 -0
  141. data/spec/lib/under_os/ui/sidebar_spec.rb +35 -0
  142. data/spec/lib/under_os/ui/slider_spec.rb +65 -0
  143. data/spec/lib/under_os/ui/spinner_spec.rb +57 -0
  144. data/spec/lib/under_os/ui/style/fonts_spec.rb +73 -0
  145. data/spec/lib/under_os/ui/style/margins_spec.rb +106 -0
  146. data/spec/lib/under_os/ui/style/outlining_spec.rb +69 -0
  147. data/spec/lib/under_os/ui/style/positioning_spec.rb +69 -0
  148. data/spec/lib/under_os/ui/style_spec.rb +19 -0
  149. data/spec/lib/under_os/ui/switch_spec.rb +56 -0
  150. data/spec/lib/under_os/ui/textarea_spec.rb +30 -0
  151. data/spec/lib/under_os/ui/utils/commons_spec.rb +81 -0
  152. data/spec/lib/under_os/ui/utils/manipulation_spec.rb +130 -0
  153. data/spec/lib/under_os/ui/utils/styles_spec.rb +140 -0
  154. data/spec/lib/under_os/ui/utils/traversing_spec.rb +124 -0
  155. data/spec/lib/under_os/ui/utils/wrap_spec.rb +69 -0
  156. data/spec/lib/under_os/ui/view_spec.rb +39 -0
  157. data/under-os.gemspec +32 -0
  158. metadata +225 -11
  159. data/lib/under_os/application.rb +0 -16
  160. data/lib/under_os/window.rb +0 -5
@@ -0,0 +1,110 @@
1
+ class UnderOs::File
2
+ attr_reader :path, :mode
3
+
4
+ def self.open(path, *args, &block)
5
+ new path, *args, &block
6
+ end
7
+
8
+ def self.read(path, *args)
9
+ new(path, *args).read
10
+ end
11
+
12
+ def self.write(path, content)
13
+ new(path, "w"){|f| f.write(content) }
14
+ end
15
+
16
+ def self.size(path)
17
+ new(path).size
18
+ end
19
+
20
+ def self.delete(path)
21
+ NSFileManager.defaultManager.removeItemAtPath(UnderOs::File.path(path), error:nil)
22
+ end
23
+
24
+ def self.path(path)
25
+ path.to_s[0] == '/' ? path : NSHomeDirectory().stringByAppendingPathComponent(path)
26
+ end
27
+
28
+ def self.tmp(filename, mode="w", &block)
29
+ new NSTemporaryDirectory().stringByAppendingPathComponent(filename), mode, &block
30
+ end
31
+
32
+ def self.exists?(path, is_dir=nil)
33
+ NSFileManager.defaultManager.fileExistsAtPath(UnderOs::File.path(path), isDirectory:is_dir)
34
+ end
35
+
36
+ def self.file?(path)
37
+ exists?(path, false)
38
+ end
39
+
40
+ def self.dir?(path)
41
+ exists?(path, true)
42
+ end
43
+
44
+ def initialize(path, mode="r", &block)
45
+ @path = UnderOs::File.path(path)
46
+ @mode = mode
47
+
48
+ yield(self) if block_given?
49
+ end
50
+
51
+ def url
52
+ @url ||= NSURL.fileURLWithPath(@path)
53
+ end
54
+
55
+ def read(size=nil)
56
+ open
57
+ data = if size == nil
58
+ @handle.readDataToEndOfFile
59
+ else
60
+ @handle.readDataOfLength(size)
61
+ end
62
+ close
63
+
64
+ @mode == "b" ? data : NSString.alloc.initWithData(data, encoding:NSUTF8StringEncoding)
65
+ end
66
+
67
+ def write(content)
68
+ if ! UnderOs::File.exists?(@path)
69
+ NSFileManager.defaultManager.createFileAtPath @path, contents:nil, attributes:nil
70
+ end
71
+
72
+ content = content.dataUsingEncoding(NSUTF8StringEncoding) if content.is_a?(String)
73
+
74
+ open
75
+ @handle.writeData content
76
+ close
77
+ end
78
+
79
+ def open
80
+ @handle = if @mode == "r"
81
+ NSFileHandle.fileHandleForReadingAtPath(@path)
82
+ else
83
+ NSFileHandle.fileHandleForWritingAtPath(@path)
84
+ end
85
+
86
+ @handle.seekToEndOfFile if ["w+", "a"].include?(@mode)
87
+ end
88
+
89
+ def close
90
+ @handle.closeFile
91
+ @handle = nil
92
+ end
93
+
94
+ def seek(offset)
95
+ @handle.seekToFileOffset(offset)
96
+ end
97
+
98
+ def rewind
99
+ seek 0
100
+ end
101
+
102
+ def size
103
+ NSFileManager.defaultManager.attributesOfItemAtPath(@path, error: nil).fileSize
104
+ end
105
+
106
+ def truncate(size)
107
+ @handle.truncateFileAtOffset(size)
108
+ end
109
+
110
+ end
@@ -0,0 +1,50 @@
1
+ class UnderOs::History
2
+ attr_reader :_, :navbar
3
+
4
+ def initialize
5
+ @_ = UINavigationController.alloc
6
+ @navbar = UnderOs::UI::Navbar.new(@_)
7
+ end
8
+
9
+ def root_page
10
+ @_.topViewController.wrapper
11
+ end
12
+
13
+ def root_page=(page)
14
+ @_.initWithRootViewController(page._)
15
+ end
16
+
17
+ def current_page
18
+ @_.visibleViewController.wrapper
19
+ end
20
+
21
+ def push(page, animated=true)
22
+ if pages.include?(page)
23
+ pop_to(page)
24
+ else
25
+ @_.pushViewController(page._, animated: animated)
26
+ end
27
+ end
28
+
29
+ alias :<< :push
30
+
31
+ def pop(page=nil, animated=true)
32
+ if page
33
+ @_.popToViewController(page._, animated: animated)
34
+ else
35
+ @_.popViewControllerAnimated(animated)
36
+ end
37
+ end
38
+
39
+ def pages
40
+ @_.viewControllers.map{|c| c.wrapper rescue nil }.compact
41
+ end
42
+
43
+ def pop_to(page, animated=true)
44
+ pop(page, animated)
45
+ end
46
+
47
+ def pop_to_root(animated=true)
48
+ @_.popToRootViewControllerAnimated(animated)
49
+ end
50
+ end
@@ -0,0 +1,44 @@
1
+ #
2
+ # A little wrap to handle iOS HTTP requests receiving
3
+ #
4
+ class UnderOs::HTTP::Request
5
+ class Receiver
6
+ def initialize(request, stream=false)
7
+ @request = request
8
+ @stream = stream
9
+ @data = NSMutableData.dataWithCapacity(0)
10
+ end
11
+
12
+ def connection(connection, didReceiveResponse:response)
13
+ @data.setLength(0)
14
+ @response = UnderOs::HTTP::Response.new(response, @data)
15
+
16
+ emit(:response)
17
+ end
18
+
19
+ def connection(connection, didReceiveData:data)
20
+ @data.setLength(0) if @stream
21
+ @data.appendData(data)
22
+ emit(:data)
23
+ end
24
+
25
+ # def connection(connection, willCacheResponse:cachedResponse)
26
+ # return nil # don't cache
27
+ # end
28
+
29
+ def connection(connection, didFailWithError:error)
30
+ @response = UnderOs::HTTP::Response.new(error, @data)
31
+
32
+ emit(:failure)
33
+ end
34
+
35
+ def connectionDidFinishLoading(connection)
36
+ emit(:success)
37
+ end
38
+
39
+ def emit(event)
40
+ @request.emit(event, response: @response)
41
+ @request.emit(:complete, response: @response) if event == :failure || event == :success
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,89 @@
1
+ #
2
+ # Options:
3
+ #
4
+ # * :method - GET, POST, ...
5
+ # * :cookies - Hash of cookie values
6
+ # * :stream - boolean, in case you want to stream stuff
7
+ #
8
+ # Events:
9
+ #
10
+ # * :response - when response header is received
11
+ # * :data - when a chunk of data is received
12
+ # * :success - when the request is successfully finished
13
+ # * :failure - when request has failed for whatever reason
14
+ # * :complete - when it's complete (either way)
15
+ #
16
+ class UnderOs::HTTP::Request
17
+ include UnderOs::Events
18
+
19
+ attr_reader :url, :method, :params
20
+
21
+ def initialize(url, options={}, &block)
22
+ @url = url
23
+ @options = options
24
+
25
+ on :complete, &block if block_given?
26
+ end
27
+
28
+ def on(*args, &block)
29
+ super *args do |event|
30
+ args = block.arity == 0 ? [] : [event.params[:response]]
31
+ block.call *args
32
+ end
33
+ end
34
+
35
+ def send
36
+ @request = build_request
37
+ @receiver = Receiver.new(self, @options[:stream])
38
+ @connection = NSURLConnection.alloc.initWithRequest(@request, delegate:@receiver)
39
+ @connection.start
40
+ end
41
+
42
+ def cancel
43
+ @connection.cancel
44
+ end
45
+
46
+ def method
47
+ method = @options[:method] || :get
48
+ method = method.to_s.upcase
49
+ method = 'GET' unless %w[GET POST PUT DELETE PATCH HEAD].include?(method)
50
+ method
51
+ end
52
+
53
+ def headers
54
+ @options[:headers] || {}
55
+ end
56
+
57
+ def cookies
58
+ @options[:cookies] || {}
59
+ end
60
+
61
+ protected
62
+
63
+ def build_request
64
+ url = NSURL.URLWithString(NSString.stringWithFormat(@url))
65
+ NSMutableURLRequest.requestWithURL(url).tap do |request|
66
+ request.setHTTPMethod self.method
67
+ #request.setHTTPBody self.params
68
+
69
+ cookies = self.cookies.map do |key, value|
70
+ NSHTTPCookie.cookieWithProperties({
71
+ NSHTTPCookieDomain => url.host,
72
+ NSHTTPCookiePath => "/",
73
+ NSHTTPCookieName => key.to_s,
74
+ NSHTTPCookieValue => value.to_s
75
+ })
76
+ end
77
+
78
+ request.setAllHTTPHeaderFields NSHTTPCookie.requestHeaderFieldsWithCookies(cookies) if cookies.size > 0
79
+
80
+ headers.each do |key, value|
81
+ request.addValue value, forHTTPHeaderField:key
82
+ end
83
+
84
+ # [newRequest addValue:@"application/x-www-form-urlencoded;charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
85
+ # [newRequest setHTTPBody:[query dataUsingEncoding:NSUTF8StringEncoding]];
86
+ end
87
+ end
88
+ end
89
+
@@ -0,0 +1,24 @@
1
+ class UnderOs::HTTP::Response
2
+ attr_reader :data
3
+
4
+ def initialize(response, data)
5
+ @response = response
6
+ @data = data # raw NSData
7
+ end
8
+
9
+ def headers
10
+ @response.allHeaderFields
11
+ end
12
+
13
+ def body
14
+ @body ||= @data.to_s
15
+ end
16
+
17
+ def content_length
18
+ headers["Content-Length"].to_i
19
+ end
20
+
21
+ def content_type
22
+ headers["Content-Type"]
23
+ end
24
+ end
@@ -0,0 +1,49 @@
1
+ #
2
+ # Basically keeps track of cookies between the requests
3
+ #
4
+ class Session
5
+ def initialize(default_options={})
6
+ @options = default_options
7
+ @options[:cookies] ||= {}
8
+ end
9
+
10
+ def cookies
11
+ @options[:cookies]
12
+ end
13
+
14
+ def get(url, options={}, &block)
15
+ request(url, {method: 'GET'}.merge(options), &block).send
16
+ end
17
+
18
+ def post(url, options={}, &block)
19
+ request(url, {method: 'POST'}.merge(options), &block).send
20
+ end
21
+
22
+ def put(url, options={}, &block)
23
+ request(url, {method: 'PUT'}.merge(options), &block).send
24
+ end
25
+
26
+ def delete(url, options={}, &block)
27
+ request(url, {method: 'DELETE'}.merge(options), &block).send
28
+ end
29
+
30
+ def request(url, options={}, &block)
31
+ options = options.merge(@options){|k,a,b| a.merge(b) }
32
+
33
+ UnderOs::HTTP::Request.new(url, options, &block).tap do |request|
34
+ request.on :response do |response|
35
+ save_cookies response.headers["Set-Cookie"] || ''
36
+ end
37
+ end
38
+ end
39
+
40
+ protected
41
+
42
+ def save_cookies(cookies)
43
+ cookies.scan(/([a-z_]+?)=([^; ]+)/).each do |key, value|
44
+ unless ['path', 'domain', 'expires'].include?(key)
45
+ @options[:cookies][key] = value
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,5 @@
1
+ class UnderOs::HTTP
2
+ def self.get(url, options={}, &block)
3
+ Request.new(url, options.merge(method: :get), &block).send
4
+ end
5
+ end
@@ -0,0 +1,96 @@
1
+ class UnderOs::Page::Builder
2
+
3
+ def self.views_from(source)
4
+ @inst ||= new
5
+ if source.is_a?(String)
6
+ @inst.from_html(source)
7
+ else
8
+ @inst.from_nodes(source)
9
+ end
10
+ end
11
+
12
+ def from_html(source)
13
+ @html ||= UnderOs::Parser::HTML.new
14
+ from_nodes @html.parse(source)
15
+ end
16
+
17
+ def from_nodes(list)
18
+ list.map do |node|
19
+ build_view_from(node)
20
+ end
21
+ end
22
+
23
+ def build_view_from(node)
24
+ klass = class_for(node)
25
+ options = options_from_attrs(node[:attrs] || {})
26
+
27
+ if klass.instance_methods.include?(:text) && node[:text]
28
+ options[:text] = node[:text]
29
+ end
30
+
31
+ klass.new(options).tap do |view|
32
+ if node[:children] && node[:children].any?
33
+ build_children_for(view, node[:children])
34
+ end
35
+ end
36
+ end
37
+
38
+ def class_for(node)
39
+ if node[:attrs] && node[:attrs][:wrapper].is_a?(String)
40
+ node[:attrs].delete(:wrapper).constantize
41
+ else
42
+ UnderOs::UI::Wrap::WRAPS_TAGS_MAP[node[:tag]] || UnderOs::UI::View
43
+ end
44
+ end
45
+
46
+ def options_from_attrs(hash)
47
+ {}.tap do |options|
48
+ hash.each do |key, value|
49
+ options[key] = value
50
+ end
51
+ end
52
+ end
53
+
54
+ def build_children_for(view, nodes)
55
+ if view.is_a?(UnderOs::UI::Select)
56
+ view.optgroups = select_optgroups_from(nodes)
57
+ elsif view.is_a?(UnderOs::UI::Collection)
58
+ find_collection_items_for(view, nodes)
59
+ else
60
+ from_nodes(nodes).each do |child|
61
+ view.insert child
62
+ end
63
+ end
64
+ end
65
+
66
+ def select_optgroups_from(nodes)
67
+ nodes = [{tag: 'optgroup', children: nodes}] if nodes[0][:tag] == 'option'
68
+
69
+ nodes.map do |group|
70
+ {}.tap do |options|
71
+ group[:children].each do |option|
72
+ if option[:tag] == 'option'
73
+ label = option[:text]
74
+ value = option[:attrs][:value] || label
75
+
76
+ options[value] = label if value && label
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ def find_collection_items_for(collection, nodes)
84
+ nodes.each do |node|
85
+ klass = class_for(node)
86
+
87
+ if klass <= UnderOs::UI::Collection::Item
88
+ klass.build(collection) { from_nodes(node[:children]) }
89
+ end
90
+
91
+ # header
92
+ # footer
93
+ end
94
+ end
95
+
96
+ end
@@ -0,0 +1,43 @@
1
+ class UnderOs::Page::Layout
2
+
3
+ def initialize(page)
4
+ @page = page
5
+
6
+ build_layout_from_xib || build_layout_from_html || build_layout_from_nothing
7
+
8
+ @page.view = UnderOs::UI::View.new(@page._.view)
9
+ @page.view.instance_variable_set('@_tag_name', 'PAGE')
10
+ end
11
+
12
+ def build_layout_from_xib
13
+ if filename = find_layout_with_type('xib')
14
+ @page._.view = NSBundle.mainBundle.loadNibNamed(filename.sub(/\.xib$/, ''), owner:self, options:nil)[0]
15
+ end
16
+ end
17
+
18
+ def build_layout_from_html
19
+ if filename = find_layout_with_type('html')
20
+ if layout = UnderOs::Parser.parse(filename)
21
+ if view = UnderOs::Page::Builder.views_from(layout)[0]
22
+ @page._.view = view._
23
+ @page.title = layout[0][:attrs][:title] || ''
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ def build_layout_from_nothing
30
+ @page._.view = UIView.alloc.init
31
+ @page._.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
32
+ end
33
+
34
+ def find_layout_with_type(ext)
35
+ filename = @page.class.layout || "#{@page.name}.#{ext}"
36
+ filename, type = filename.match(/^(.+?)\.([a-z]+)$/).to_a.slice(1,2)
37
+
38
+ if type == ext && NSBundle.mainBundle.pathForResource(filename, ofType:type)
39
+ "#{filename}.#{type}"
40
+ end
41
+ end
42
+
43
+ end
@@ -0,0 +1,83 @@
1
+ class UnderOs::Page::StylesMatcher
2
+
3
+ def self.new(css_rule)
4
+ @cache ||= {}
5
+ @cache[css_rule] ||= super
6
+ end
7
+
8
+ def initialize(css_rule)
9
+ css_rule = css_rule.strip
10
+ rules = css_rule.scan(/([\S]+)/).map(&:first)
11
+ @rule = parse(rules.pop)
12
+ @parent = rules.size == 0 ? false : self.class.new(rules.join(' '))
13
+ end
14
+
15
+ def match(view)
16
+ score_for(view) != 0
17
+ end
18
+
19
+ def score_for(view)
20
+ id_score = id_score_for(view)
21
+ tag_score = tag_score_for(view)
22
+ class_score = class_score_for(view)
23
+
24
+ return 0 if @rule[:id] && id_score == 0
25
+ return 0 if @rule[:tag] && tag_score == 0
26
+ return 0 if @rule[:classes].size > 0 && class_score == 0
27
+ return 0 if (this_score = id_score + tag_score + class_score) == 0
28
+
29
+ parent_score = parent_score_for(view)
30
+
31
+ return 0 if @parent && parent_score == 0
32
+
33
+ parent_score + this_score
34
+ end
35
+
36
+ private
37
+
38
+ def id_score_for(view)
39
+ @rule[:id] == view.id ? 1 : 0
40
+ end
41
+
42
+ def tag_score_for(view)
43
+ @rule[:tag] == view.tagName ? 1 : 0
44
+ end
45
+
46
+ def class_score_for(view)
47
+ match = @rule[:classes] & view.classNames
48
+ match.size == @rule[:classes].size ? match.size : 0
49
+ end
50
+
51
+ def parent_score_for(view)
52
+ return 0 if ! @parent
53
+
54
+ parent = view; score = 0
55
+
56
+ while parent = parent.parent
57
+ score = @parent.score_for(parent)
58
+ break if score > 0
59
+ end
60
+
61
+ score
62
+ end
63
+
64
+ def parse(string)
65
+ {}.tap do |rule|
66
+ if m = string.match(/^([a-z]+)/)
67
+ rule[:tag] = m[1].upcase
68
+ else
69
+ rule[:tag] = false # so it wouldn't match nil
70
+ end
71
+
72
+ if m = string.match(/#([a-z_\-0-9]+)/)
73
+ rule[:id] = m[1]
74
+ else
75
+ rule[:id] = false # so it wouldn't match nil
76
+ end
77
+
78
+ if m = string.scan(/(\.)([a-z_\-0-9]+)/)
79
+ rule[:classes] = m.map{|c| c[1]}
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,67 @@
1
+ class UnderOs::Page::Stylesheet
2
+ attr_reader :rules
3
+
4
+ def initialize(styles={})
5
+ @rules = {}
6
+
7
+ styles.each do |rule, style|
8
+ self[rule] = style
9
+ end
10
+ end
11
+
12
+ def styles_for(view)
13
+ {}.tap do |styles|
14
+ weighted_styles_for(view).each do |hash|
15
+ hash.each do |key, value|
16
+ styles[key] = value
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ def [](rule)
23
+ @rules[rule.to_s]
24
+ end
25
+
26
+ def []=(rule, values)
27
+ @rules[rule.to_s] ||= {}
28
+ @rules[rule.to_s].merge! values
29
+ end
30
+
31
+ def <<(another_stylesheet)
32
+ another_stylesheet.rules.each do |rule, styles|
33
+ self[rule] = styles
34
+ end
35
+ end
36
+
37
+ def +(another_stylesheet)
38
+ self.class.new.tap do |combined_sheet|
39
+ combined_sheet << self
40
+ combined_sheet << another_stylesheet
41
+ end
42
+ end
43
+
44
+ def load(filename)
45
+ UnderOs::Parser.parse(filename).each do |rule, styles|
46
+ self[rule] = styles
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def weighted_styles_for(view)
53
+ find_styles_for(view).
54
+ sort{|a,b| a[:score] <=> b[:score]}.
55
+ map{|e| e[:style]}
56
+ end
57
+
58
+ def find_styles_for(view)
59
+ [].tap do |styles|
60
+ @rules.each do |css, rule|
61
+ score = UnderOs::Page::StylesMatcher.new(css).score_for(view)
62
+ styles << {score: score, style: rule} if score != 0
63
+ end
64
+ end
65
+ end
66
+
67
+ end