under-os-ui 1.4.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.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +26 -0
  3. data/lib/assets/fontawesome-webfont.ttf +0 -0
  4. data/lib/assets/under-os.css +115 -0
  5. data/lib/core/kernel.rb +16 -0
  6. data/lib/under-os-ui.rb +6 -0
  7. data/lib/under_os/app.rb +26 -0
  8. data/lib/under_os/config.rb +25 -0
  9. data/lib/under_os/history.rb +53 -0
  10. data/lib/under_os/page.rb +178 -0
  11. data/lib/under_os/page/builder.rb +96 -0
  12. data/lib/under_os/page/layout.rb +43 -0
  13. data/lib/under_os/page/matcher.rb +128 -0
  14. data/lib/under_os/page/stylesheet.rb +67 -0
  15. data/lib/under_os/parser.rb +24 -0
  16. data/lib/under_os/parser/css.rb +37 -0
  17. data/lib/under_os/parser/html.rb +97 -0
  18. data/lib/under_os/ui.rb +3 -0
  19. data/lib/under_os/ui/alert.rb +52 -0
  20. data/lib/under_os/ui/button.rb +42 -0
  21. data/lib/under_os/ui/collection.rb +65 -0
  22. data/lib/under_os/ui/collection/cell.rb +21 -0
  23. data/lib/under_os/ui/collection/delegate.rb +70 -0
  24. data/lib/under_os/ui/collection/item.rb +32 -0
  25. data/lib/under_os/ui/collection/layout.rb +43 -0
  26. data/lib/under_os/ui/collection/styles.rb +15 -0
  27. data/lib/under_os/ui/div.rb +3 -0
  28. data/lib/under_os/ui/form.rb +60 -0
  29. data/lib/under_os/ui/icon.rb +61 -0
  30. data/lib/under_os/ui/icon/awesome.rb +376 -0
  31. data/lib/under_os/ui/icon/engine.rb +9 -0
  32. data/lib/under_os/ui/image.rb +31 -0
  33. data/lib/under_os/ui/input.rb +140 -0
  34. data/lib/under_os/ui/label.rb +21 -0
  35. data/lib/under_os/ui/locker.rb +42 -0
  36. data/lib/under_os/ui/navbar.rb +123 -0
  37. data/lib/under_os/ui/progress.rb +17 -0
  38. data/lib/under_os/ui/scroll.rb +102 -0
  39. data/lib/under_os/ui/select.rb +95 -0
  40. data/lib/under_os/ui/sidebar.rb +45 -0
  41. data/lib/under_os/ui/slider.rb +37 -0
  42. data/lib/under_os/ui/spinner.rb +23 -0
  43. data/lib/under_os/ui/style.rb +21 -0
  44. data/lib/under_os/ui/style/fonts.rb +56 -0
  45. data/lib/under_os/ui/style/margins.rb +164 -0
  46. data/lib/under_os/ui/style/outlining.rb +170 -0
  47. data/lib/under_os/ui/style/positioning.rb +183 -0
  48. data/lib/under_os/ui/switch.rb +26 -0
  49. data/lib/under_os/ui/textarea.rb +19 -0
  50. data/lib/under_os/ui/utils/animation.rb +101 -0
  51. data/lib/under_os/ui/utils/commons.rb +70 -0
  52. data/lib/under_os/ui/utils/dimensions.rb +37 -0
  53. data/lib/under_os/ui/utils/events.rb +210 -0
  54. data/lib/under_os/ui/utils/manipulation.rb +44 -0
  55. data/lib/under_os/ui/utils/position.rb +21 -0
  56. data/lib/under_os/ui/utils/size.rb +21 -0
  57. data/lib/under_os/ui/utils/styles.rb +89 -0
  58. data/lib/under_os/ui/utils/traversing.rb +44 -0
  59. data/lib/under_os/ui/utils/wrap.rb +77 -0
  60. data/lib/under_os/ui/view.rb +31 -0
  61. data/spec/assets/app.css +13 -0
  62. data/spec/assets/test.css +7 -0
  63. data/spec/assets/test.html +3 -0
  64. data/spec/assets/test.png +0 -0
  65. data/spec/assets/test_page.rb +2 -0
  66. data/spec/under_os/page/builder_spec.rb +128 -0
  67. data/spec/under_os/page/layout_spec.rb +18 -0
  68. data/spec/under_os/page/matcher_spec.rb +260 -0
  69. data/spec/under_os/page/stylesheet_spec.rb +83 -0
  70. data/spec/under_os/page_spec.rb +5 -0
  71. data/spec/under_os/parser/css_spec.rb +77 -0
  72. data/spec/under_os/parser/html_spec.rb +152 -0
  73. data/spec/under_os/parser_spec.rb +16 -0
  74. data/spec/under_os/ui/button_spec.rb +50 -0
  75. data/spec/under_os/ui/collection_spec.rb +19 -0
  76. data/spec/under_os/ui/div_spec.rb +24 -0
  77. data/spec/under_os/ui/form_spec.rb +156 -0
  78. data/spec/under_os/ui/icon_spec.rb +57 -0
  79. data/spec/under_os/ui/image_spec.rb +39 -0
  80. data/spec/under_os/ui/input_spec.rb +109 -0
  81. data/spec/under_os/ui/label_spec.rb +22 -0
  82. data/spec/under_os/ui/locker_spec.rb +31 -0
  83. data/spec/under_os/ui/progress_spec.rb +31 -0
  84. data/spec/under_os/ui/scroll_spec.rb +75 -0
  85. data/spec/under_os/ui/select_spec.rb +135 -0
  86. data/spec/under_os/ui/sidebar_spec.rb +35 -0
  87. data/spec/under_os/ui/slider_spec.rb +69 -0
  88. data/spec/under_os/ui/spinner_spec.rb +57 -0
  89. data/spec/under_os/ui/style/fonts_spec.rb +111 -0
  90. data/spec/under_os/ui/style/margins_spec.rb +106 -0
  91. data/spec/under_os/ui/style/outlining_spec.rb +101 -0
  92. data/spec/under_os/ui/style/positioning_spec.rb +69 -0
  93. data/spec/under_os/ui/style_spec.rb +19 -0
  94. data/spec/under_os/ui/switch_spec.rb +60 -0
  95. data/spec/under_os/ui/textarea_spec.rb +34 -0
  96. data/spec/under_os/ui/utils/commons_spec.rb +81 -0
  97. data/spec/under_os/ui/utils/events_spec.rb +87 -0
  98. data/spec/under_os/ui/utils/manipulation_spec.rb +130 -0
  99. data/spec/under_os/ui/utils/styles_spec.rb +140 -0
  100. data/spec/under_os/ui/utils/traversing_spec.rb +124 -0
  101. data/spec/under_os/ui/utils/wrap_spec.rb +69 -0
  102. data/spec/under_os/ui/view_spec.rb +39 -0
  103. data/under-os-ui.gemspec +23 -0
  104. metadata +216 -0
