under-os 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +3 -1
- data/README.md +4 -12
- data/Rakefile +1 -0
- data/app/layouts/home.html +9 -10
- data/app/pages/collections_page.rb +6 -0
- data/app/pages/http_page.rb +9 -4
- data/app/styles/collections.css +4 -0
- data/lib/under-os.rb +2 -4
- data/lib/under_os/color.rb +18 -10
- data/lib/under_os/core/array.rb +5 -0
- data/lib/under_os/core/hash.rb +10 -0
- data/lib/under_os/core/json.rb +19 -0
- data/lib/under_os/core/object.rb +9 -0
- data/lib/under_os/core/string.rb +40 -0
- data/lib/under_os/file.rb +1 -1
- data/lib/under_os/http/cookies.rb +30 -0
- data/lib/under_os/http/request.rb +37 -20
- data/lib/under_os/http/response.rb +4 -0
- data/lib/under_os/http.rb +27 -1
- data/lib/under_os/ui/collection/delegate.rb +4 -2
- data/lib/under_os/ui/collection.rb +3 -1
- data/lib/under_os/ui/locker.rb +1 -1
- data/lib/under_os/ui/style/fonts.rb +18 -24
- data/lib/under_os/ui/style/margins.rb +34 -30
- data/lib/under_os.rb +1 -1
- data/spec/lib/core/hash_spec.rb +19 -0
- data/spec/lib/core/json_spec.rb +32 -0
- data/spec/lib/core/string_spec.rb +34 -0
- data/spec/lib/under_os/http/cookies_spec.rb +13 -0
- data/spec/lib/under_os/http/request_spec.rb +44 -0
- data/spec/lib/under_os/http_spec.rb +20 -0
- data/under-os.gemspec +4 -2
- metadata +38 -9
- data/app/pages/stuff_page.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ff1789b7dfe17082f36cf9eea7c8c3444077716
|
4
|
+
data.tar.gz: 520c56f69fdc975f55be7e49d87f3742c12e4dca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea4aab7ec336bd41cde899ab86f4caeaa9d206cb7261915eb85157b97a117b628b41e204df63627ac9e18f36e99e0cedc70f876d7441a6cee27bfbe74afb2aef
|
7
|
+
data.tar.gz: 3e7eee7f55f17c5952b96741f2db01cd7ea38e2842476eca515f27a3e093cb8c5516bef93f8dd51cfbd86be60c398d1f1e861540ed63e6283e4183ed41ff9e2c
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
# Under OS
|
1
|
+
# Under OS [![Build Status](https://travis-ci.org/under-os/under-os.png)](https://travis-ci.org/under-os/under-os) [![Code Climate](https://codeclimate.com/github/under-os/under-os.png)](https://codeclimate.com/github/under-os/under-os)
|
2
2
|
|
3
|
-
|
3
|
+
[UnderOS](http://under-os.com) is an experiment in building a thin web-like wrapper over iOS using rubymotion
|
4
4
|
|
5
|
-
The idea is to use
|
5
|
+
The idea is to use encapsulation instead of monkey patching and build the
|
6
6
|
entire development platform correctly and from scratch.
|
7
7
|
|
8
|
-
The result should be a
|
8
|
+
The result should be a _webbish_ infrastructure that uses ruby instead
|
9
9
|
of JavaScript and compiles into native code in the end.
|
10
10
|
|
11
11
|
That's gonna be legendary!
|
@@ -37,14 +37,6 @@ Now, Run it!
|
|
37
37
|
cd test && rake
|
38
38
|
```
|
39
39
|
|
40
|
-
## What's What
|
41
|
-
|
42
|
-
* `app/layouts` - where you keep your HTML layouts
|
43
|
-
* `app/pages` - where the page scripts live
|
44
|
-
* `app/styles` - where the CSS files go
|
45
|
-
* `app/models` - where your data models chill
|
46
|
-
* `app/views` - where you keep your custom views/components classes
|
47
|
-
|
48
40
|
|
49
41
|
# Copyright & License
|
50
42
|
|
data/Rakefile
CHANGED
data/app/layouts/home.html
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
<page title="Home">
|
2
2
|
<view id="buttons">
|
3
|
-
<button id="b1" data-page="
|
4
|
-
<button id="b2" data-page="
|
5
|
-
<button id="b3" data-page="
|
6
|
-
<button id="b4" data-page="
|
7
|
-
<button id="b5" data-page="
|
8
|
-
<button id="b6" data-page="
|
9
|
-
<button id="b7" data-page="
|
10
|
-
<button id="b8" data-page="
|
11
|
-
<button id="b9" data-page="
|
12
|
-
<button id="b10" data-page="collections">Collections</button>
|
3
|
+
<button id="b1" data-page="calculator">Calculator Demo</button>
|
4
|
+
<button id="b2" data-page="inputs">Inputs Demo</button>
|
5
|
+
<button id="b3" data-page="sidebars">Sidebar Demo</button>
|
6
|
+
<button id="b4" data-page="scrolls">Scrolls Demo</button>
|
7
|
+
<button id="b5" data-page="navbar">Navbar Demo</button>
|
8
|
+
<button id="b6" data-page="alerts">Alerts Demo</button>
|
9
|
+
<button id="b7" data-page="lockers">Lockers Demo</button>
|
10
|
+
<button id="b8" data-page="http">HTTP Demo</button>
|
11
|
+
<button id="b9" data-page="collections">Collections</button>
|
13
12
|
</view>
|
14
13
|
</page>
|
@@ -5,5 +5,11 @@ class CollectionsPage < UnderOs::Page
|
|
5
5
|
@collection.on :item do |item, index|
|
6
6
|
item.children[0].text = "##{index + 1}"
|
7
7
|
end
|
8
|
+
@collection.on :select do |item|
|
9
|
+
item.addClass 'selected'
|
10
|
+
end
|
11
|
+
@collection.on :unselect do |item|
|
12
|
+
item.removeClass 'selected'
|
13
|
+
end
|
8
14
|
end
|
9
15
|
end
|
data/app/pages/http_page.rb
CHANGED
@@ -13,7 +13,11 @@ class HttpPage < UnderOs::Page
|
|
13
13
|
@locker.show
|
14
14
|
|
15
15
|
UnderOs::HTTP.get search_url do |response|
|
16
|
-
|
16
|
+
if image_url = parse_first_image_url(response)
|
17
|
+
@result.load image_url do
|
18
|
+
@locker.hide
|
19
|
+
end
|
20
|
+
else
|
17
21
|
@locker.hide
|
18
22
|
end
|
19
23
|
end
|
@@ -22,12 +26,13 @@ class HttpPage < UnderOs::Page
|
|
22
26
|
def search_url
|
23
27
|
query = @search.value
|
24
28
|
query = 'puppy' if query.empty?
|
29
|
+
query = String.new(query).url_encode
|
25
30
|
|
26
|
-
"https://
|
31
|
+
"https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=#{query}"
|
27
32
|
end
|
28
33
|
|
29
|
-
def parse_first_image_url(
|
30
|
-
|
34
|
+
def parse_first_image_url(response)
|
35
|
+
response.json["responseData"]["results"][0]["url"] rescue nil # ftw!
|
31
36
|
end
|
32
37
|
|
33
38
|
end
|
data/app/styles/collections.css
CHANGED
data/lib/under-os.rb
CHANGED
@@ -8,16 +8,14 @@ Motion::Project::App.instance_eval do
|
|
8
8
|
Dir.glob(File.dirname(__FILE__) + '/**/*.rb').reverse.each do |file|
|
9
9
|
app.files.insert(0, file) if file != __FILE__
|
10
10
|
end
|
11
|
-
end
|
12
11
|
|
13
|
-
setup_before_under_os *args do |app|
|
14
12
|
app.resources_dirs << File.dirname(__FILE__) + "/assets"
|
15
13
|
app.resources_dirs << "app/styles/" if File.exists?("app/styles")
|
16
14
|
app.resources_dirs << "app/layouts/" if File.exists?("app/layouts")
|
17
15
|
|
18
16
|
app.fonts << "fontawesome-webfont.ttf"
|
19
|
-
|
20
|
-
instance_exec app, &block
|
21
17
|
end
|
18
|
+
|
19
|
+
setup_before_under_os *args, &block
|
22
20
|
end
|
23
21
|
end
|
data/lib/under_os/color.rb
CHANGED
@@ -94,26 +94,28 @@ class UnderOs::Color
|
|
94
94
|
|
95
95
|
def color_from_string(name)
|
96
96
|
name = name.downcase.strip
|
97
|
-
name =
|
98
|
-
name = 'darkGray' if name == 'darkgray'
|
99
|
-
name = 'lightGray' if name == 'lightgray'
|
97
|
+
name = ALIASES[name] || name
|
100
98
|
|
101
99
|
return UIColor.send("#{name}Color") if IOS_COLORS.include?(name)
|
102
100
|
|
103
101
|
name = HTML_COLORS[name] || name
|
104
102
|
name = "#" + name[1]*2 + name[2]*2 + name[3]*2 if name =~ /^#[abcdef0-9]{3}$/
|
105
103
|
|
106
|
-
r, g, b, a =
|
107
|
-
|
108
|
-
|
104
|
+
r, g, b, a = color_2_rgba(name)
|
105
|
+
|
106
|
+
color_from_array(r, g, b, a || 1.0)
|
107
|
+
end
|
108
|
+
|
109
|
+
def color_2_rgba(color)
|
110
|
+
if color =~ /^#[abcdef0-9]{6}$/
|
111
|
+
hex_2_rgb(color)
|
112
|
+
elsif m = color.match(/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d*)\s*\)$/)
|
109
113
|
[m[1].to_i, m[2].to_i, m[3].to_i]
|
110
|
-
elsif m =
|
114
|
+
elsif m = color.match(/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d*)\s*,\s*([\d\.]+)\s*\)$/)
|
111
115
|
[m[1].to_i, m[2].to_i, m[3].to_i, m[4].to_f]
|
112
116
|
else
|
113
|
-
raise "Malformed color spec: #{
|
117
|
+
raise "Malformed color spec: #{color.inspect}"
|
114
118
|
end
|
115
|
-
|
116
|
-
color_from_array(r, g, b, a || 1.0)
|
117
119
|
end
|
118
120
|
|
119
121
|
def color_from_param(param) # 0.0..1.0
|
@@ -144,6 +146,12 @@ class UnderOs::Color
|
|
144
146
|
end
|
145
147
|
end
|
146
148
|
|
149
|
+
ALIASES = {
|
150
|
+
'transparent' => 'clear',
|
151
|
+
'darkgray' => 'darkGray',
|
152
|
+
'lightgray' => 'lightGray'
|
153
|
+
}
|
154
|
+
|
147
155
|
IOS_COLORS = %w[
|
148
156
|
black
|
149
157
|
darkGray
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class JSON
|
2
|
+
class Malformed < StandardError ; end
|
3
|
+
|
4
|
+
def self.parse(string, encoding=nil)
|
5
|
+
error = Pointer.new(:object)
|
6
|
+
data = NSJSONSerialization.JSONObjectWithData string.to_data(encoding), options:0, error:error
|
7
|
+
|
8
|
+
if error[0]
|
9
|
+
raise Malformed
|
10
|
+
else
|
11
|
+
data
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.generate(object, pretty=false)
|
16
|
+
options = pretty ? NSJSONWritingPrettyPrinted : 0
|
17
|
+
NSJSONSerialization.dataWithJSONObject(object, options:options, error:nil).to_s
|
18
|
+
end
|
19
|
+
end
|
data/lib/under_os/core/string.rb
CHANGED
@@ -37,4 +37,44 @@ class String
|
|
37
37
|
end
|
38
38
|
constant
|
39
39
|
end
|
40
|
+
|
41
|
+
def url_encode(encoding=nil)
|
42
|
+
stringByAddingPercentEscapesUsingEncoding ENCODINGS[encoding] || NSUTF8StringEncoding
|
43
|
+
end
|
44
|
+
|
45
|
+
def url_decode(encoding=nil)
|
46
|
+
stringByReplacingPercentEscapesUsingEncoding ENCODINGS[encoding] || NSUTF8StringEncoding
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_data(encoding=nil)
|
50
|
+
dataUsingEncoding ENCODINGS[encoding] || NSUTF8StringEncoding
|
51
|
+
end
|
52
|
+
|
53
|
+
ENCODINGS = {
|
54
|
+
'utf-8' => NSUTF8StringEncoding,
|
55
|
+
'utf-16' => NSUTF16StringEncoding,
|
56
|
+
'utf-32' => NSUTF32StringEncoding,
|
57
|
+
'ascii' => NSASCIIStringEncoding,
|
58
|
+
'latin1' => NSISOLatin1StringEncoding,
|
59
|
+
'latin2' => NSISOLatin2StringEncoding,
|
60
|
+
'cp1250' => NSWindowsCP1250StringEncoding,
|
61
|
+
'cp1251' => NSWindowsCP1251StringEncoding,
|
62
|
+
'cp1252' => NSWindowsCP1252StringEncoding,
|
63
|
+
'cp1253' => NSWindowsCP1253StringEncoding,
|
64
|
+
'cp1254' => NSWindowsCP1254StringEncoding,
|
65
|
+
|
66
|
+
|
67
|
+
# NSNEXTSTEPStringEncoding = 2,
|
68
|
+
# NSJapaneseEUCStringEncoding = 3,
|
69
|
+
# NSSymbolStringEncoding = 6,
|
70
|
+
# NSNonLossyASCIIStringEncoding = 7,
|
71
|
+
# NSShiftJISStringEncoding = 8,
|
72
|
+
# NSISO2022JPStringEncoding = 21,
|
73
|
+
# NSMacOSRomanStringEncoding = 30,
|
74
|
+
# NSUTF16BigEndianStringEncoding = 0x90000100,
|
75
|
+
# NSUTF16LittleEndianStringEncoding = 0x94000100,
|
76
|
+
# NSUTF32BigEndianStringEncoding = 0x98000100,
|
77
|
+
# NSUTF32LittleEndianStringEncoding = 0x9c000100,
|
78
|
+
# NSProprietaryStringEncoding = 65536
|
79
|
+
}
|
40
80
|
end
|
data/lib/under_os/file.rb
CHANGED
@@ -69,7 +69,7 @@ class UnderOs::File
|
|
69
69
|
NSFileManager.defaultManager.createFileAtPath @path, contents:nil, attributes:nil
|
70
70
|
end
|
71
71
|
|
72
|
-
content = content.
|
72
|
+
content = content.to_data('utf-8') if content.is_a?(String)
|
73
73
|
|
74
74
|
open
|
75
75
|
@handle.writeData content
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#
|
2
|
+
# A simple cookie jar thing
|
3
|
+
#
|
4
|
+
class UnderOs::HTTP::Cookies
|
5
|
+
def initialize(cookies, url)
|
6
|
+
@url = url.is_a?(String) ? NSURL.URLWithString(url) : url
|
7
|
+
@hash = cookies
|
8
|
+
end
|
9
|
+
|
10
|
+
def headers
|
11
|
+
NSHTTPCookie.requestHeaderFieldsWithCookies(ios_cookies)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
headers["Cookie"]
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def ios_cookies
|
21
|
+
@hash.map do |key, value|
|
22
|
+
NSHTTPCookie.cookieWithProperties({
|
23
|
+
NSHTTPCookieDomain => @url.host,
|
24
|
+
NSHTTPCookiePath => "/",
|
25
|
+
NSHTTPCookieName => key.to_s,
|
26
|
+
NSHTTPCookieValue => value.to_s
|
27
|
+
})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,9 +1,11 @@
|
|
1
1
|
#
|
2
2
|
# Options:
|
3
3
|
#
|
4
|
-
# * :method
|
5
|
-
# * :cookies
|
6
|
-
# * :stream
|
4
|
+
# * :method - GET, POST, ...
|
5
|
+
# * :cookies - Hash of cookie values
|
6
|
+
# * :stream - boolean, in case you want to stream stuff
|
7
|
+
# * :params - the POST/PUT/PATCH params hash
|
8
|
+
# * :encoding - the POST data encoding
|
7
9
|
#
|
8
10
|
# Events:
|
9
11
|
#
|
@@ -37,10 +39,14 @@ class UnderOs::HTTP::Request
|
|
37
39
|
@receiver = Receiver.new(self, @options[:stream])
|
38
40
|
@connection = NSURLConnection.alloc.initWithRequest(@request, delegate:@receiver)
|
39
41
|
@connection.start
|
42
|
+
|
43
|
+
return self
|
40
44
|
end
|
41
45
|
|
42
46
|
def cancel
|
43
47
|
@connection.cancel
|
48
|
+
|
49
|
+
return self
|
44
50
|
end
|
45
51
|
|
46
52
|
def method
|
@@ -58,32 +64,43 @@ class UnderOs::HTTP::Request
|
|
58
64
|
@options[:cookies] || {}
|
59
65
|
end
|
60
66
|
|
67
|
+
def params
|
68
|
+
@options[:params] || {}
|
69
|
+
end
|
70
|
+
|
71
|
+
def encoding
|
72
|
+
@options[:encoding] || 'utf-8'
|
73
|
+
end
|
74
|
+
|
61
75
|
protected
|
62
76
|
|
63
77
|
def build_request
|
64
|
-
|
65
|
-
|
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
|
78
|
+
query = params.to_query
|
79
|
+
url = build_url(query)
|
77
80
|
|
78
|
-
|
81
|
+
NSMutableURLRequest.requestWithURL(url).tap do |request|
|
82
|
+
request.setHTTPMethod method
|
79
83
|
|
80
|
-
headers.each do |key, value|
|
84
|
+
headers.merge(UnderOs::HTTP::Cookies.new(cookies, url).headers).each do |key, value|
|
81
85
|
request.addValue value, forHTTPHeaderField:key
|
82
86
|
end
|
83
87
|
|
84
|
-
|
85
|
-
|
88
|
+
if %w[POST PUT PATCH DELETE].include?(method) && !query.empty?
|
89
|
+
request.addValue "application/x-www-form-urlencoded;charset=#{encoding}", forHTTPHeaderField:"Content-Type"
|
90
|
+
request.setHTTPBody query.to_data(encoding)
|
91
|
+
end
|
86
92
|
end
|
87
93
|
end
|
94
|
+
|
95
|
+
def build_url(query)
|
96
|
+
url = @url
|
97
|
+
|
98
|
+
if method == "GET" && !query.empty?
|
99
|
+
url += url.include?('?') ? '&' : '?'
|
100
|
+
url += query
|
101
|
+
end
|
102
|
+
|
103
|
+
NSURL.URLWithString(url)
|
104
|
+
end
|
88
105
|
end
|
89
106
|
|
data/lib/under_os/http.rb
CHANGED
@@ -1,5 +1,31 @@
|
|
1
1
|
class UnderOs::HTTP
|
2
2
|
def self.get(url, options={}, &block)
|
3
|
-
|
3
|
+
request url, options.merge(method: :get), &block
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.post(url, options={}, &block)
|
7
|
+
request url, options.merge(method: :post), &block
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.put(url, options={}, &block)
|
11
|
+
request url, options.merge(method: :put), &block
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.patch(url, options={}, &block)
|
15
|
+
request url, options.merge(method: :patch), &block
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.head(url, options={}, &block)
|
19
|
+
request url, options.merge(method: :head), &block
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.delete(url, options={}, &block)
|
23
|
+
request url, options.merge(method: :delete), &block
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def self.request(*args, &block)
|
29
|
+
Request.new(*args, &block).send
|
4
30
|
end
|
5
31
|
end
|
@@ -59,10 +59,12 @@ class UnderOs::UI::Collection::Delegate < UIViewController
|
|
59
59
|
################################################################
|
60
60
|
|
61
61
|
def collectionView(collection, didSelectItemAtIndexPath: indexPath)
|
62
|
-
|
62
|
+
item = collection.cellForItemAtIndexPath(indexPath).uos_view_for(@collection)
|
63
|
+
@collection.emit(:select, item: item, index: indexPath.row, section: indexPath.section)
|
63
64
|
end
|
64
65
|
|
65
66
|
def collectionView(collection, didDeselectItemAtIndexPath: indexPath)
|
66
|
-
|
67
|
+
item = collection.cellForItemAtIndexPath(indexPath).uos_view_for(@collection)
|
68
|
+
@collection.emit(:unselect, item: item, index: indexPath.row, section: indexPath.section)
|
67
69
|
end
|
68
70
|
end
|
@@ -14,7 +14,7 @@ class UnderOs::UI::Collection < UnderOs::UI::View
|
|
14
14
|
|
15
15
|
def on(*args, &block)
|
16
16
|
super *args do |event|
|
17
|
-
params = [event.item, event.index, event.section]
|
17
|
+
params = [event.item, event.index, event.section]
|
18
18
|
params = params.slice(0, block.arity) if block.arity > -1
|
19
19
|
|
20
20
|
block.call *params
|
@@ -40,6 +40,7 @@ class UnderOs::UI::Collection < UnderOs::UI::View
|
|
40
40
|
|
41
41
|
def reload
|
42
42
|
@_.reloadData
|
43
|
+
self
|
43
44
|
end
|
44
45
|
|
45
46
|
def number_of_items(section=0)
|
@@ -48,6 +49,7 @@ class UnderOs::UI::Collection < UnderOs::UI::View
|
|
48
49
|
|
49
50
|
def number_of_items=(value)
|
50
51
|
@number_of_items = value.is_a?(Numeric) ? [value] : value
|
52
|
+
reload
|
51
53
|
end
|
52
54
|
|
53
55
|
def number_of_sections
|
data/lib/under_os/ui/locker.rb
CHANGED
@@ -22,39 +22,33 @@ module UnderOs::UI
|
|
22
22
|
|
23
23
|
def textAlign
|
24
24
|
if @view.is_a?(UIButton)
|
25
|
-
|
26
|
-
when UIControlContentHorizontalAlignmentRight then 'right'
|
27
|
-
when UIControlContentHorizontalAlignmentCenter then 'center'
|
28
|
-
when UIControlContentHorizontalAlignmentFill then 'justify'
|
29
|
-
else 'left'
|
30
|
-
end
|
25
|
+
BUTTONS_ALIGMENTS_MAP.key(@view.contentHorizontalAlignment)
|
31
26
|
elsif @view.respond_to?(:textAlignment)
|
32
|
-
|
33
|
-
when NSTextAlignmentRight then 'right'
|
34
|
-
when NSTextAlignmentCenter then 'center'
|
35
|
-
when NSTextAlignmentJustified then 'justify'
|
36
|
-
else 'left'
|
37
|
-
end
|
27
|
+
TEXTNODES_ALIGMENTS_MAP.key(@view.textAlignment)
|
38
28
|
end
|
39
29
|
end
|
40
30
|
|
41
31
|
def textAlign=(value)
|
42
32
|
if @view.is_a?(UIButton)
|
43
|
-
@view.contentHorizontalAlignment =
|
44
|
-
when 'right' then UIControlContentHorizontalAlignmentRight
|
45
|
-
when 'center' then UIControlContentHorizontalAlignmentCenter
|
46
|
-
when 'justify' then UIControlContentHorizontalAlignmentFill
|
47
|
-
else UIControlContentHorizontalAlignmentLeft
|
48
|
-
end
|
33
|
+
@view.contentHorizontalAlignment = BUTTONS_ALIGMENTS_MAP[value.to_s] || BUTTONS_ALIGMENTS_MAP['left']
|
49
34
|
elsif @view.respond_to?(:textAlignment)
|
50
|
-
@view.textAlignment =
|
51
|
-
when 'right' then NSTextAlignmentRight
|
52
|
-
when 'center' then NSTextAlignmentCenter
|
53
|
-
when 'justify' then NSTextAlignmentJustified
|
54
|
-
else NSTextAlignmentLeft
|
55
|
-
end
|
35
|
+
@view.textAlignment = TEXTNODES_ALIGMENTS_MAP[value.to_s] || BUTTONS_ALIGMENTS_MAP['left']
|
56
36
|
end
|
57
37
|
end
|
38
|
+
|
39
|
+
BUTTONS_ALIGMENTS_MAP = {
|
40
|
+
'right' => UIControlContentHorizontalAlignmentRight,
|
41
|
+
'center' => UIControlContentHorizontalAlignmentCenter,
|
42
|
+
'justify' => UIControlContentHorizontalAlignmentFill,
|
43
|
+
'left' => UIControlContentHorizontalAlignmentLeft
|
44
|
+
}
|
45
|
+
|
46
|
+
TEXTNODES_ALIGMENTS_MAP = {
|
47
|
+
'right' => NSTextAlignmentRight,
|
48
|
+
'center' => NSTextAlignmentCenter,
|
49
|
+
'justify' => NSTextAlignmentJustified,
|
50
|
+
'left' => NSTextAlignmentLeft
|
51
|
+
}
|
58
52
|
end
|
59
53
|
end
|
60
54
|
end
|
@@ -19,11 +19,8 @@ module UnderOs::UI
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def margin=(value)
|
22
|
-
|
23
|
-
|
24
|
-
self.marginLeft = value[3]
|
25
|
-
self.marginRight = value[1]
|
26
|
-
self.marginBottom = value[2]
|
22
|
+
@margin_top, @margin_right, @margin_botom, @margin_left = to_4dim_array(value)
|
23
|
+
set_offsets
|
27
24
|
end
|
28
25
|
|
29
26
|
def marginTop
|
@@ -67,11 +64,8 @@ module UnderOs::UI
|
|
67
64
|
end
|
68
65
|
|
69
66
|
def padding=(value)
|
70
|
-
|
71
|
-
|
72
|
-
self.paddingLeft = value[3]
|
73
|
-
self.paddingRight = value[1]
|
74
|
-
self.paddingBottom = value[2]
|
67
|
+
@padding_top, @padding_right, @padding_botom, @padding_left = to_4dim_array(value)
|
68
|
+
set_offsets
|
75
69
|
end
|
76
70
|
|
77
71
|
def paddingTop
|
@@ -113,10 +107,7 @@ module UnderOs::UI
|
|
113
107
|
private
|
114
108
|
|
115
109
|
def to_4dim_array(value)
|
116
|
-
if value.is_a?(String)
|
117
|
-
value = value.gsub('px', '').strip.split().reject(&:blank?).map(&:to_f)
|
118
|
-
end
|
119
|
-
|
110
|
+
value = value.gsub('px', '').split.map(&:to_f) if value.is_a?(String)
|
120
111
|
value = Array(value)
|
121
112
|
case value.size
|
122
113
|
when 1 then value * 4
|
@@ -128,32 +119,45 @@ module UnderOs::UI
|
|
128
119
|
def set_offsets
|
129
120
|
return nil if display != :inline
|
130
121
|
|
131
|
-
position_x
|
132
|
-
position_y
|
122
|
+
position_x = marginLeft + parent_offset_x
|
123
|
+
position_y = marginTop
|
133
124
|
|
134
|
-
|
135
|
-
|
125
|
+
@view.frame = [[position_x, position_y], [
|
126
|
+
@view.frame.size.width, @view.frame.size.height
|
127
|
+
]]
|
128
|
+
end
|
129
|
+
|
130
|
+
def set_paddings
|
131
|
+
if @view.respond_to?(:contentEdgeInsets)
|
132
|
+
@view.contentEdgeInsets = UIEdgeInsetsMake(paddingTop, paddingLeft, paddingBottom, paddingRight)
|
133
|
+
end
|
134
|
+
end
|
136
135
|
|
137
|
-
|
138
|
-
|
139
|
-
|
136
|
+
def parent_offset_x
|
137
|
+
offset = 0
|
138
|
+
parent_frame = parent_view_frame
|
140
139
|
|
141
|
-
|
140
|
+
if parent_frame
|
141
|
+
offset += parent_frame.origin.x + parent_frame.size.width
|
142
142
|
|
143
|
-
if wrap = UnderOs::UI::View.wrap_for(view)
|
144
|
-
|
143
|
+
if wrap = UnderOs::UI::View.wrap_for(@view)
|
144
|
+
offset += wrap.style.marginRight
|
145
145
|
end
|
146
146
|
end
|
147
147
|
|
148
|
-
|
149
|
-
view.frame.size.width, view.frame.size.height
|
150
|
-
]]
|
148
|
+
offset
|
151
149
|
end
|
152
150
|
|
153
|
-
def
|
154
|
-
|
155
|
-
|
151
|
+
def parent_view_frame
|
152
|
+
parent_view = @view.superview
|
153
|
+
parent_frame = nil
|
154
|
+
|
155
|
+
unless parent_view.subviews[0] === @view
|
156
|
+
previous_view = parent_view.subviews[parent_view.subviews.index(@view)-1]
|
157
|
+
parent_frame = previous_view && previous_view.frame
|
156
158
|
end
|
159
|
+
|
160
|
+
parent_frame
|
157
161
|
end
|
158
162
|
end
|
159
163
|
end
|
data/lib/under_os.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
describe Hash do
|
2
|
+
describe '#to_query' do
|
3
|
+
it "converts a simple hash into a query string" do
|
4
|
+
{a: 1, b: 2}.to_query.should == 'a=1&b=2'
|
5
|
+
end
|
6
|
+
|
7
|
+
it "converts nested hashes into queries correctly" do
|
8
|
+
{a: 1, b: {c: {d: 4}}}.to_query.should == 'a=1&b%5Bc%5D%5Bd%5D=4'
|
9
|
+
end
|
10
|
+
|
11
|
+
it "handles array values correctly" do
|
12
|
+
{a: [1,2,3,4]}.to_query.should == 'a%5B%5D=1&a%5B%5D=2&a%5B%5D=3&a%5B%5D=4'
|
13
|
+
end
|
14
|
+
|
15
|
+
it "escapes any URL sensitive characters in the values" do
|
16
|
+
{a: '%= '}.to_query.should == 'a=%25=%20'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
describe JSON do
|
2
|
+
describe ".parse" do
|
3
|
+
it "parses correct json strings" do
|
4
|
+
JSON.parse('{"a":1,"b":true,"c":["data"]}').should == {
|
5
|
+
"a" => 1, "b" => true, "c" => ["data"]
|
6
|
+
}
|
7
|
+
end
|
8
|
+
|
9
|
+
it "raises an exception on malformed data" do
|
10
|
+
-> {
|
11
|
+
JSON.parse("malformed")
|
12
|
+
}.should.raise(JSON::Malformed)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe ".generate" do
|
17
|
+
it "generates JSON string out of objects" do
|
18
|
+
JSON.generate({a:1, b:true, c:[:data]}).should ==
|
19
|
+
'{"a":1,"b":true,"c":["data"]}'
|
20
|
+
end
|
21
|
+
|
22
|
+
it "generates pretty print when asked" do
|
23
|
+
JSON.generate({a:1, b:true, c:[:data]}, :pretty).should ==
|
24
|
+
"{\n \"a\" : 1,\n \"b\" : true,\n \"c\" : [\n \"data\"\n ]\n}"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "allows to export things directly of objects" do
|
28
|
+
{a:1, b:true, c:[:data]}.to_json.should ==
|
29
|
+
'{"a":1,"b":true,"c":["data"]}'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -84,4 +84,38 @@ describe String do
|
|
84
84
|
}.should.raise(NameError)
|
85
85
|
end
|
86
86
|
end
|
87
|
+
|
88
|
+
describe '#url_encode' do
|
89
|
+
it "escapes all the URL sensitive symbols" do
|
90
|
+
"!*'\"();:@&=+$,/?%#[]% ".url_encode.should == "!*'%22();:@&=+$,/?%25%23%5B%5D%25%20"
|
91
|
+
end
|
92
|
+
|
93
|
+
it "doesn't touch normal characters" do
|
94
|
+
"Hello World".url_encode.should == "Hello%20World"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe '#url_decode' do
|
99
|
+
it "converts an url encoded string back to normality" do
|
100
|
+
"!*'%22();:@&=+$,/?%25%23%5B%5D%25%20".url_decode.should == "!*'\"();:@&=+$,/?%#[]% "
|
101
|
+
end
|
102
|
+
|
103
|
+
it "doesn't break normal characters" do
|
104
|
+
"Hello%20World".url_decode.should == "Hello World"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '#to_data' do
|
109
|
+
before do
|
110
|
+
@data = "ohai there".to_data
|
111
|
+
end
|
112
|
+
|
113
|
+
it "converts the string into a data object" do
|
114
|
+
@data.is_a?(NSData).should == true
|
115
|
+
end
|
116
|
+
|
117
|
+
it "converts it into data with correct content" do
|
118
|
+
@data.to_s.should == "ohai there"
|
119
|
+
end
|
120
|
+
end
|
87
121
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
describe UnderOS::HTTP::Cookies do
|
2
|
+
before do
|
3
|
+
@cookies = UnderOS::HTTP::Cookies.new({a: 1, b: true}, "http://test.com")
|
4
|
+
end
|
5
|
+
|
6
|
+
it "allows to export them in a string" do
|
7
|
+
@cookies.to_s.should == "a=1; b=true"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "allows to export them into an HTTP header hash" do
|
11
|
+
@cookies.headers.should == {"Cookie"=>"a=1; b=true"}
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
describe UnderOS::HTTP::Request do
|
2
|
+
before do
|
3
|
+
@url = "http://test.com"
|
4
|
+
@request = UnderOS::HTTP::Request.new(@url, {
|
5
|
+
headers: {my: 'headers'},
|
6
|
+
cookies: {my: 'cookies'},
|
7
|
+
params: {my: 'params'},
|
8
|
+
method: :put
|
9
|
+
})
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#constructor" do
|
13
|
+
it "assigns the url correctly" do
|
14
|
+
@request.url.should == @url
|
15
|
+
end
|
16
|
+
|
17
|
+
it "assigns the request headers correctly" do
|
18
|
+
@request.headers.should == {my: 'headers'}
|
19
|
+
end
|
20
|
+
|
21
|
+
it "assigns the request cookies correctly" do
|
22
|
+
@request.cookies.should == {my: 'cookies'}
|
23
|
+
end
|
24
|
+
|
25
|
+
it "assigns my params correctly" do
|
26
|
+
@request.params.should == {my: 'params'}
|
27
|
+
end
|
28
|
+
|
29
|
+
it "assigns the request method correctly" do
|
30
|
+
@request.method.should == 'PUT'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#on" do
|
35
|
+
it "returns the response object instead of an event into a callback" do
|
36
|
+
@response = nil
|
37
|
+
|
38
|
+
@request.on(:smth) { |r| @response = r }
|
39
|
+
@request.emit(:smth, response: 'response')
|
40
|
+
|
41
|
+
@response.should == 'response'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
describe UnderOs::HTTP do
|
2
|
+
extend Facon::SpecHelpers
|
3
|
+
|
4
|
+
before do
|
5
|
+
@url = 'http://test.com'
|
6
|
+
@req = mock 'request', send: :request
|
7
|
+
end
|
8
|
+
|
9
|
+
%w[get post put patch head delete].each do |method|
|
10
|
+
describe ".#{method}" do
|
11
|
+
it "sends a #{method.upcase} request" do
|
12
|
+
UnderOs::HTTP::Request.should.receive(:new)
|
13
|
+
.with(@url, foo: 'bar', method: method.to_sym)
|
14
|
+
.and_return(@req)
|
15
|
+
|
16
|
+
UnderOs::HTTP.__send__(method, @url, foo: 'bar').should == :request
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/under-os.gemspec
CHANGED
@@ -16,8 +16,6 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
|
19
|
-
gem.add_development_dependency 'rake'
|
20
|
-
|
21
19
|
gem.post_install_message = %Q{
|
22
20
|
If you want to use the UnderOS template with RubyMotion, please run the following:
|
23
21
|
|
@@ -29,4 +27,8 @@ Gem::Specification.new do |gem|
|
|
29
27
|
|
30
28
|
motion create awesomness --template=uos
|
31
29
|
}
|
30
|
+
|
31
|
+
gem.add_development_dependency 'rake'
|
32
|
+
gem.add_development_dependency 'motion-facon'
|
33
|
+
|
32
34
|
end
|
metadata
CHANGED
@@ -1,27 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: under-os
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nikolay Nemshilov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-12-
|
11
|
+
date: 2013-12-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: motion-facon
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
25
39
|
- !ruby/object:Gem::Version
|
26
40
|
version: '0'
|
27
41
|
description: A web-broser like wrapper over iOS
|
@@ -31,7 +45,8 @@ executables: []
|
|
31
45
|
extensions: []
|
32
46
|
extra_rdoc_files: []
|
33
47
|
files:
|
34
|
-
-
|
48
|
+
- .gitignore
|
49
|
+
- .travis.yml
|
35
50
|
- Gemfile
|
36
51
|
- Gemfile.lock
|
37
52
|
- README.md
|
@@ -57,7 +72,6 @@ files:
|
|
57
72
|
- app/pages/navbar_page.rb
|
58
73
|
- app/pages/scrolls_page.rb
|
59
74
|
- app/pages/sidebars_page.rb
|
60
|
-
- app/pages/stuff_page.rb
|
61
75
|
- app/styles/application.css
|
62
76
|
- app/styles/calculator.css
|
63
77
|
- app/styles/collections.css
|
@@ -73,14 +87,19 @@ files:
|
|
73
87
|
- lib/under_os/app.rb
|
74
88
|
- lib/under_os/color.rb
|
75
89
|
- lib/under_os/config.rb
|
90
|
+
- lib/under_os/core/array.rb
|
91
|
+
- lib/under_os/core/hash.rb
|
92
|
+
- lib/under_os/core/json.rb
|
76
93
|
- lib/under_os/core/kernel.rb
|
77
94
|
- lib/under_os/core/numeric.rb
|
95
|
+
- lib/under_os/core/object.rb
|
78
96
|
- lib/under_os/core/string.rb
|
79
97
|
- lib/under_os/delegate.rb
|
80
98
|
- lib/under_os/events.rb
|
81
99
|
- lib/under_os/file.rb
|
82
100
|
- lib/under_os/history.rb
|
83
101
|
- lib/under_os/http.rb
|
102
|
+
- lib/under_os/http/cookies.rb
|
84
103
|
- lib/under_os/http/receiver.rb
|
85
104
|
- lib/under_os/http/request.rb
|
86
105
|
- lib/under_os/http/response.rb
|
@@ -144,11 +163,16 @@ files:
|
|
144
163
|
- spec/assets/test.css
|
145
164
|
- spec/assets/test.html
|
146
165
|
- spec/assets/test_page.rb
|
166
|
+
- spec/lib/core/hash_spec.rb
|
167
|
+
- spec/lib/core/json_spec.rb
|
147
168
|
- spec/lib/core/numeric_spec.rb
|
148
169
|
- spec/lib/core/string_spec.rb
|
149
170
|
- spec/lib/under_os/color_spec.rb
|
150
171
|
- spec/lib/under_os/events_spec.rb
|
151
172
|
- spec/lib/under_os/file_spec.rb
|
173
|
+
- spec/lib/under_os/http/cookies_spec.rb
|
174
|
+
- spec/lib/under_os/http/request_spec.rb
|
175
|
+
- spec/lib/under_os/http_spec.rb
|
152
176
|
- spec/lib/under_os/page/builder_spec.rb
|
153
177
|
- spec/lib/under_os/page/layout_spec.rb
|
154
178
|
- spec/lib/under_os/page/matcher_spec.rb
|
@@ -201,17 +225,17 @@ require_paths:
|
|
201
225
|
- lib
|
202
226
|
required_ruby_version: !ruby/object:Gem::Requirement
|
203
227
|
requirements:
|
204
|
-
- -
|
228
|
+
- - '>='
|
205
229
|
- !ruby/object:Gem::Version
|
206
230
|
version: '0'
|
207
231
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
208
232
|
requirements:
|
209
|
-
- -
|
233
|
+
- - '>='
|
210
234
|
- !ruby/object:Gem::Version
|
211
235
|
version: '0'
|
212
236
|
requirements: []
|
213
237
|
rubyforge_project:
|
214
|
-
rubygems_version: 2.
|
238
|
+
rubygems_version: 2.1.11
|
215
239
|
signing_key:
|
216
240
|
specification_version: 4
|
217
241
|
summary: A web-broser like wrapper over iOS using RubyMotion
|
@@ -220,11 +244,16 @@ test_files:
|
|
220
244
|
- spec/assets/test.css
|
221
245
|
- spec/assets/test.html
|
222
246
|
- spec/assets/test_page.rb
|
247
|
+
- spec/lib/core/hash_spec.rb
|
248
|
+
- spec/lib/core/json_spec.rb
|
223
249
|
- spec/lib/core/numeric_spec.rb
|
224
250
|
- spec/lib/core/string_spec.rb
|
225
251
|
- spec/lib/under_os/color_spec.rb
|
226
252
|
- spec/lib/under_os/events_spec.rb
|
227
253
|
- spec/lib/under_os/file_spec.rb
|
254
|
+
- spec/lib/under_os/http/cookies_spec.rb
|
255
|
+
- spec/lib/under_os/http/request_spec.rb
|
256
|
+
- spec/lib/under_os/http_spec.rb
|
228
257
|
- spec/lib/under_os/page/builder_spec.rb
|
229
258
|
- spec/lib/under_os/page/layout_spec.rb
|
230
259
|
- spec/lib/under_os/page/matcher_spec.rb
|
data/app/pages/stuff_page.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
class StuffPage < UnderOs::Page
|
2
|
-
def initialize
|
3
|
-
self.title = "Various Stuff"
|
4
|
-
|
5
|
-
@box = View.new(style: {
|
6
|
-
top: 50,
|
7
|
-
left: 50,
|
8
|
-
width: 100,
|
9
|
-
height: 100,
|
10
|
-
background: :red,
|
11
|
-
borderRadius: 10,
|
12
|
-
borderWidth: 2,
|
13
|
-
borderColor: :green
|
14
|
-
})
|
15
|
-
|
16
|
-
@box.on(:tap){ @box.fade_out.fade_in }
|
17
|
-
|
18
|
-
@b2 = View.new(style: {background: :blue})
|
19
|
-
@b2.size = {x: 50, y: 50}
|
20
|
-
@b2.position = {x: 25, y: 25}
|
21
|
-
|
22
|
-
@b2.on(:tap, :highlight)
|
23
|
-
|
24
|
-
insert @box.insert(@b2)
|
25
|
-
|
26
|
-
insert Button.new(text: 'Boo Hoo!').position(x: 100, y: 200)
|
27
|
-
|
28
|
-
insert Label.new(text: "Hey Label", style: {background: :red}).position({x: 100, y: 250})
|
29
|
-
|
30
|
-
insert Icon.new(:cog).position(x: 50, y: 300)
|
31
|
-
insert Icon.new(:trash).position(x: 100, y: 300)
|
32
|
-
insert Icon.new(:home).position(x: 150, y: 300)
|
33
|
-
insert Icon.new(:magic).position(x: 200, y: 300)
|
34
|
-
end
|
35
|
-
end
|