under-os 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5ff1789b7dfe17082f36cf9eea7c8c3444077716
4
- data.tar.gz: 520c56f69fdc975f55be7e49d87f3742c12e4dca
3
+ metadata.gz: 97b21422505f0e6c41a9437eca6fc287e5c37db1
4
+ data.tar.gz: 163b49514385bce8995b306b5b087961b250ecc2
5
5
  SHA512:
6
- metadata.gz: ea4aab7ec336bd41cde899ab86f4caeaa9d206cb7261915eb85157b97a117b628b41e204df63627ac9e18f36e99e0cedc70f876d7441a6cee27bfbe74afb2aef
7
- data.tar.gz: 3e7eee7f55f17c5952b96741f2db01cd7ea38e2842476eca515f27a3e093cb8c5516bef93f8dd51cfbd86be60c398d1f1e861540ed63e6283e4183ed41ff9e2c
6
+ metadata.gz: b114c74edf769d28d294aa327c9382e6927bc690a13b4fd7331bb2ae371f29f34ba6131d92c81ad8f7cefc84c3bee9eb0a3d953247bf0ad4d07b64643eba5d0b
7
+ data.tar.gz: e3dec5a68e2a7abf834d910ba6b4fb30fddb365068f8a8e576ee7a365531d5f9e31c9561a2dce92498e26ba02f5d2efad97af3a7ad6467de5034b9d3e45f907d
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  build
2
2
  .repl_history
3
3
  *.gem
4
+ .bundle
data/Gemfile.lock CHANGED
@@ -1,13 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- under-os (1.0.0)
4
+ under-os (1.1.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  motion-facon (0.5.0.1)
10
- rake (10.1.0)
10
+ rake (10.1.1)
11
11
 
12
12
  PLATFORMS
13
13
  ruby
@@ -1,5 +1,9 @@
1
1
  <page title="Inputs Demo">
2
- <input placeholder="Tap here" />
2
+ <input id="i1" type="text" placeholder="Plain text" />
3
+ <input id="i2" type="password" placeholder="Password" />
4
+ <input id="i3" type="email" placeholder="your@email.com" />
5
+ <input id="i4" type="phone" placeholder="+0431431431" />
6
+
3
7
  <textarea>some value</textarea>
4
8
 
5
9
  <slider min="0" max="100" value="40" />
@@ -9,7 +9,7 @@ class HttpPage < UnderOs::Page
9
9
  end
10
10
 
11
11
  def search
12
- @search.hide_keyboard
12
+ @search.blur
13
13
  @locker.show
14
14
 
15
15
  UnderOs::HTTP.get search_url do |response|
@@ -1,26 +1,39 @@
1
1
  input {
2
2
  left: 10;
3
- top: 100;
4
3
  width: 300;
5
- height: 40;
4
+ height: 30;
6
5
  }
7
6
 
7
+ input#i1 {
8
+ top: 55;
9
+ }
10
+
11
+ input#i2 {
12
+ top: 95;
13
+ }
14
+
15
+ input#i3 {
16
+ top: 135;
17
+ }
18
+ input#i4 {
19
+ top: 175;
20
+ }
8
21
  textarea {
9
- left: 10;
10
- top: 150;
11
- width: 300;
22
+ top: 215;
23
+ left: 10;
24
+ width: 300;
12
25
  height: 100;
13
26
  }
14
27
 
15
28
  slider {
16
29
  left: 10;
17
- top: 300;
30
+ top: 330;
18
31
  width: 200;
19
32
  }
20
33
 
21
34
  switch {
22
35
  left: 250;
23
- top: 300;
36
+ top: 330;
24
37
  }
25
38
 
26
39
  progress {
@@ -6,10 +6,15 @@ class UnderOs::Page::StylesMatcher
6
6
  end
7
7
 
8
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(' '))
9
+ css_rules = css_rule.strip.split(/\s*,\s*/)
10
+
11
+ if css_rules.size == 1
12
+ rules = css_rules[0].scan(/([\S]+)/).map(&:first)
13
+ @rule = parse(rules.pop)
14
+ @parent = rules.size == 0 ? false : self.class.new(rules.join(' '))
15
+ else
16
+ @multiple_matchers = css_rules.map{ |rule| self.class.new(rule) }
17
+ end
13
18
  end
14
19
 
15
20
  def match(view)
@@ -17,40 +22,72 @@ class UnderOs::Page::StylesMatcher
17
22
  end
18
23
 
19
24
  def score_for(view)