@@ -0,0 +1,3 @@
1
+ module UnderOs::UI
2
+ # Just a namespace for UI things
3
+ end
@@ -0,0 +1,52 @@
1
+ class UnderOs::UI::Alert
2
+ include UnderOs::Events
3
+
4
+ def initialize(options={})
5
+ options = {message: options} if options.is_a?(String)
6
+ self.on = options.delete[:on] if options[:on]
7
+
8
+ @_ = CustomAlertView.alloc.initiWithOptions(self, options)
9
+ @_.show unless options[:show] == false
10
+ end
11
+
12
+ def show
13
+ @_.show
14
+ self
15
+ end
16
+
17
+ def hide(animated=true)
18
+ @_.dismissWithClickedButtonIndex(0, animated: animated)
19
+ self
20
+ end
21
+
22
+ def visible
23
+ @_.visible
24
+ end
25
+
26
+ def hidden
27
+ !visible
28
+ end
29
+
30
+ class CustomAlertView < UIAlertView
31
+ def initiWithOptions(wrapper, options)
32
+ @wrapper = wrapper
33
+
34
+ initWithTitle( options[:title] || "",
35
+ message: options[:message] || "No message given",
36
+ delegate: self,
37
+ cancelButtonTitle: options[:button] || "Ok",
38
+ otherButtonTitles: nil )
39
+
40
+ (options[:buttons] || []).each do |title|
41
+ addButtonWithTitle title
42
+ end
43
+
44
+ self
45
+ end
46
+
47
+ def alertView(alertView, willDismissWithButtonIndex:buttonIndex)
48
+ @wrapper.emit(:tap, buttonIndex: buttonIndex, buttonTitle: buttonTitleAtIndex(buttonIndex))
49
+ @wrapper.emit(:close)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,42 @@
1
+ class UnderOS::UI::Button < UnderOS::UI::View
2
+ wraps UIButton, tag: 'button'
3
+
4
+ def initialize(options={})
5
+ super
6
+
7
+ self.text = options.delete(:text) || ''
8
+ self.disable if options[:disabled]
9
+
10
+ @_.showsTouchWhenHighlighted = true
11
+ @_.setBackgroundImage(options.delete(:image), forState:UIControlStateNormal) if options[:image]
12
+ @_.sizeToFit
13
+ end
14
+
15
+ def text
16
+ @_.currentTitle
17
+ end
18
+
19
+ def text=(new_text, state=UIControlStateNormal)
20
+ @_.setTitle new_text, forState:state
21
+ repaint
22
+ end
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
+
42
+ end
@@ -0,0 +1,65 @@
1
+ class UnderOs::UI::Collection < UnderOs::UI::View
2
+ wraps UICollectionView, tag: :collection
3
+
4
+ def initialize(options={})
5
+ super
6
+
7
+ self.layout = Layout.new if ! options[:layout]
8
+ self.layout = options.delete(:layout) if options[:layout].is_a?(Class)
9
+ self.layout = options.delete(:layout).constantize if options[:layout].is_a?(String)
10
+
11
+ @_.delegate = @_.dataSource = Delegate.new(self)
12
+ @_.registerClass(Cell, forCellWithReuseIdentifier:'UOSCollectionCell')
13
+ end
14
+
15
+ def on(*args, &block)
16
+ super *args do |event|
17
+ params = [event.item, event.index, event.section]
18
+ params = params.slice(0, block.arity) if block.arity > -1
19
+
20
+ block.call *params
21
+ end
22
+ end
23
+
24
+ def layout
25
+ @layout
26
+ end
27
+
28
+ def layout=(layout)
29
+ layout = Layout.new(layout) if layout.is_a?(UICollectionViewLayout)
30
+ @_.collectionViewLayout = (@layout = layout)._
31
+ end
32
+
33
+ def item_class
34
+ Cell.classes[self]
35
+ end
36
+
37
+ def item_class=(klass)
38
+ Cell.classes[self] = klass
39
+ end
40
+
41
+ def reload
42
+ @_.reloadData
43
+ self
44
+ end
45
+
46
+ def number_of_items(section=0)
47
+ (@number_of_items || [0])[section]
48
+ end
49
+
50
+ def number_of_items=(value)
51
+ @number_of_items = value.is_a?(Numeric) ? [value] : value
52
+ reload
53
+ end
54
+
55
+ def number_of_sections
56
+ (@number_of_items || [0]).size
57
+ end
58
+
59
+ def repaint(stylesheet=nil)
60
+ stylesheet ||= page && page.stylesheet
61
+
62
+ self.style = stylesheet.styles_for(self) if stylesheet
63
+ Styles.build(self, stylesheet) if stylesheet
64
+ end
65
+ end
@@ -0,0 +1,21 @@
1
+ #
2
+ # This is a bridge to the iOS native functionality
3
+ # please do not use it in your code
4
+ #
5
+ class UnderOs::UI::Collection::Cell < UICollectionViewCell
6
+
7
+ def self.classes
8
+ @classes ||= {}
9
+ end
10
+
11
+ def uos_view_for(collection)
12
+ @uos_view ||= self.class.classes[collection].for(collection).tap do |view|
13
+ contentView.addSubview(view._)
14
+ end
15
+ end
16
+
17
+ def prepareForReuse
18
+ super
19
+ @uos_view.cleanup if @uos_view
20
+ end
21
+ end
@@ -0,0 +1,70 @@
1
+ #
2
+ # The iOS level events receiver, not for a public use
3
+ #
4
+ class UnderOs::UI::Collection::Delegate < UIViewController
5
+
6
+ def self.new(collection)
7
+ alloc.tap do |instance|
8
+ instance.instance_eval do
9
+ @collection = collection
10
+ end
11
+ end
12
+ end
13
+
14
+ ################################################################
15
+ # DataSource API
16
+ ################################################################
17
+
18
+ def numberOfSectionsInCollectionView(collection)
19
+ @collection.number_of_sections
20
+ end
21
+
22
+ def collectionView(collection, numberOfItemsInSection: section)
23
+ @collection.number_of_items(section)
24
+ end
25
+
26
+ def collectionView(collection, cellForItemAtIndexPath: indexPath)
27
+ collection.dequeueReusableCellWithReuseIdentifier('UOSCollectionCell', forIndexPath:indexPath).tap do |item|
28
+ @collection.emit(:item, item: item.uos_view_for(@collection), index: indexPath.row, section: indexPath.section)
29
+ end
30
+ end
31
+
32
+ # def collectionView(collection, viewForSupplementaryElementOfKind: kind, atIndexPath: indexPath)
33
+ # # kind is a string
34
+ # UICollectionReusableView.alloc.init
35
+ # UICollectionReusableView * reusableview = nil ;
36
+
37
+ # if ( kind == UICollectionElementKindSectionHeader ) {
38
+ # RecipeCollectionHeaderView * headerView = [ collectionView dequeueReusableSupplementaryViewOfKind : UICollectionElementKindSectionHeader withReuseIdentifier : @ "HeaderView" forIndexPath : indexPath ] ;
39
+ # NSString * title = [ [ NSString alloc ] initWithFormat : @ "Recipe Group #%i" , indexPath.section + 1 ] ;
40
+ # headerView.title.text = title;
41
+ # UIImage * headerImage = [ UIImage imageNamed : @ "header_banner.png" ] ;
42
+ # headerView.backgroundImage.image = headerImage;
43
+
44
+ # reusableview = headerView;
45
+ # }
46
+
47
+ # if ( kind == UICollectionElementKindSectionFooter ) {
48
+ # UICollectionReusableView * footerview = [ collectionView dequeueReusableSupplementaryViewOfKind : UICollectionElementKindSectionFooter withReuseIdentifier : @ "FooterView" forIndexPath : indexPath ] ;
49
+
50
+ # reusableview = footerview;
51
+ # }
52
+
53
+ # return reusableview;
54
+ # end
55
+
56
+
57
+ ################################################################
58
+ # DataSource API
59
+ ################################################################
60
+
61
+ def collectionView(collection, didSelectItemAtIndexPath: indexPath)
62
+ item = collection.cellForItemAtIndexPath(indexPath).uos_view_for(@collection)
63
+ @collection.emit(:select, item: item, index: indexPath.row, section: indexPath.section)
64
+ end
65
+
66
+ def collectionView(collection, didDeselectItemAtIndexPath: indexPath)
67
+ item = collection.cellForItemAtIndexPath(indexPath).uos_view_for(@collection)
68
+ @collection.emit(:unselect, item: item, index: indexPath.row, section: indexPath.section)
69
+ end
70
+ end
@@ -0,0 +1,32 @@
1
+ #
2
+ # This is the collection item class that you supposed
3
+ # to inherit (well, if you need to)
4
+ #
5
+ class UnderOs::UI::Collection::Item < UnderOs::UI::View
6
+
7
+ tag :item
8
+
9
+ def self.build(collection, &builder)
10
+ @builders ||= {}
11
+ @builders[collection] = builder
12
+ collection.item_class = self
13
+ end
14
+
15
+ def self.for(collection, stylesheet=nil)
16
+ new.tap do |view|
17
+ def view.parent; @_parent; end
18
+ view.instance_variable_set('@_parent', collection)
19
+
20
+ @builders[collection] && @builders[collection].call.each do |child|
21
+ view.insert child
22
+ end
23
+
24
+ view.repaint(stylesheet || UnderOs::App.history.current_page.stylesheet)
25
+ end
26
+ end
27
+
28
+ def cleanup
29
+ # implement me if you need to clean cells between reuse
30
+ end
31
+
32
+ end
@@ -0,0 +1,43 @@
1
+ #
2
+ # The basic, grid (flow) layout. inheritable.
3
+ #
4
+ class Layout
5
+ attr_reader :_
6
+
7
+ def initialize(layout=nil)
8
+ @_ = layout || UICollectionViewFlowLayout.alloc.init
9
+
10
+ self.items_spacing = 0
11
+ self.rows_spacing = 1
12
+ end
13
+
14
+ def item_size
15
+ end
16
+
17
+ def item_size=(*size)
18
+ size = UnderOs::Point.new(*size)
19
+ @_.itemSize = CGSizeMake(size.x, size.y)
20
+ end
21
+
22
+ def items_spacing
23
+ @_.minimumInteritemSpacing
24
+ end
25
+
26
+ def items_spacing=(value)
27
+ @_.minimumInteritemSpacing = value
28
+ end
29
+
30
+ def rows_spacing
31
+ @_.minimumLineSpacing
32
+ end
33
+
34
+ def rows_spacing=(value)
35
+ @_.minimumLineSpacing = value
36
+ end
37
+
38
+ def section_inset
39
+ end
40
+
41
+ def section_inset=(value)
42
+ end
43
+ end
@@ -0,0 +1,15 @@
1
+ #
2
+ # This thing catches styles from the collection element
3
+ # and adjusts the layout settings for them
4
+ #
5
+ class UnderOs::UI::Collection::Styles
6
+ def self.build(collection, stylesheet)
7
+ item = UnderOs::UI::Collection::Item.for(collection, stylesheet)
8
+
9
+ collection.layout.item_size = item.size
10
+ collection.layout.items_spacing = item.style.marginLeft + item.style.marginRight
11
+ collection.layout.rows_spacing = item.style.marginTop + item.style.marginBottom
12
+
13
+ # TODO header/footer
14
+ end
15
+ 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
@@ -0,0 +1,61 @@
1
+ class UnderOs::UI::Icon < UnderOs::UI::View
2
+ include UnderOs::UI::IconEngine
3
+ engine UnderOs::UI::IconEngineAwesome
4
+
5
+ wraps UIButton, tag: 'icon'
6
+
7
+ def initialize(options)
8
+ options = {type: options} if ! options.is_a?(Hash)
9
+
10
+ super(options)
11
+
12
+ self.type = options.delete(:type) || :bug
13
+ self.size = options.delete(:size) || 20
14
+ self.disable if options[:disabled]
15
+
16
+ @_.sizeToFit
17
+ @_.showsTouchWhenHighlighted = true
18
+ end
19
+
20
+ def type
21
+ @type
22
+ end
23
+
24
+ def type=(type)
25
+ @type = type
26
+ @_.setTitle self.class.engine.text(type), forState:UIControlStateNormal
27
+ end
28
+
29
+ def size(size=nil)
30
+ if size
31
+ self.size = size
32
+ self
33
+ else
34
+ @size
35
+ end
36
+ end
37
+
38
+ def size=(size)
39
+ @size = size
40
+ @_.setFont self.class.engine.font(size)
41
+ @_.sizeToFit
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
61
+ end