fron 0.2.0rc1 → 1.0.0rc1

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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +20 -0
  3. data/.reek +2 -0
  4. data/.rubocop.yml +14 -11
  5. data/Gemfile +6 -3
  6. data/Gemfile.lock +73 -86
  7. data/Rakefile +11 -15
  8. data/Readme.md +1 -1
  9. data/fron.gemspec +2 -2
  10. data/lib/fron/version.rb +1 -1
  11. data/opal/fron.rb +2 -0
  12. data/opal/fron/core.rb +1 -0
  13. data/opal/fron/core/behaviors/components.rb +18 -10
  14. data/opal/fron/core/behaviors/events.rb +9 -10
  15. data/opal/fron/core/behaviors/routes.rb +6 -10
  16. data/opal/fron/core/behaviors/style.rb +30 -0
  17. data/opal/fron/core/component.rb +44 -23
  18. data/opal/fron/core/eventable.rb +3 -3
  19. data/opal/fron/core/logger.rb +1 -1
  20. data/opal/fron/core/sheet.rb +140 -0
  21. data/opal/fron/core_ext.rb +1 -0
  22. data/opal/fron/core_ext/array.rb +23 -0
  23. data/opal/fron/core_ext/hash.rb +6 -6
  24. data/opal/fron/core_ext/kernel.rb +10 -1
  25. data/opal/fron/core_ext/numeric.rb +7 -0
  26. data/opal/fron/core_ext/time.rb +6 -0
  27. data/opal/fron/dom/document.rb +6 -3
  28. data/opal/fron/dom/element.rb +79 -19
  29. data/opal/fron/dom/event.rb +5 -1
  30. data/opal/fron/dom/modules/dimensions.rb +0 -14
  31. data/opal/fron/dom/modules/element_accessor.rb +25 -0
  32. data/opal/fron/dom/modules/events.rb +1 -1
  33. data/opal/fron/dom/node.rb +7 -5
  34. data/opal/fron/dom/style.rb +0 -2
  35. data/opal/fron/dom/window.rb +14 -0
  36. data/opal/fron/event_mock.rb +24 -6
  37. data/opal/fron/js/scroll_into_view_if_needed.js +27 -0
  38. data/opal/fron/js/syntetic_event.js +20 -13
  39. data/opal/fron/request/request.rb +21 -19
  40. data/opal/fron/request/response.rb +1 -1
  41. data/opal/fron/storage.rb +2 -0
  42. data/opal/fron/storage/local_storage.rb +3 -45
  43. data/opal/fron/storage/session_storage.rb +12 -0
  44. data/opal/fron/storage/store.rb +54 -0
  45. data/opal/fron/utils/drag.rb +21 -18
  46. data/opal/fron/utils/keyboard.rb +14 -12
  47. data/opal/fron/utils/point.rb +12 -4
  48. data/opal/fron/utils/render_proc.rb +6 -2
  49. data/spec/core-ext/array_spec.rb +10 -2
  50. data/spec/core-ext/numeric_spec.rb +6 -0
  51. data/spec/core/behaviors/style_spec.rb +51 -0
  52. data/spec/core/component_inheritance_spec.rb +10 -15
  53. data/spec/core/component_spec.rb +10 -15
  54. data/spec/dom/element_spec.rb +12 -1
  55. data/spec/dom/modules/classlist_spec.rb +8 -9
  56. data/spec/dom/modules/dimensions_spec.rb +2 -1
  57. data/spec/dom/modules/events_spec.rb +42 -31
  58. data/spec/dom/style_spec.rb +1 -1
  59. data/spec/spec_helper.rb +0 -1
  60. data/spec/utils/drag_spec.rb +2 -2
  61. data/spec/utils/keyboard_spec.rb +4 -1
  62. data/website/application.rb +4 -0
  63. data/website/config.ru +30 -0
  64. data/website/examples/content_editable.rb +29 -0
  65. data/website/examples/converter.rb +49 -0
  66. data/website/examples/icon_button.rb +20 -0
  67. data/website/examples/image_paragraph.rb +33 -0
  68. data/website/examples/my_blue_box.rb +9 -0
  69. data/website/examples/my_box.rb +9 -0
  70. data/website/examples/my_button.rb +27 -0
  71. data/website/examples/my_green_box.rb +14 -0
  72. data/website/examples/source_reader.rb +32 -0
  73. data/website/examples/text_area.rb +42 -0
  74. data/website/pages/components.md.erb +16 -0
  75. data/website/pages/components/composition.md.erb +9 -0
  76. data/website/pages/components/events.md.erb +20 -0
  77. data/website/pages/components/inheritance.md.erb +19 -0
  78. data/website/pages/components/routes.md.erb +49 -0
  79. data/website/pages/components/styles.md.erb +38 -0
  80. data/website/pages/getting-started.md +8 -0
  81. data/website/pages/home.md +4 -0
  82. data/website/pages/intro.md +30 -0
  83. data/website/pages/utilities.md +10 -0
  84. data/website/pages/utilities/local-storage.md.erb +16 -0
  85. data/website/pages/utilities/request.md.erb +12 -0
  86. data/website/setup.rb +162 -0
  87. data/website/vendor/highlight.js +2 -0
  88. data/website/vendor/highlight.ruby.js +1 -0
  89. data/website/vendor/marked.min.js +6 -0
  90. metadata +43 -7
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe DOM::Element do
4
- subject { described_class.new 'div' }
4
+ subject { described_class.new 'div[tabindex=0]' }
5
5
  let(:el) { subject.instance_variable_get('@el') }
