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/opal/fron/storage.rb
CHANGED
@@ -2,52 +2,10 @@ module Fron
|
|
2
2
|
module Storage
|
3
3
|
# Local Storage wrapper and adapter
|
4
4
|
module LocalStorage
|
5
|
-
|
6
|
-
#
|
7
|
-
# @param key [String] The key
|
8
|
-
#
|
9
|
-
# @return [Object] The value
|
10
|
-
def self.get(key)
|
11
|
-
value = `window.localStorage.getItem(#{key}) || false`
|
12
|
-
value ? JSON.parse(value) : nil
|
13
|
-
end
|
14
|
-
|
15
|
-
# Sets a value to local storage with the given key
|
16
|
-
#
|
17
|
-
# @param key [String] The key
|
18
|
-
# @param data [Object] The value
|
19
|
-
def self.set(key, data)
|
20
|
-
`window.localStorage.setItem(#{key},#{data.to_json})`
|
21
|
-
end
|
22
|
-
|
23
|
-
# Removes a value from local storage with the given key
|
24
|
-
#
|
25
|
-
# @param key [String] The key
|
26
|
-
def self.remove(key)
|
27
|
-
`window.localStorage.removeItem(#{key})`
|
28
|
-
end
|
29
|
-
|
30
|
-
# Returns the all keys present in local storage
|
31
|
-
#
|
32
|
-
# @return [Array] Array of keys
|
33
|
-
def self.keys
|
34
|
-
%x{
|
35
|
-
ret = []
|
36
|
-
for (var key in localStorage){ ret.push(key) }
|
37
|
-
return ret
|
38
|
-
}
|
39
|
-
end
|
40
|
-
|
41
|
-
# Returns all values from local storage
|
42
|
-
#
|
43
|
-
# @return [Array] Array of values
|
44
|
-
def self.all
|
45
|
-
keys.map { |key| get key }
|
46
|
-
end
|
5
|
+
extend Store
|
47
6
|
|
48
|
-
|
49
|
-
|
50
|
-
`window.localStorage.clear()`
|
7
|
+
def self.store
|
8
|
+
`window.localStorage`
|
51
9
|
end
|
52
10
|
end
|
53
11
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Fron
|
2
|
+
module Storage
|
3
|
+
# Abstract wrapper and adapter for the Storage API
|
4
|
+
module Store
|
5
|
+
# Gets a value from the store with the given key
|
6
|
+
#
|
7
|
+
# @param key [String] The key
|
8
|
+
#
|
9
|
+
# @return [Object] The value
|
10
|
+
def get(key)
|
11
|
+
value = `#{store}.getItem(#{key}) || false`
|
12
|
+
value ? JSON.parse(value) : nil
|
13
|
+
end
|
14
|
+
|
15
|
+
# Sets a value to the store with the given key
|
16
|
+
#
|
17
|
+
# @param key [String] The key
|
18
|
+
# @param data [Object] The value
|
19
|
+
def set(key, data)
|
20
|
+
`#{store}.setItem(#{key},#{data.to_json})`
|
21
|
+
end
|
22
|
+
|
23
|
+
# Removes a value from the store with the given key
|
24
|
+
#
|
25
|
+
# @param key [String] The key
|
26
|
+
def remove(key)
|
27
|
+
`#{store}.removeItem(#{key})`
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the all keys present in store
|
31
|
+
#
|
32
|
+
# @return [Array] Array of keys
|
33
|
+
def keys
|
34
|
+
%x{
|
35
|
+
ret = []
|
36
|
+
for (var key in #{store}){ ret.push(key) }
|
37
|
+
return ret
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns all values from the store
|
42
|
+
#
|
43
|
+
# @return [Array] Array of values
|
44
|
+
def all
|
45
|
+
keys.map { |key| get key }
|
46
|
+
end
|
47
|
+
|
48
|
+
# Clears the store, removeing all values
|
49
|
+
def clear
|
50
|
+
`#{store}.clear()`
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/opal/fron/utils/drag.rb
CHANGED
@@ -12,29 +12,30 @@ module Fron
|
|
12
12
|
# @return [DOM::Element] The documents body
|
13
13
|
attr_reader :body
|
14
14
|
|
15
|
-
IS_TOUCH =
|
16
|
-
|
17
|
-
if IS_TOUCH
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
15
|
+
IS_TOUCH = false
|
16
|
+
|
17
|
+
EVENTS = if IS_TOUCH
|
18
|
+
{
|
19
|
+
down: 'touchstart',
|
20
|
+
move: 'touchmove',
|
21
|
+
up: 'touchend'
|
22
|
+
}
|
23
|
+
else
|
24
|
+
{
|
25
|
+
down: 'mousedown',
|
26
|
+
move: 'mousemove',
|
27
|
+
up: 'mouseup'
|
28
|
+
}
|
29
|
+
end
|
30
30
|
|
31
31
|
# Creates a new drag instance.
|
32
32
|
#
|
33
33
|
# @param base [DOM::Element] The element to monitor
|
34
|
-
def initialize(base)
|
34
|
+
def initialize(base, start_distance = 7)
|
35
35
|
reset
|
36
36
|
@base = base
|
37
37
|
@body = DOM::Document.body
|
38
|
+
@start_distance = start_distance
|
38
39
|
|
39
40
|
@base.on EVENTS[:down] do |event| start(event) end
|
40
41
|
end
|
@@ -66,6 +67,8 @@ module Fron
|
|
66
67
|
@up_method = @body.on! EVENTS[:up] do |evt| up(evt) end
|
67
68
|
|
68
69
|
request_animation_frame do move end
|
70
|
+
|
71
|
+
pos(event) if @start_distance == 0
|
69
72
|
end
|
70
73
|
|
71
74
|
# Runs when the pointer moves starts.
|
@@ -73,7 +76,7 @@ module Fron
|
|
73
76
|
# @param event [Event] The event
|
74
77
|
def pos(event)
|
75
78
|
@position = position(event)
|
76
|
-
if diff.distance
|
79
|
+
if diff.distance >= @start_distance.to_i && !@started
|
77
80
|
@started = true
|
78
81
|
trigger 'start', @target
|
79
82
|
end
|
@@ -128,7 +131,7 @@ module Fron
|
|
128
131
|
if IS_TOUCH && event.touches
|
129
132
|
Point.new `#{event.touches}[0].pageX`, `#{event.touches}[0].pageY`
|
130
133
|
else
|
131
|
-
Point.new event.
|
134
|
+
Point.new event.page_x, event.page_y
|
132
135
|
end
|
133
136
|
end
|
134
137
|
end
|
data/opal/fron/utils/keyboard.rb
CHANGED
@@ -39,11 +39,8 @@ module Fron
|
|
39
39
|
# @param event [DOM::Event] The event
|
40
40
|
def keydown(event)
|
41
41
|
return if DOM::Document.active_element
|
42
|
-
|
43
|
-
combo
|
44
|
-
combo << 'shift' if event.shift?
|
45
|
-
combo << 'alt' if event.alt?
|
46
|
-
combo.uniq!
|
42
|
+
|
43
|
+
combo = Keyboard.calculate_shortcut event
|
47
44
|
|
48
45
|
self.class.shortcuts.each do |shortcut|
|
49
46
|
next unless shortcut[:parts].sort == combo.sort
|
@@ -53,18 +50,23 @@ module Fron
|
|
53
50
|
end
|
54
51
|
end
|
55
52
|
|
53
|
+
def self.calculate_shortcut(event)
|
54
|
+
combo = [event.key]
|
55
|
+
combo << 'ctrl' if event.ctrl?
|
56
|
+
combo << 'shift' if event.shift?
|
57
|
+
combo << 'alt' if event.alt?
|
58
|
+
combo << 'meta' if event.meta?
|
59
|
+
combo.uniq
|
60
|
+
end
|
61
|
+
|
56
62
|
# Handles the shortcut.
|
57
63
|
#
|
58
64
|
# @param shortcut [Hash] The shortcut
|
59
65
|
def handle_shortcut(shortcut)
|
60
66
|
action = shortcut[:action]
|
61
|
-
if shortcut[:block]
|
62
|
-
|
63
|
-
|
64
|
-
send action
|
65
|
-
else
|
66
|
-
warn self.class.name + " - shortcut #{shortcut[:parts].join('+')}:#{action} is not implemented!"
|
67
|
-
end
|
67
|
+
return instance_exec(&shortcut[:block]) if shortcut[:block]
|
68
|
+
return send(action) if respond_to? action
|
69
|
+
warn self.class.name + " - shortcut #{shortcut[:parts].join('+')}:#{action} is not implemented!"
|
68
70
|
end
|
69
71
|
end
|
70
72
|
end
|
data/opal/fron/utils/point.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
# rubocop:disable VariableName
|
2
|
-
require 'math'
|
3
|
-
|
4
1
|
module Fron
|
5
2
|
# Simple class for point with x and y coordinates.
|
6
3
|
class Point
|
@@ -21,7 +18,8 @@ module Fron
|
|
21
18
|
# @param x [Float] The x coordiante
|
22
19
|
# @param y [Float] The y coordiante
|
23
20
|
def initialize(x = 0, y = 0)
|
24
|
-
@x
|
21
|
+
@x = x
|
22
|
+
@y = y
|
25
23
|
end
|
26
24
|
|
27
25
|
# Returns the difference from an other point.
|
@@ -74,5 +72,15 @@ module Fron
|
|
74
72
|
def to_s
|
75
73
|
"[#{x}, #{y}]"
|
76
74
|
end
|
75
|
+
|
76
|
+
def clamp(width, height)
|
77
|
+
@x = @x.clamp(0, width)
|
78
|
+
@y = @y.clamp(0, height)
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_h
|
83
|
+
{ x: x, y: y }
|
84
|
+
end
|
77
85
|
end
|
78
86
|
end
|
@@ -6,10 +6,11 @@ module Fron
|
|
6
6
|
#
|
7
7
|
# @param method [Method] The method
|
8
8
|
# @param verbose [Boolean] Whether or not to log render time
|
9
|
-
def initialize(method, verbose)
|
9
|
+
def initialize(method, verbose, message)
|
10
10
|
@running = false
|
11
11
|
@method = method
|
12
12
|
@verbose = verbose
|
13
|
+
@message = message
|
13
14
|
end
|
14
15
|
|
15
16
|
# Runs the proc
|
@@ -19,7 +20,10 @@ module Fron
|
|
19
20
|
request_animation_frame do
|
20
21
|
time = Time.now
|
21
22
|
@method.call
|
22
|
-
|
23
|
+
if @verbose
|
24
|
+
message = @message || "Rendered #{@method.owner}"
|
25
|
+
logger.info "[#{(Time.now - time) * 1000}ms] #{message}"
|
26
|
+
end
|
23
27
|
@running = false
|
24
28
|
end
|
25
29
|
end
|
data/spec/core-ext/array_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Array do
|
4
|
-
subject { %w(a b) }
|
4
|
+
subject { %w(a b a) }
|
5
5
|
|
6
6
|
describe '#reverse_each_with_index' do
|
7
7
|
it 'should run in reverse' do
|
@@ -9,7 +9,15 @@ describe Array do
|
|
9
9
|
subject.reverse_each_with_index do |item, index|
|
10
10
|
array << [item, index]
|
11
11
|
end
|
12
|
-
array.should eq [['b', 1], ['a', 0]]
|
12
|
+
array.should eq [['a', 2], ['b', 1], ['a', 0]]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#sort_by!' do
|
17
|
+
it 'should sort the array in place' do
|
18
|
+
result = subject.sort_by! { |item| item }
|
19
|
+
result.should eq subject
|
20
|
+
subject.should eq %w(a a b)
|
13
21
|
end
|
14
22
|
end
|
15
23
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Test Component
|
4
|
+
class StyleTest < Fron::Component
|
5
|
+
tag 'style-test'
|
6
|
+
|
7
|
+
stylesheet 'http://test.com/index.css'
|
8
|
+
|
9
|
+
keyframes 'test', from: { color: :red },
|
10
|
+
to: { color: :blue }
|
11
|
+
|
12
|
+
style background: :red,
|
13
|
+
img: {
|
14
|
+
width: 200.px
|
15
|
+
},
|
16
|
+
'&:hover' => {
|
17
|
+
color: :blue
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
describe StyleTest do
|
22
|
+
let(:style) { Fron::Sheet.render }
|
23
|
+
|
24
|
+
before do
|
25
|
+
subject
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should create style tag' do
|
29
|
+
style.should_not be_nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should set css for component' do
|
33
|
+
style.should match('style-test')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should set css for sub rulest' do
|
37
|
+
style.should match('style-test img')
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should set css for hover' do
|
41
|
+
style.should match('style-test:hover')
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should create keyframes rule' do
|
45
|
+
style.should match('@keyframes test')
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should create styleheet link tag' do
|
49
|
+
style.should match('test.com')
|
50
|
+
end
|
51
|
+
end
|
@@ -26,28 +26,23 @@ end
|
|
26
26
|
describe SuperComponent do
|
27
27
|
subject { described_class }
|
28
28
|
|
29
|
-
let(:
|
29
|
+
let(:registry) { subject.instance_variable_get('@registry') }
|
30
30
|
|
31
|
-
it 'should inherit
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
it 'should inherit registry in order' do
|
32
|
+
registry.should_not be nil
|
33
|
+
registry[0][:args].should eq [:text, 'text']
|
34
|
+
registry[2][:args].should eq [:title, 'title']
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
describe InheritedComponent do
|
39
39
|
subject { described_class }
|
40
40
|
|
41
|
-
let(:
|
42
|
-
let(:events) { subject.instance_variable_get('@on') }
|
41
|
+
let(:registry) { subject.instance_variable_get('@registry') }
|
43
42
|
|
44
|
-
it 'should inherit
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
it 'should inherit events' do
|
50
|
-
events.should_not be nil
|
51
|
-
events[0].should eq [:click, :render]
|
43
|
+
it 'should inherit registry' do
|
44
|
+
registry.should_not be nil
|
45
|
+
registry[0][:args].should eq [:text, 'text']
|
46
|
+
registry[1][:args].should eq [:click, :render]
|
52
47
|
end
|
53
48
|
end
|
data/spec/core/component_spec.rb
CHANGED
@@ -10,11 +10,10 @@ class TestComponent < Fron::Component
|
|
10
10
|
end
|
11
11
|
|
12
12
|
describe Fron::Component do
|
13
|
-
subject
|
13
|
+
subject { TestComponent.new }
|
14
14
|
|
15
15
|
let(:listeners) { subject.instance_variable_get '@listeners' }
|
16
|
-
let(:
|
17
|
-
let(:events) { subject.instance_variable_get('@on') }
|
16
|
+
let(:registry) { subject.instance_variable_get('@registry') }
|
18
17
|
|
19
18
|
describe 'DSL' do
|
20
19
|
subject { TestComponent }
|
@@ -34,22 +33,18 @@ describe Fron::Component do
|
|
34
33
|
end
|
35
34
|
|
36
35
|
describe '#on' do
|
37
|
-
it 'should
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
it 'should push event into the events array' do
|
43
|
-
subject.on :click, :test
|
44
|
-
events.length.should be 2
|
36
|
+
it 'should add to registry' do
|
37
|
+
expect {
|
38
|
+
subject.on :click, :test
|
39
|
+
}.to change { registry.count }.by 1
|
45
40
|
end
|
46
41
|
end
|
47
42
|
|
48
43
|
describe '#component' do
|
49
44
|
it 'should create components array' do
|
50
|
-
|
51
|
-
|
52
|
-
|
45
|
+
expect {
|
46
|
+
subject.component :test, 'test'
|
47
|
+
}.to change { registry.count }.by 1
|
53
48
|
end
|
54
49
|
|
55
50
|
it 'should create attr_reader for component' do
|
@@ -65,7 +60,7 @@ describe Fron::Component do
|
|
65
60
|
end
|
66
61
|
|
67
62
|
it 'should apply events' do
|
68
|
-
listeners[:click].length.should eq
|
63
|
+
listeners[:click].length.should eq 1
|
69
64
|
end
|
70
65
|
|
71
66
|
it 'should create components' do
|