25
+ return summary_score_for(view) if @multiple_matchers
26
+
20
27
  id_score = id_score_for(view)
21
28
  tag_score = tag_score_for(view)
22
29
  class_score = class_score_for(view)
30
+ attrs_score = attrs_score_for(view)
31
+ total_score = id_score + tag_score + class_score + attrs_score
23
32
 
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)
33
+ total_score = 0 if id_score == 0 && @rule[:id]
34
+ total_score = 0 if tag_score == 0 && @rule[:tag]
35
+ total_score = 0 if class_score == 0 && @rule[:classes].size != 0
36
+ total_score = 0 if attrs_score == 0 && @rule[:attrs].size != 0
30
37
 
31
- return 0 if @parent && parent_score == 0
38
+ if @parent && total_score != 0
39
+ parent_score = parent_score_for(view)
40
+ total_score = parent_score == 0 ? 0 : total_score + parent_score
41
+ end
32
42
 
33
- parent_score + this_score
43
+ total_score
34
44
  end
35
45
 
36
46
  private
37
47
 
48
+ def summary_score_for(view)
49
+ @multiple_matchers.map{ |matcher| matcher.score_for(view) }.max
50
+ end
51
+
38
52
  def id_score_for(view)
39
53
  @rule[:id] == view.id ? 1 : 0
40
54
  end
41
55
 
42
56
  def tag_score_for(view)
43
- @rule[:tag] == view.tagName ? 1 : 0
57
+ @rule[:tag] == '*' || @rule[:tag] == view.tagName ? 1 : 0
44
58
  end
45
59
 
46
60
  def class_score_for(view)
61
+ return 0 if @rule[:classes].size == 0
47
62
  match = @rule[:classes] & view.classNames
48
63
  match.size == @rule[:classes].size ? match.size : 0
49
64
  end
50
65
 
51
- def parent_score_for(view)
52
- return 0 if ! @parent
66
+ def attrs_score_for(view)
67
+ score = 0; return 0 if @rule[:attrs].size == 0
68
+
69
+ @rule[:attrs].each do |key, value, operand|
70
+ attr = view.respond_to?(key) && view.__send__(key)
71
+ attr = attr.to_s if attr.is_a?(Symbol) || attr.is_a?(Numeric)
72
+
73
+ if attr && attr.is_a?(String)
74
+ matches = case operand
75
+ when '=' then attr == value
76
+ when '*=' then attr.include?(value)
77
+ when '^=' then attr.starts_with?(value)
78
+ when '$=' then attr.ends_with?(value)
79
+ when '~=' then attr.split(' ').include?(value)
80
+ when '|=' then attr.split('-').include?(value)
81
+ end
82
+
83
+ score += 1 if matches
84
+ end
85
+ end
86
+
87
+ score
88
+ end
53
89
 
90
+ def parent_score_for(view)
54
91
  parent = view; score = 0
55
92
 
56
93
  while parent = parent.parent
@@ -63,7 +100,7 @@ private
63
100
 
64
101
  def parse(string)
65
102
  {}.tap do |rule|
66
- if m = string.match(/^([a-z]+)/)
103
+ if m = string.match(/^([a-z\*]+)/)
67
104
  rule[:tag] = m[1].upcase
68
105
  else
69
106
  rule[:tag] = false # so it wouldn't match nil
@@ -77,6 +114,14 @@ private
77
114
 
78
115
  if m = string.scan(/(\.)([a-z_\-0-9]+)/)
79
116
  rule[:classes] = m.map{|c| c[1]}
