fron 0.2.0rc1 → 1.0.0rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +20 -0
- data/.reek +2 -0
- data/.rubocop.yml +14 -11
- data/Gemfile +6 -3
- data/Gemfile.lock +73 -86
- data/Rakefile +11 -15
- data/Readme.md +1 -1
- data/fron.gemspec +2 -2
- data/lib/fron/version.rb +1 -1
- data/opal/fron.rb +2 -0
- data/opal/fron/core.rb +1 -0
- data/opal/fron/core/behaviors/components.rb +18 -10
- data/opal/fron/core/behaviors/events.rb +9 -10
- data/opal/fron/core/behaviors/routes.rb +6 -10
- data/opal/fron/core/behaviors/style.rb +30 -0
- data/opal/fron/core/component.rb +44 -23
- data/opal/fron/core/eventable.rb +3 -3
- data/opal/fron/core/logger.rb +1 -1
- data/opal/fron/core/sheet.rb +140 -0
- data/opal/fron/core_ext.rb +1 -0
- data/opal/fron/core_ext/array.rb +23 -0
- data/opal/fron/core_ext/hash.rb +6 -6
- data/opal/fron/core_ext/kernel.rb +10 -1
- data/opal/fron/core_ext/numeric.rb +7 -0
- data/opal/fron/core_ext/time.rb +6 -0
- data/opal/fron/dom/document.rb +6 -3
- data/opal/fron/dom/element.rb +79 -19
- data/opal/fron/dom/event.rb +5 -1
- data/opal/fron/dom/modules/dimensions.rb +0 -14
- data/opal/fron/dom/modules/element_accessor.rb +25 -0
- data/opal/fron/dom/modules/events.rb +1 -1
- data/opal/fron/dom/node.rb +7 -5
- data/opal/fron/dom/style.rb +0 -2
- data/opal/fron/dom/window.rb +14 -0
- data/opal/fron/event_mock.rb +24 -6
- data/opal/fron/js/scroll_into_view_if_needed.js +27 -0
- data/opal/fron/js/syntetic_event.js +20 -13
- data/opal/fron/request/request.rb +21 -19
- data/opal/fron/request/response.rb +1 -1
- data/opal/fron/storage.rb +2 -0
- data/opal/fron/storage/local_storage.rb +3 -45
- data/opal/fron/storage/session_storage.rb +12 -0
- data/opal/fron/storage/store.rb +54 -0
- data/opal/fron/utils/drag.rb +21 -18
- data/opal/fron/utils/keyboard.rb +14 -12
- data/opal/fron/utils/point.rb +12 -4
- data/opal/fron/utils/render_proc.rb +6 -2
- data/spec/core-ext/array_spec.rb +10 -2
- data/spec/core-ext/numeric_spec.rb +6 -0
- data/spec/core/behaviors/style_spec.rb +51 -0
- data/spec/core/component_inheritance_spec.rb +10 -15
- data/spec/core/component_spec.rb +10 -15
- data/spec/dom/element_spec.rb +12 -1
- data/spec/dom/modules/classlist_spec.rb +8 -9
- data/spec/dom/modules/dimensions_spec.rb +2 -1
- data/spec/dom/modules/events_spec.rb +42 -31
- data/spec/dom/style_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -1
- data/spec/utils/drag_spec.rb +2 -2
- data/spec/utils/keyboard_spec.rb +4 -1
- data/website/application.rb +4 -0
- data/website/config.ru +30 -0
- data/website/examples/content_editable.rb +29 -0
- data/website/examples/converter.rb +49 -0
- data/website/examples/icon_button.rb +20 -0
- data/website/examples/image_paragraph.rb +33 -0
- data/website/examples/my_blue_box.rb +9 -0
- data/website/examples/my_box.rb +9 -0
- data/website/examples/my_button.rb +27 -0
- data/website/examples/my_green_box.rb +14 -0
- data/website/examples/source_reader.rb +32 -0
- data/website/examples/text_area.rb +42 -0
- data/website/pages/components.md.erb +16 -0
- data/website/pages/components/composition.md.erb +9 -0
- data/website/pages/components/events.md.erb +20 -0
- data/website/pages/components/inheritance.md.erb +19 -0
- data/website/pages/components/routes.md.erb +49 -0
- data/website/pages/components/styles.md.erb +38 -0
- data/website/pages/getting-started.md +8 -0
- data/website/pages/home.md +4 -0
- data/website/pages/intro.md +30 -0
- data/website/pages/utilities.md +10 -0
- data/website/pages/utilities/local-storage.md.erb +16 -0
- data/website/pages/utilities/request.md.erb +12 -0
- data/website/setup.rb +162 -0
- data/website/vendor/highlight.js +2 -0
- data/website/vendor/highlight.ruby.js +1 -0
- data/website/vendor/marked.min.js +6 -0
- metadata +43 -7
data/spec/dom/element_spec.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
67
|
+
element['class'].should eq nil
|
69
68
|
end
|
70
69
|
end
|
71
70
|
end
|
@@ -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
|
-
|
7
|
+
it 'should register for event' do
|
8
|
+
promise = Promise.new
|
9
9
|
listener = element.on 'click' do
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
24
|
+
it 'should register for event' do
|
25
|
+
promise = Promise.new
|
24
26
|
listener = element.on! 'click' do
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
44
|
+
element.instance_variable_get('@listeners')[:click]
|
45
|
+
.include?(listener).should eq true
|
42
46
|
element.off 'click', listener
|
43
|
-
|
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
|
-
|
55
|
+
element.instance_variable_get('@listeners')[:click]
|
56
|
+
.include?(listener).should eq true
|
51
57
|
element.off 'click'
|
52
|
-
|
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
|
-
|
66
|
+
element.instance_variable_get('@listeners')[:click]
|
67
|
+
.include?(listener).should eq true
|
60
68
|
element.off
|
61
|
-
|
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
|
-
|
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
|
-
|
70
|
-
|
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
|
-
|
88
|
+
it 'should trigger the event' do
|
89
|
+
promise = Promise.new
|
79
90
|
element.on 'click' do
|
80
|
-
|
81
|
-
|
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
|
data/spec/dom/style_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
data/spec/utils/drag_spec.rb
CHANGED
@@ -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(
|
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 }
|
data/spec/utils/keyboard_spec.rb
CHANGED
@@ -7,7 +7,10 @@ class TestKeyboard < Fron::Keyboard
|
|
7
7
|
end
|
8
8
|
|
9
9
|
describe TestKeyboard do
|
10
|
-
let(:event) {
|
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
|
data/website/config.ru
ADDED
@@ -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
|