fron 0.1.4 → 0.2.0rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.reek +11 -0
- data/.rubocop.yml +54 -0
- data/.travis.yml +11 -0
- data/.yardopts +4 -0
- data/Changelog.md +7 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +106 -15
- data/Rakefile +19 -15
- data/Readme.md +23 -0
- data/fron.gemspec +2 -2
- data/lib/fron/version.rb +2 -1
- data/opal/fron.rb +5 -5
- data/opal/fron/core.rb +3 -10
- data/opal/fron/core/behaviors/components.rb +42 -0
- data/opal/fron/core/behaviors/events.rb +27 -0
- data/opal/fron/core/behaviors/routes.rb +59 -0
- data/opal/fron/core/component.rb +64 -90
- data/opal/fron/core/eventable.rb +18 -0
- data/opal/fron/core/logger.rb +10 -1
- data/opal/fron/core_ext.rb +9 -0
- data/opal/fron/core_ext/array.rb +12 -0
- data/opal/fron/core_ext/date.rb +57 -0
- data/opal/fron/core_ext/hash.rb +52 -0
- data/opal/fron/core_ext/kernel.rb +57 -0
- data/opal/fron/core_ext/nil.rb +7 -0
- data/opal/fron/core_ext/numeric.rb +19 -0
- data/opal/fron/core_ext/object.rb +11 -0
- data/opal/fron/core_ext/proc.rb +19 -0
- data/opal/fron/{core-ext → core_ext}/string.rb +4 -0
- data/opal/fron/dom.rb +15 -13
- data/opal/fron/dom/document.rb +22 -6
- data/opal/fron/dom/element.rb +105 -67
- data/opal/fron/dom/event.rb +110 -40
- data/opal/fron/dom/{file-reader.rb → file_reader.rb} +6 -1
- data/opal/fron/dom/fragment.rb +2 -0
- data/opal/fron/dom/modules/attributes.rb +43 -0
- data/opal/fron/dom/modules/classlist.rb +26 -13
- data/opal/fron/dom/modules/dimensions.rb +79 -9
- data/opal/fron/dom/modules/element_accessor.rb +35 -0
- data/opal/fron/dom/modules/events.rb +67 -20
- data/opal/fron/dom/node.rb +98 -39
- data/opal/fron/dom/nodelist.rb +9 -2
- data/opal/fron/dom/style.rb +23 -2
- data/opal/fron/dom/text.rb +4 -0
- data/opal/fron/dom/window.rb +31 -2
- data/opal/fron/event_mock.rb +54 -0
- data/opal/fron/js/syntetic_event.js +16 -0
- data/opal/fron/request.rb +2 -2
- data/opal/fron/request/request.rb +77 -14
- data/opal/fron/request/response.rb +33 -6
- data/opal/fron/storage.rb +1 -1
- data/opal/fron/storage/local_storage.rb +54 -0
- data/opal/fron/utils/drag.rb +135 -0
- data/opal/fron/utils/keyboard.rb +70 -0
- data/opal/fron/utils/point.rb +78 -0
- data/opal/fron/utils/render_proc.rb +27 -0
- data/spec/core-ext/array_spec.rb +15 -0
- data/spec/core-ext/date_spec.rb +54 -0
- data/spec/core-ext/hash_spec.rb +18 -2
- data/spec/core-ext/kernel_spec.rb +57 -0
- data/spec/core-ext/nil_spec.rb +9 -0
- data/spec/core-ext/numeric_spec.rb +25 -0
- data/spec/core-ext/proc_spec.rb +15 -0
- data/spec/core-ext/string_spec.rb +11 -0
- data/spec/core/behaviors/events_spec.rb +25 -0
- data/spec/core/behaviors/routes_spec.rb +59 -0
- data/spec/core/component_inheritance_spec.rb +26 -16
- data/spec/core/component_spec.rb +25 -29
- data/spec/core/eventable_spec.rb +19 -19
- data/spec/core/logger_spec.rb +5 -6
- data/spec/dom/document_spec.rb +4 -5
- data/spec/dom/element_spec.rb +106 -15
- data/spec/dom/event_spec.rb +101 -61
- data/spec/dom/file_reader_spec.rb +11 -0
- data/spec/dom/fragment_spec.rb +3 -4
- data/spec/dom/instance_retaining_spec.rb +58 -0
- data/spec/dom/modules/classlist_spec.rb +18 -19
- data/spec/dom/modules/dimensions_spec.rb +87 -22
- data/spec/dom/modules/events_spec.rb +22 -8
- data/spec/dom/node_spec.rb +25 -17
- data/spec/dom/nodelist_spec.rb +2 -3
- data/spec/dom/style_spec.rb +6 -5
- data/spec/dom/text_spec.rb +4 -3
- data/spec/dom/window_spec.rb +24 -9
- data/spec/js/mocks.js +14 -0
- data/spec/request/request_spec.rb +34 -15
- data/spec/request/response_spec.rb +9 -10
- data/spec/spec_helper.rb +11 -0
- data/spec/storage/{local-storage_spec.rb → local_storage_spec.rb} +6 -7
- data/spec/utils/drag_spec.rb +136 -0
- data/spec/utils/keyboard_spec.rb +75 -0
- data/spec/utils/point_spec.rb +55 -0
- data/spec/utils/render_proc_spec.rb +18 -0
- metadata +58 -36
- data/docs/application.md +0 -7
- data/docs/configuration.md +0 -29
- data/docs/controllers.md +0 -35
- data/docs/routing.md +0 -63
- data/opal/fron/core-ext.rb +0 -5
- data/opal/fron/core-ext/hash.rb +0 -31
- data/opal/fron/core-ext/kernel.rb +0 -10
- data/opal/fron/core-ext/numeric.rb +0 -9
- data/opal/fron/core-ext/proc.rb +0 -9
- data/opal/fron/core/adapters/local.rb +0 -43
- data/opal/fron/core/adapters/rails.rb +0 -65
- data/opal/fron/core/application.rb +0 -42
- data/opal/fron/core/configuration.rb +0 -29
- data/opal/fron/core/controller.rb +0 -41
- data/opal/fron/core/model.rb +0 -90
- data/opal/fron/core/router.rb +0 -86
- data/opal/fron/storage/local-storage.rb +0 -34
- data/spec/core/adapter/local_spec.rb +0 -65
- data/spec/core/adapter/rails_spec.rb +0 -77
- data/spec/core/application_spec.rb +0 -35
- data/spec/core/configuration_spec.rb +0 -20
- data/spec/core/controlller_spec.rb +0 -68
- data/spec/core/model_spec.rb +0 -125
- data/spec/core/router_spec.rb +0 -124
data/opal/fron/dom/nodelist.rb
CHANGED
@@ -1,14 +1,21 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
|
3
3
|
module DOM
|
4
|
+
# Node List
|
4
5
|
class NodeList
|
5
6
|
include Enumerable
|
6
7
|
extend Forwardable
|
7
8
|
|
8
|
-
|
9
|
+
# @return [Array] The nodes
|
10
|
+
attr_reader :nodes
|
9
11
|
|
12
|
+
def_delegators :@nodes, :length, :include?, :each, :index, :[], :to_a, :last, :empty?
|
13
|
+
|
14
|
+
# Initializes the node list
|
15
|
+
#
|
16
|
+
# @param nodes [Array] Array of nodes
|
10
17
|
def initialize(nodes)
|
11
|
-
@nodes = nodes.map { |node| DOM::
|
18
|
+
@nodes = nodes.map { |node| DOM::Element.from_node node }
|
12
19
|
end
|
13
20
|
end
|
14
21
|
end
|
data/opal/fron/dom/style.rb
CHANGED
@@ -1,10 +1,22 @@
|
|
1
|
+
# rubocop:disable MethodName
|
2
|
+
|
1
3
|
module DOM
|
4
|
+
# Style
|
2
5
|
class Style
|
6
|
+
# Initializes the style
|
7
|
+
#
|
8
|
+
# @param el [DOM::Element] The element
|
3
9
|
def initialize(el)
|
4
10
|
@el = el
|
5
11
|
end
|
6
12
|
|
7
|
-
|
13
|
+
# Sets or gets a given CSS property
|
14
|
+
#
|
15
|
+
# @param name [String] The property
|
16
|
+
# @param value [String] The value
|
17
|
+
#
|
18
|
+
# @return [String] The value of the property
|
19
|
+
def method_missing(name, value)
|
8
20
|
if name =~ /\=$/
|
9
21
|
self[name[0..-2]] = value
|
10
22
|
else
|
@@ -12,11 +24,20 @@ module DOM
|
|
12
24
|
end
|
13
25
|
end
|
14
26
|
|
27
|
+
# Gets a CSS property value
|
28
|
+
#
|
29
|
+
# @param prop [String] The property
|
30
|
+
#
|
31
|
+
# @return [String] The value of the property
|
15
32
|
def [](prop)
|
16
33
|
`#{@el}.style[#{prop}]`
|
17
34
|
end
|
18
35
|
|
19
|
-
|
36
|
+
# Sets the given CSS property with the given value
|
37
|
+
#
|
38
|
+
# @param prop [String] The property
|
39
|
+
# @param value [String] The value
|
40
|
+
def []=(prop, value)
|
20
41
|
`#{@el}.style[#{prop}] = #{value}`
|
21
42
|
end
|
22
43
|
end
|
data/opal/fron/dom/text.rb
CHANGED
data/opal/fron/dom/window.rb
CHANGED
@@ -1,21 +1,50 @@
|
|
1
1
|
module DOM
|
2
|
+
# Window
|
2
3
|
module Window
|
3
4
|
extend Events
|
4
5
|
@el = `window`
|
5
6
|
|
7
|
+
# Sets the url via pushState
|
8
|
+
#
|
9
|
+
# @param url [String] The url
|
10
|
+
def self.state=(url)
|
11
|
+
return if url == state
|
12
|
+
`window.history.pushState({},'',#{url})`
|
13
|
+
timeout { trigger 'popstate' }
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns the locations pathname as state
|
17
|
+
#
|
18
|
+
# @return [String] The pathname
|
19
|
+
def self.state
|
20
|
+
`window.location.pathname`
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the locations hash
|
24
|
+
#
|
25
|
+
# @return [String] The hash
|
6
26
|
def self.hash
|
7
27
|
`window.location.hash.slice(1)`
|
8
28
|
end
|
9
29
|
|
30
|
+
# Sets the locations hash with the given value
|
31
|
+
#
|
32
|
+
# @param value [String] The value
|
10
33
|
def self.hash=(value)
|
11
34
|
`window.location.hash = #{value}`
|
12
35
|
end
|
13
36
|
|
14
|
-
|
37
|
+
# Returns the Y scroll position of the window
|
38
|
+
#
|
39
|
+
# @return [Numeric] The position
|
40
|
+
def self.scroll_y
|
15
41
|
`window.scrollY || document.documentElement.scrollTop`
|
16
42
|
end
|
17
43
|
|
18
|
-
|
44
|
+
# Returns the X scroll position of the window
|
45
|
+
#
|
46
|
+
# @return [Numeric] The position
|
47
|
+
def self.scroll_x
|
19
48
|
`window.scrollX || document.documentElement.scrollTop`
|
20
49
|
end
|
21
50
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'fron/js/syntetic_event'
|
2
|
+
|
3
|
+
# Event Mock module for mocking events
|
4
|
+
module EventMock
|
5
|
+
class << self
|
6
|
+
# Sets / gets the whether or not
|
7
|
+
# log event triggers
|
8
|
+
#
|
9
|
+
# @param value [Boolean] The verbosity
|
10
|
+
# @return [Boolean] The verbosity
|
11
|
+
attr_accessor :verbose
|
12
|
+
|
13
|
+
# Triggers a syntetic event.
|
14
|
+
#
|
15
|
+
# @param element [DOM::Element] The element
|
16
|
+
# @param type [String] Event type
|
17
|
+
# @param data [Hash] The data for the event
|
18
|
+
def trigger_event(element, type, data = {})
|
19
|
+
event = `new SynteticEvent(#{element.instance_variable_get('@el')}, #{data.to_n})`
|
20
|
+
dispath_event element, event, type
|
21
|
+
end
|
22
|
+
|
23
|
+
# Dispatches a sytetic event
|
24
|
+
#
|
25
|
+
# @param element [DOM::Element] The element
|
26
|
+
# @param event [SynteticEvent] The event
|
27
|
+
# @param type [String] Event type
|
28
|
+
#
|
29
|
+
# @return [type] [description]
|
30
|
+
def dispath_event(element, event, type)
|
31
|
+
if `#{element.listeners} || Opal.nil`
|
32
|
+
element.listeners[type].to_a.each do |method|
|
33
|
+
break unless `#{event}.immediatePropagate`
|
34
|
+
method.call event
|
35
|
+
end
|
36
|
+
end
|
37
|
+
return unless `#{event}.propagate`
|
38
|
+
return unless element.parent
|
39
|
+
dispath_event element.parent, event, type
|
40
|
+
end
|
41
|
+
|
42
|
+
# Mocks triggers on DOM::Events
|
43
|
+
def mock_events
|
44
|
+
DOM::Events.alias_method :old_trigger, :trigger
|
45
|
+
DOM::Events.define_method :trigger do |type, data = {}|
|
46
|
+
puts "Triggered syntetic event \"#{type}\" for \"#{path}\"" if EventMock.verbose
|
47
|
+
EventMock.trigger_event self, type, data
|
48
|
+
end
|
49
|
+
yield
|
50
|
+
ensure
|
51
|
+
DOM::Events.alias_method :trigger, :old_trigger
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
SynteticEvent = function(target, data){
|
2
|
+
this.target = target
|
3
|
+
this.defaultPrevented = false
|
4
|
+
this.immediatePropagate = true
|
5
|
+
this.propagate = true
|
6
|
+
this.data = data
|
7
|
+
}
|
8
|
+
SynteticEvent.prototype.stopImmediatePropagation = function(){
|
9
|
+
this.immediatePropagate = false
|
10
|
+
}
|
11
|
+
SynteticEvent.prototype.stopPropagation = function(){
|
12
|
+
this.propagate = false
|
13
|
+
}
|
14
|
+
SynteticEvent.prototype.preventDefault = function(){
|
15
|
+
this.defaultPrevented = true
|
16
|
+
}
|
data/opal/fron/request.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'fron/request/response'
|
2
|
+
require 'fron/request/request'
|
@@ -1,9 +1,29 @@
|
|
1
1
|
require 'json'
|
2
2
|
|
3
3
|
module Fron
|
4
|
+
# Request
|
4
5
|
class Request
|
5
|
-
|
6
|
+
extend Eventable
|
7
|
+
extend Forwardable
|
6
8
|
|
9
|
+
# Sets / gets the URL
|
10
|
+
#
|
11
|
+
# @param value [String] The URL
|
12
|
+
# @return [String] The URL
|
13
|
+
attr_accessor :url
|
14
|
+
|
15
|
+
# Sets / gets the headers for the request
|
16
|
+
#
|
17
|
+
# @param value [Hash] The headers
|
18
|
+
# @return [Hash] The headers
|
19
|
+
attr_accessor :headers
|
20
|
+
|
21
|
+
def_delegators :class, :trigger
|
22
|
+
|
23
|
+
# Initialies the request
|
24
|
+
#
|
25
|
+
# @param url [String] The url
|
26
|
+
# @param headers [Hash] The headers
|
7
27
|
def initialize(url, headers = {})
|
8
28
|
@url = url
|
9
29
|
@headers = headers
|
@@ -12,50 +32,93 @@ module Fron
|
|
12
32
|
self
|
13
33
|
end
|
14
34
|
|
15
|
-
|
16
|
-
|
35
|
+
# Runs a request
|
36
|
+
#
|
37
|
+
# @param method [String] The method
|
38
|
+
# @param data [Hash] The data
|
39
|
+
#
|
40
|
+
# @yieldparam response [Response] The response
|
41
|
+
def request(method = 'GET', data = nil, &callback)
|
42
|
+
if ready_state == 0 || ready_state == 4
|
17
43
|
@callback = callback
|
18
|
-
if method.upcase ==
|
19
|
-
|
20
|
-
|
21
|
-
|
44
|
+
if method.upcase == 'UPLOAD'
|
45
|
+
send 'POST', @url, data.to_form_data
|
46
|
+
elsif method.upcase == 'GET' && data
|
47
|
+
send method, @url + '?' + data.to_query_string.to_s, nil
|
22
48
|
else
|
23
|
-
|
24
|
-
|
25
|
-
`#{@request}.send(#{data.to_json if data})`
|
49
|
+
data = data.to_json if data
|
50
|
+
send method, @url, data
|
26
51
|
end
|
52
|
+
trigger :loading
|
27
53
|
else
|
28
|
-
|
54
|
+
fail 'The request is already running!'
|
29
55
|
end
|
30
56
|
end
|
31
57
|
|
58
|
+
# Runs a GET request
|
59
|
+
#
|
60
|
+
# @param data [Hash] The data
|
61
|
+
#
|
62
|
+
# @yieldparam response [Response] The response
|
32
63
|
def get(data, &callback)
|
33
64
|
request 'GET', data, &callback
|
34
65
|
end
|
35
66
|
|
67
|
+
# Runs a POST request
|
68
|
+
#
|
69
|
+
# @param data [Hash] The data
|
70
|
+
#
|
71
|
+
# @yieldparam response [Response] The response
|
36
72
|
def post(data, &callback)
|
37
73
|
request 'POST', data, &callback
|
38
74
|
end
|
39
75
|
|
76
|
+
# Runs a PUT request
|
77
|
+
#
|
78
|
+
# @param data [Hash] The data
|
79
|
+
#
|
80
|
+
# @yieldparam response [Response] The response
|
40
81
|
def put(data, &callback)
|
41
82
|
request 'PUT', data, &callback
|
42
83
|
end
|
43
84
|
|
44
85
|
private
|
45
|
-
|
46
|
-
|
86
|
+
|
87
|
+
# Sends the given data to the given URL
|
88
|
+
# with the given method
|
89
|
+
#
|
90
|
+
# @param method [String] The method
|
91
|
+
# @param url [String] The URL
|
92
|
+
# @param data [*] The data
|
93
|
+
def send(method, url, data)
|
94
|
+
`#{@request}.open(#{method}, #{url})`
|
95
|
+
`#{@request}.withCredentials = true`
|
96
|
+
set_headers
|
97
|
+
`#{@request}.send(#{data})`
|
98
|
+
end
|
99
|
+
|
100
|
+
# Sets the headers
|
101
|
+
def set_headers
|
102
|
+
@headers.each_pair do |header, value|
|
47
103
|
`#{@request}.setRequestHeader(#{header},#{value})`
|
48
104
|
end
|
49
105
|
end
|
50
106
|
|
107
|
+
# Returns the ready state of the request
|
108
|
+
#
|
109
|
+
# @return [Numeric] The ready state
|
51
110
|
def ready_state
|
52
111
|
`#{@request}.readyState`
|
53
112
|
end
|
54
113
|
|
114
|
+
# Handles the hash change
|
55
115
|
def handle_state_change
|
56
|
-
|
116
|
+
return unless ready_state == 4
|
117
|
+
begin
|
57
118
|
response = Response.new `#{@request}.status`, `#{@request}.response`, `#{@request}.getAllResponseHeaders()`
|
58
119
|
@callback.call response if @callback
|
120
|
+
ensure
|
121
|
+
trigger :loaded
|
59
122
|
end
|
60
123
|
end
|
61
124
|
end
|
@@ -1,7 +1,22 @@
|
|
1
1
|
module Fron
|
2
|
+
# Response
|
2
3
|
class Response
|
3
|
-
|
4
|
+
# @return [String] The response body
|
5
|
+
attr_reader :body
|
4
6
|
|
7
|
+
# @return [Hash] The response headers
|
8
|
+
attr_reader :headers
|
9
|
+
|
10
|
+
# @return [Numeric] The response status code
|
11
|
+
attr_reader :status
|
12
|
+
|
13
|
+
# Initializes the response
|
14
|
+
#
|
15
|
+
# @param status [Numeric] The status
|
16
|
+
# @param body [String] The response body
|
17
|
+
# @param headers [Hash] The headers
|
18
|
+
#
|
19
|
+
# @return [type] [description]
|
5
20
|
def initialize(status, body, headers)
|
6
21
|
@body = body
|
7
22
|
@status = status
|
@@ -13,24 +28,36 @@ module Fron
|
|
13
28
|
end
|
14
29
|
end
|
15
30
|
|
31
|
+
# Returns the content type of the response
|
32
|
+
#
|
33
|
+
# @return [String] The content type
|
16
34
|
def content_type
|
17
35
|
@headers['Content-Type']
|
18
36
|
end
|
19
37
|
|
38
|
+
# Returns whether the request was successfull
|
39
|
+
#
|
40
|
+
# @return [Boolean] True if it was false if not
|
20
41
|
def ok?
|
21
42
|
@status == 200
|
22
43
|
end
|
23
44
|
|
45
|
+
# Returns the response body as json
|
46
|
+
#
|
47
|
+
# @return [Hash] The body
|
24
48
|
def json
|
25
49
|
JSON.parse @body
|
26
50
|
end
|
27
51
|
|
52
|
+
# Returns the response body as DOM::Fragment
|
53
|
+
#
|
54
|
+
# @return [DOM::Fragment] The body
|
28
55
|
def dom
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
56
|
+
div = DOM::Element.new 'div'
|
57
|
+
div.html = @body
|
58
|
+
fragment = DOM::Fragment.new
|
59
|
+
fragment << div
|
60
|
+
fragment
|
34
61
|
end
|
35
62
|
end
|
36
63
|
end
|
data/opal/fron/storage.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require '
|
1
|
+
require 'fron/storage/local_storage'
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Fron
|
2
|
+
module Storage
|
3
|
+
# Local Storage wrapper and adapter
|
4
|
+
module LocalStorage
|
5
|
+
# Gets a value from local storage with the given key
|
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
|
47
|
+
|
48
|
+
# Clears local storage removeing all values
|
49
|
+
def self.clear
|
50
|
+
`window.localStorage.clear()`
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|