under-os 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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