6
6
  let(:a) { described_class.new 'a' }
7
7
  let(:a2) { described_class.new 'a' }
@@ -54,6 +54,17 @@ describe DOM::Element do
54
54
  end
55
55
  end
56
56
 
57
+ describe '#tabindex' do
58
+ it 'should return tabindex' do
59
+ subject.tabindex.should eq '0'
60
+ end
61
+
62
+ it 'should set tabindex' do
63
+ subject.tabindex = 1
64
+ subject[:tabindex].should eq '1'
65
+ end
66
+ end
67
+
57
68
  describe '#disabled' do
58
69
  it 'should return the disabled state of the element' do
59
70
  `#{el}.disabled = true`
@@ -2,17 +2,16 @@ require 'spec_helper'
2
2
 
3
3
  describe DOM::ClassList do
4
4
  let(:element) { DOM::Element.new 'div' }
5
- subject { element['class'] }
6
5
 
7
6
  describe '#add_class' do
8
7
  it 'should add a class' do
9
8
  element.add_class 'test'
10
- subject.should eq 'test'
9
+ element['class'].should eq 'test'
11
10
  end
12
11
 
13
12
  it 'should add multiple classes' do
14
13
  element.add_class 'test', 'help'
15
- subject.should eq 'test help'
14
+ element['class'].should eq 'test help'
16
15
  end
17
16
  end
18
17
 
@@ -23,12 +22,12 @@ describe DOM::ClassList do
23
22
 
24
23
  it 'should add a class' do
25
24
  element.remove_class 'test'
26
- subject.should eq 'help'
25
+ element['class'].should eq 'help'
27
26
  end
28
27
 
29
28
  it 'should add multiple classes' do
30
29
  element.remove_class 'test', 'help'
31
- subject.should eq nil
30
+ element['class'].should eq nil
32
31
  end
33
32
  end
34
33
 
@@ -50,22 +49,22 @@ describe DOM::ClassList do
50
49
 
51
50
  it 'should remove class if the element has the given class' do
52
51
  element.toggle_class 'test'
53
- subject.should eq nil
52
+ element['class'].should eq nil
54
53
  end
55
54
 
56
55
  it 'should add class if the element does not have the given class' do
57
56
  element.toggle_class 'help'
58
- subject.should eq 'test help'
57
+ element['class'].should eq 'test help'
59
58
  end
60
59
 
61
60
  it 'should add class if the second argument is true' do
62
61
  element.toggle_class 'help', true
63
- subject.should eq 'test help'
62
+ element['class'].should eq 'test help'
64
63
  end
65
64
 
66
65
  it 'should remove class if the second argument if false' do
67
66
  element.toggle_class 'test', false
68
- subject.should eq nil
67
+ element['class'].should eq nil
69
68
  end
70
69
  end
71
70
  end