117
+ else
118
+ rule[:classes] = []
119
+ end
120
+
121
+ if m = string.scan(/\[\s*([a-z]+)\s*([*^$~|]{0,1}=)\s*('|")?(.+?)(\3)?\s*\]/)
122
+ rule[:attrs] = m.map{|c| [c[0], c[3], c[1]] }
123
+ else
124
+ rule[:attrs] = []
80
125
  end
81
126
  end
82
127
  end
@@ -3,7 +3,7 @@ class UnderOs::Parser::CSS
3
3
  style = style.gsub(/\/\*[\s\S]+?\*\//, '').strip
4
4
 
5
5
  {}.tap do |result|
6
- style.scan(/(\A|\})([a-z0-9_\-\.\s#:,]+)\{([^}]+)/).map do |rule|
6
+ style.scan(/(\A|\})([a-z0-9_\*\-\.\s#:,]+)\{([^}]+)/).map do |rule|
7
7
  values = parse_styles(rule[2])
8
8
 
9
9
  rule[1].split(',').each do |css_rule|
@@ -4,7 +4,9 @@ class UnderOS::UI::Button < UnderOS::UI::View
4
4
  def initialize(options={})
5
5
  super
6
6
 
7
- self.text = options.delete(:text) || ''
7
+ self.text = options.delete(:text) || ''
8
+ self.disable if options[:disabled]
9
+
8
10
  @_.showsTouchWhenHighlighted = true
9
11
  @_.setBackgroundImage(options.delete(:image), forState:UIControlStateNormal) if options[:image]
10
12
  @_.sizeToFit
@@ -19,4 +21,22 @@ class UnderOS::UI::Button < UnderOS::UI::View
19
21
  repaint
20
22
  end
21
23
 
24
+ def disabled
25
+ ! @_.isEnabled
26
+ end
27
+
28
+ alias :disabled? :disabled
29
+
30
+ def disabled=(value)
31
+ @_.enabled = ! value
32
+ end
33
+
34
+ def disable
35
+ self.disabled = true
36
+ end
37
+
38
+ def enable
39
+ self.disabled = false
40
+ end
41
+
22
42
  end
@@ -0,0 +1,3 @@
1
+ class UnderOs::UI::Div < UnderOs::UI::View
2
+ tag :div
3
+ end
@@ -0,0 +1,60 @@
1
+ class UnderOs::UI::Form < UnderOs::UI::View
2
+ tag :form
3
+
4
+ def elements
5
+ find('*').select do |view|
6
+ view.is_a?(UnderOs::UI::Input) || view._.is_a?(UIButton)
7
+ end
8
+ end
9
+
10
+ def inputs
11
+ find('*').select do |view|
12
+ view.is_a?(UnderOs::UI::Input)
13
+ end
14
+ end
15
+
16
+ def values
17
+ {}.tap do |values|
18
+ inputs.each do |input|
19
+ next if input.disabled || ! input.name || (input.is_a?(UnderOs::UI::Switch) && !input.checked)
20
+
21
+ hash = values; key = nil
22
+ keys = input.name.scan(/[^\[]+/)
23
+
24
+ # getting throught the smth[smth][smth][] in the name
25
+ while keys.size > 1
26
+ key = keys.shift
27
+ key = key.slice(0, key.size-1) if key.ends_with?(']')
28
+
29
+ hash[key] = keys[0] == ']' ? [] : {} if ! hash[key]
30
+ hash = hash[key]
31
+ end
32
+
33
+ key = keys.shift
34
+ key = key.slice(0, key.size-1) if key.ends_with?(']')
35
+
36
+ if hash.is_a?(Array)
37
+ hash << input.value
38
+ else
39
+ hash[key] = input.value
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ def disable
46
+ elements.each(&:disable)
47
+ self
48
+ end
49
+
50
+ def enable
51
+ elements.each(&:enable)
52
+ self
53
+ end
54
+
55
+ def focus
56
+ if input = inputs.first
57
+ input.focus
58
+ end
59
+ end
60
+ end
@@ -11,6 +11,7 @@ class UnderOs::UI::Icon < UnderOs::UI::View
11
11
 
12
12
  self.type = options.delete(:type) || :bug
13
13
  self.size = options.delete(:size) || 20
14
+ self.disable if options[:disabled]
14
15
 
15
16
  @_.sizeToFit
16
17
  @_.showsTouchWhenHighlighted = true
@@ -39,4 +40,22 @@ class UnderOs::UI::Icon < UnderOs::UI::View
39
40
  @_.setFont self.class.engine.font(size)
40
41
  @_.sizeToFit
41
42
  end
43
+
44
+ def disabled
45
+ ! @_.isEnabled
46
+ end
47
+
48
+ alias :disabled? :disabled
49
+
50
+ def disabled=(value)
51
+ @_.enabled = ! value
52
+ end
53
+
54
+ def disable
55
+ self.disabled = true
56
+ end
57
+
58
+ def enable
59
+ self.disabled = false
60
+ end
42
61
  end
@@ -1,41 +1,140 @@
1
1
  class UnderOs::UI::Input < UnderOs::UI::View
2
- include UnderOs::UI::Editable
3
-
4
2
  wraps UITextField, tag: 'input'
5
3
 
6
4
  def initialize(options={})
7
5
  super
8
6
 
9
- # self.type = options[:type] if options[:type]
7
+ self.type = options[:type] if options[:type]
8
+ self.name = options[:name] if options[:name]
10
9
  self.value = options[:value] if options[:value]
11
10
  self.placeholder = options[:placeholder] if options[:placeholder]
12
11
  self.keyboard = options[:keyboard] if options[:keyboard]
12
+ self.disabled = true if options[:disabled]
13
+
14
+ @_.delegate = self if @_.respond_to?(:delegate=)
13
15
 
14
- @_.delegate = self
16
+ if @_.class == UITextField
17
+ @_.addTarget self, action: :handle_focus, forControlEvents:UIControlEventEditingDidBegin
18
+ @_.addTarget self, action: :handle_change, forControlEvents:UIControlEventEditingChanged
19
+ @_.addTarget self, action: :handle_blur, forControlEvents:UIControlEventEditingDidEnd
20
+ end
15
21
  end
16
22
 
17
- # FIXME apparently there is a problem with this property in rubymotion
18
- # def type
19
- # if @_.secureTextEntry
20
- # :password
21
- # else
22
- # :text
23
- # end
24
- # end
23
+ def name
24
+ @name
25
+ end
25
26
 
26
- # def type=(type)
27
- # case type.to_sym
28
- # when :password then @_.secureTextEntry = true
29
- # end
30
- # end
27
+ def name=(text)
28
+ @name = text
29
+ end
31
30
 
32
- def textFieldShouldReturn(textField)
33
- hide_keyboard
34
- false
31
+ def value
32
+ @_.text
33
+ end
34
+
35
+ def value=(value)
36
+ @_.text = value
37
+ end
38
+
39
+ def placeholder
40
+ @_.placeholder
41
+ end
42
+
43
+ def placeholder=(value)
44
+ @_.placeholder = value
45
+ end
46
+
47
+ def type
48
+ if @_.respond_to?(:secureTextEntry) && @_.secureTextEntry
49
+ :password
50
+ else
51
+ keyboard == :default ? :text : keyboard
52
+ end
53
+ end
54
+
55
+ def type=(type)
56
+ case type.to_sym
57
+ when :password then @_.secureTextEntry = true
58
+ else self.keyboard = type
59
+ end
60
+ end
61
+
62
+ def keyboard
63
+ KEYBOARDS.index(@_.keyboardType)
64
+ end
65
+
66
+ def keyboard=(keyboard)
67
+ keyboard = keyboard.to_sym if keyboard.is_a?(String)
68
+ keyboard = KEYBOARDS[keyboard] || keyboard
69
+
70
+ raise "Unknown keyboard type: #{keyboard}" if keyboard.is_a?(Symbol)
71
+
72
+ @_.keyboardType = keyboard
35
73
  end
36
74
 
37
75
  def hide_keyboard
76
+ puts "DEPRECATED: please use the `#blur` method instead of `#hide_keyboard`"
77
+ blur
78
+ end
79
+
80
+ KEYBOARDS = {
81
+ default: UIKeyboardTypeDefault,
82
+ text: UIKeyboardTypeDefault,
83
+ ascii: UIKeyboardTypeASCIICapable,
84
+ numeric: UIKeyboardTypeNumbersAndPunctuation,
85
+ url: UIKeyboardTypeURL,
86
+ numbers: UIKeyboardTypeNumberPad,
87
+ phone: UIKeyboardTypePhonePad,
88
+ name: UIKeyboardTypeNamePhonePad,
89
+ email: UIKeyboardTypeEmailAddress,
90
+ decimal: UIKeyboardTypeDecimalPad,
91
+ twitter: UIKeyboardTypeTwitter,
92
+ search: UIKeyboardTypeWebSearch
93
+ }
94
+
95
+ def disabled
96
+ ! @_.isEnabled
97
+ end
98
+
99
+ alias :disabled? :disabled
100
+
101
+ def disabled=(value)
102
+ @_.enabled = ! value
103
+ end
104
+
105
+ def disable
106
+ self.disabled = true
107
+ end
108
+
109
+ def enable
110
+ self.disabled = false
111
+ end
112
+
113
+ def focus
114
+ @_.becomeFirstResponder
115
+ end
116
+
117
+ def blur
38
118
  @_.resignFirstResponder
39
119
  end
40
120
 
121
+ # delegate
122
+
123
+ def textFieldShouldReturn(textField)
124
+ blur
125
+ end
126
+
127
+ protected
128
+
129
+ def handle_focus
130
+ emit('focus')
131
+ end
132
+
133
+ def handle_change
134
+ emit('change')
135
+ end
136
+
137
+ def handle_blur
138
+ emit('blur')
139
+ end
41
140
  end
@@ -1,4 +1,4 @@
1
- class Scroll < UnderOs::UI::View
1
+ class UnderOs::UI::Scroll < UnderOs::UI::View
2
2
  wraps UIScrollView, tag: :scroll
3
3
 
4
4
  def initialize(options={})
@@ -1,15 +1,12 @@
1
- class UnderOs::UI::Select < UnderOs::UI::View
1
+ class UnderOs::UI::Select < UnderOs::UI::Input
2
2
  wraps UIPickerView, tag: :select
3
3
 
4
4
  def initialize(options={})
5
5
  super
6
6
 
7
7
  self.options = options.delete(:options) if options[:options]
8
- self.value = options.delete(:value) if options[:value]
8
+ @_.showsSelectionIndicator = true if options[:lense]
9
9
 
10
- #@_.showsSelectionIndicator = true if options[:lense]
11
-
12
- @_.delegate = self
13
10
  @_.dataSource = self
14
11
  end
15
12
 
@@ -44,7 +41,7 @@ class UnderOs::UI::Select < UnderOs::UI::View
44
41
  def value=(value)
45
42
  prev_val = @value
46
43
  @value = Array(value).map(&:to_s)
47
- emit :change if @value != prev_val
44
+ handle_change if @value != prev_val
48
45
 
49
46
  @value.each_with_index do |value, group|
50
47
  i = 0;
@@ -1,6 +1,4 @@
1
- class UnderOs::UI::Slider < UnderOs::UI::View
2
- include UnderOs::UI::Editable
3
-
1
+ class UnderOs::UI::Slider < UnderOs::UI::Input
4
2
  wraps UISlider, tag: 'slider'
5
3
 
6
4
  def initialize(options={})
@@ -8,10 +6,9 @@ class UnderOs::UI::Slider < UnderOs::UI::View
8
6
 
9
7
  self.min = options[:min] if options[:min]
10
8
  self.max = options[:max] if options[:max]
11
- self.value = options[:value] if options[:value]
12
9
 
13
10
  @_.continuous = options.delete(:track) || true # track the changes as they go
14
- @_.addTarget self, action: :fire_change_event, forControlEvents:UIControlEventValueChanged
11
+ @_.addTarget self, action: :handle_change, forControlEvents:UIControlEventValueChanged
15
12
  end
16
13
 
17
14
  def value
@@ -37,13 +34,4 @@ class UnderOs::UI::Slider < UnderOs::UI::View
37
34
  def max=(value)
38
35
  @_.maximumValue = value.to_f
39
36
  end
40
-
41
- private
42
-
43
- def fire_change_event
44
- if @_prev_value != @_.value
45
- @_prev_value = @_.value
46
- emit :change
47
- end
48
- end
49
37
  end
@@ -1,13 +1,10 @@
1
- class UnderOs::UI::Switch < UnderOs::UI::View
2
- include UnderOs::UI::Editable
3
-
1
+ class UnderOs::UI::Switch < UnderOs::UI::Input
4
2
  wraps UISwitch, tag: 'switch'
5
3
 
6
4
  def initialize(options={})
7
5
  super
8
-
9
- self.value = options[:value] if options[:value]
10
6
  self.checked = options[:checked] if options[:checked]
7
+ @_.addTarget self, action: :handle_change, forControlEvents:UIControlEventValueChanged
11
8
  end
12
9
 
13
10
  def value
@@ -1,14 +1,19 @@
1
- class UnderOs::UI::Textarea < UnderOs::UI::View
2
- include UnderOs::UI::Editable
3
-
1
+ class UnderOs::UI::Textarea < UnderOs::UI::Input
4
2
  wraps UITextView, tag: 'textarea'
5
3
 
6
- def initialize(options={})
7
- super
4
+ alias :text= :value= # to get values from the HTML layouts
5
+
6
+ # delegate
8
7
 
9
- self.value = options[:value] if options[:value]
10
- self.keyboard = options[:keyboard] if options[:keyboard]
8
+ def textViewDidBeginEditing(textView)
9
+ handle_focus
11
10
  end
12
11
 
13
- alias :text= :value= # to get values from the HTML layouts
12
+ def textViewDidChange(textView)
13
+ handle_change
14
+ end
15
+
16
+ def textViewDidEndEditing(textView)
17
+ handle_blur
18
+ end
14
19
  end
data/lib/under_os.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module UnderOs
2
- VERSION='1.1.0'
2
+ VERSION='1.2.0'
3
3
  end
4
4
 
5
5
  UOS = UnderOS = UnderOs