@@ -81,7 +81,8 @@ describe DOM::Dimensions do
81
81
  end
82
82
 
83
83
  context 'not in viewport' do
84
- height, width = `window.innerHeight`, `window.innerWidth`
84
+ height = `window.innerHeight`
85
+ width = `window.innerWidth`
85
86
  [
86
87
  [-80, -100], # Top Left
87
88
  [-80, 0], # Top
@@ -2,35 +2,38 @@ require 'spec_helper'
2
2
 
3
3
  describe DOM::Events do
4
4
  let(:element) { DOM::Element.new 'div' }
5
- subject { element.instance_variable_get '@listeners' }
6
5
 
7
6
  describe '#on' do
8
- async 'should register for event' do
7
+ it 'should register for event' do
8
+ promise = Promise.new
9
9
  listener = element.on 'click' do
10
- run_async do
11
- subject.should_not be nil
12
- subject[:click].should_not be nil
13
- subject[:click].length.should eq 1
14
- subject[:click].include?(listener).should eq true
15
- element.off 'click'
16
- end
10
+ listeners = element.instance_variable_get '@listeners'
11
+ listeners.should_not be nil
12
+ listeners[:click].should_not be nil
13
+ listeners[:click].length.should eq 1
14
+ listeners[:click].include?(listener).should eq true
15
+ promise.resolve
16
+ element.off 'click'
17
17
  end
18
18
  element.trigger 'click'
19
+ promise
19
20
  end
20
21
  end
21
22
 
22
23
  describe '#on!' do
23
- async 'should register for event' do
24
+ it 'should register for event' do
25
+ promise = Promise.new
24
26
  listener = element.on! 'click' do
25
- run_async do
26
- subject.should_not be nil
27
- subject[:click].should_not be nil
28
- subject[:click].length.should eq 1
29
- subject[:click].include?(listener).should eq true
30
- element.off 'click'
31
- end
27
+ listeners = element.instance_variable_get '@listeners'
28
+ listeners.should_not be nil
29
+ listeners[:click].should_not be_nil
30
+ listeners[:click].length.should eq 1
31
+ listeners[:click].include?(listener).should eq true
32
+ promise.resolve
33
+ element.off 'click'
32
34
  end
33
35
  element.trigger 'click'
36
+ promise
34
37
  end
35
38
  end
36
39
 
@@ -38,50 +41,58 @@ describe DOM::Events do
38
41
  context 'two arguments' do
39
42
  it 'should unregister for event' do
40
43
  listener = element.on 'click' do end
41
- subject[:click].include?(listener).should eq true
44
+ element.instance_variable_get('@listeners')[:click]
45
+ .include?(listener).should eq true
42
46
  element.off 'click', listener
43
- subject[:click].include?(listener).should eq false
47
+ element.instance_variable_get('@listeners')[:click]
48
+ .include?(listener).should eq false
44
49
  end
45
50
  end
46
51
 
47
52
  context 'one argument' do
48
53
  it 'should unregister all events for type' do
49
54
  listener = element.on 'click' do end
50
- subject[:click].include?(listener).should eq true
55
+ element.instance_variable_get('@listeners')[:click]
56
+ .include?(listener).should eq true
51
57
  element.off 'click'
52
- subject[:click].include?(listener).should eq false
58
+ element.instance_variable_get('@listeners')[:click]
59
+ .include?(listener).should eq false
53
60
  end
54
61
  end
55
62
 
56
63
  context 'no argument' do
57
64
  it 'should unregister all events' do
58
65
  listener = element.on 'click' do end
59
- subject[:click].include?(listener).should eq true
66
+ element.instance_variable_get('@listeners')[:click]
67
+ .include?(listener).should eq true
60
68
  element.off
61
- subject[:click].include?(listener).should eq false
69
+ element.instance_variable_get('@listeners')[:click]
70
+ .include?(listener).should eq false
62
71
  end
63
72
  end
64
73
  end
65
74
 
66
75
  describe '#delegate' do
67
- async 'should call the listener if the element matches the selector' do
76
+ it 'should call the listener if the element matches the selector' do
77
+ promise = Promise.new
68
78
  element.delegate 'click', 'div' do
69
- run_async do
70
- element.off 'click'
71
- end
79
+ promise.resolve
80
+ element.off 'click'
72
81
  end
73
82
  element.trigger 'click'
83
+ promise
74
84
  end
75
85
  end
76
86
 
77
87
  describe '#trigger' do
78
- async 'should trigger the event' do
88
+ it 'should trigger the event' do
89
+ promise = Promise.new
79
90
  element.on 'click' do
80
- run_async do
81
- element.off 'click'
82
- end
91
+ promise.resolve
92
+ element.off 'click'
83
93
  end
84
94
  element.trigger 'click'
95
+ promise
85
96
  end
86
97
  end
87
98
  end
@@ -23,7 +23,7 @@ describe DOM::Style do
23
23
  end
24
24
  end
25
25
 
26
- describe '[]'do
26
+ describe '[]' do
27
27
  it 'should return with the value of the given style' do
28
28
  `#{el}.style.display = 'block'`
29
29
  subject.style['display'].should eq 'block'
@@ -1,4 +1,3 @@
1
- require 'rspec_coverage_helper'
2
1
  require 'js/mocks'
3
2
  require 'fron'
4
3
  require 'fron/event_mock'
@@ -2,8 +2,8 @@ require 'spec_helper'
2
2
  require 'fron/utils/drag'
3
3
 
4
4
  describe Fron::Drag do
5
- let(:event) { double(pageX: 0, pageY: 0, preventDefult: true, stop: true, target: true) }
6
- let(:base) { DOM::Element.new 'div' }
5
+ let(:event) { double(page_x: 0, page_y: 0, preventDefult: true, stop: true, target: true) }
6
+ let(:base) { DOM::Element.new 'div' }
7
7
  let(:position) { double }
8
8
 
9
9
  subject { described_class.new base }
@@ -7,7 +7,10 @@ class TestKeyboard < Fron::Keyboard
7
7
  end
8
8
 
9
9
  describe TestKeyboard do
10
- let(:event) { DOM::Event.new `{ctrlKey: true, altKey: true, shiftKey: true, keyCode: 38}` }
10
+ let(:event) {
11
+ DOM::Event.new `{ ctrlKey: true, altKey: true, shiftKey: true,
12
+ metaKey: false, keyCode: 38 }`
13
+ }
11
14
 
12
15
  describe Fron::Keyboard do
13
16
  it 'should work on its own' do
@@ -0,0 +1,4 @@
1
+ require 'setup'
2
+
3
+ DOM::Document.body << Main.new
4
+ DOM::Window.trigger :popstate
@@ -0,0 +1,30 @@
1
+ require 'fron'
2
+ require 'active_support/core_ext/string/inflections'
3
+
4
+ # Proxy
5
+ class Proxy
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ env['PATH_INFO'] = '/' if !(env['PATH_INFO'] =~ /\..*$/) && !(env['PATH_INFO'] =~ /^\/(pages)/)
12
+ @app.call env
13
+ end
14
+ end
15
+
16
+ use Proxy
17
+
18
+ module Helpers
19
+ def example(klass)
20
+ source = File.read(File.join(File.dirname(__FILE__), "examples/#{klass.underscore}.rb"))
21
+ "<example class='#{klass}'></example>\n```ruby\n#{source}\n```"
22
+ end
23
+ end
24
+
25
+ run Opal::Server.new { |s|
26
+ s.append_path 'website'
27
+ s.source_map = false
28
+ s.main = 'application'
29
+ s.sprockets.context_class.send(:include, Helpers)
30
+ }
@@ -0,0 +1,29 @@
1
+ # We start a by extending from Fron::Component
2
+ class ContentEditable < Fron::Component
3
+ # Set the tag
4
+ tag 'content-editable'
5
+
6
+ # When the element is blurred call the change method
7
+ on :blur, :change
8
+
9
+ # Set styles
10
+ style background: '#F9F9F9',
11
+ borderRadius: 5.px,
12
+ display: :block,
13
+ padding: 10.px
14
+
15
+ # Initializes the compontent:
16
+ # * Sets the contenteditable attribute to true
17
+ # * Sets the spellcheck to false
18
+ def initialize
19
+ super
20
+ self.contenteditable = true
21
+ self.spellcheck = false
22
+ self.text = 'Some default content...'
23
+ end
24
+
25
+ # Run on the blur event
26
+ def change
27
+ logger.info "The content is now: #{text}"
28
+ end
29
+ end
@@ -0,0 +1,49 @@
1
+ # Celsius to Fahrenheit Converter
2
+ class Converter < Fron::Component
3
+ # Celsius part
4
+ component :celcius, :div do
5
+ component :label, 'label', text: 'Celsius: '
6
+ component :input, 'input', value: 0
7
+ end
8
+
9
+ # Fahrenheit part
10
+ component :fahrenheit, :div do
11
+ component :label, 'label', text: 'Fahrenheit:'
12
+ component :result, 'span', text: '32'
13
+ end
14
+
15
+ # Button
16
+ component :button, 'button', text: 'Convert'
17
+
18
+ # We will convert on click of the button
19
+ on :click, 'button', :convert
20
+ # or on change of the input
21
+ on :change, :convert
22
+
23
+ # Styling
24
+ style background: '#F9F9F9',
25
+ alignItems: 'flex-end',
26
+ display: :flex,
27
+ padding: 10.px,
28
+ label: { display: :block },
29
+ div: { flexDirection: :column,
30
+ marginRight: 5.px,
31
+ display: :flex },
32
+ button: { position: :relative,
33
+ height: 30.px,
34
+ top: -1.px },
35
+ 'input, span' => {
36
+ display: 'inline-block',
37
+ border: '1px solid #ddd',
38
+ lineHeight: 20.px,
39
+ fontSize: 14.px,
40
+ padding: 5.px,
41
+ height: 30.px,
42
+ width: 200.px
43
+ }
44
+
45
+ # Converting Logic
46
+ def convert
47
+ @fahrenheit.result.text = @celcius.input.value.to_i * 9 / 5 + 32
48
+ end
49
+ end
@@ -0,0 +1,20 @@
1
+ # Extend MyButton
2
+ class IconButton < MyButton
3
+ extend Forwardable
4
+
5
+ # Set the tag
6
+ tag 'icon-button'
7
+
8
+ # Add child components
9
+ component :icon, :icon
10
+ component :span, :span
11
+
12
+ # Delegate methods
13
+ def_delegators :span, :text=, :text
14
+
15
+ # Style the icon, everything else is inherited
16
+ style 'icon:before' => { fontFamily: 'FontAwesome',
17
+ display: 'inline-block',
18
+ marginRight: 10.px,
19
+ content: '"\f0f4"' }
20
+ end
@@ -0,0 +1,33 @@
1
+ # Paragraph component with an image.
2
+ class ImageParagraph < Fron::Component
3
+ tag 'image-paragraph'
4
+
5
+ # Define components
6
+ component :image, :img
7
+ component :content, :content
8
+
9
+ # Set Styling
10
+ style border: '1px solid #EEE',
11
+ display: :block,
12
+ padding: 20.px,
13
+ img: { float: :left,
14
+ marginRight: 20.px },
15
+ '&:after' => { display: :block,
16
+ content: '""',
17
+ clear: :both }
18
+
19
+ # Set data
20
+ def initialize
21
+ super
22
+ @image[:src] = 'http://placehold.it/180/f9f9f9/666'
23
+ @content.text = 'Lorem ipsum dolor sit amet, consectetur adipiscing
24
+ elit. Vivamus molestie placerat sem a ultrices.
25
+ Cras ultricies enim luctus enim aliquam convallis.
26
+ Sed et felis volutpat, suscipit urna et, malesuada
27
+ tellus. Nunc et tellus fringilla, tristique eros
28
+ et, aliquam nisi. Quisque faucibus porta odio non
29
+ mollis. Donec volutpat convallis blandit. Donec
30
+ non nisl elit. Quisque orci neque, consequat
31
+ interdum elit eu, auctor elementum magna.'
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ # My sweet red box is gone....NOOOOOOOO!!!
2
+ class MyBlueBox < MyBox
3
+ tag 'my-blue-box'
4
+
5
+ # This is only needed if no style DSL is used
6
+ ensure_styles!
7
+
8
+ style background: :blue
9
+ end