fron 0.1.4 → 0.2.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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.reek +11 -0
  4. data/.rubocop.yml +54 -0
  5. data/.travis.yml +11 -0
  6. data/.yardopts +4 -0
  7. data/Changelog.md +7 -0
  8. data/Gemfile +3 -1
  9. data/Gemfile.lock +106 -15
  10. data/Rakefile +19 -15
  11. data/Readme.md +23 -0
  12. data/fron.gemspec +2 -2
  13. data/lib/fron/version.rb +2 -1
  14. data/opal/fron.rb +5 -5
  15. data/opal/fron/core.rb +3 -10
  16. data/opal/fron/core/behaviors/components.rb +42 -0
  17. data/opal/fron/core/behaviors/events.rb +27 -0
  18. data/opal/fron/core/behaviors/routes.rb +59 -0
  19. data/opal/fron/core/component.rb +64 -90
  20. data/opal/fron/core/eventable.rb +18 -0
  21. data/opal/fron/core/logger.rb +10 -1
  22. data/opal/fron/core_ext.rb +9 -0
  23. data/opal/fron/core_ext/array.rb +12 -0
  24. data/opal/fron/core_ext/date.rb +57 -0
  25. data/opal/fron/core_ext/hash.rb +52 -0
  26. data/opal/fron/core_ext/kernel.rb +57 -0
  27. data/opal/fron/core_ext/nil.rb +7 -0
  28. data/opal/fron/core_ext/numeric.rb +19 -0
  29. data/opal/fron/core_ext/object.rb +11 -0
  30. data/opal/fron/core_ext/proc.rb +19 -0
  31. data/opal/fron/{core-ext → core_ext}/string.rb +4 -0
  32. data/opal/fron/dom.rb +15 -13
  33. data/opal/fron/dom/document.rb +22 -6
  34. data/opal/fron/dom/element.rb +105 -67
  35. data/opal/fron/dom/event.rb +110 -40
  36. data/opal/fron/dom/{file-reader.rb → file_reader.rb} +6 -1
  37. data/opal/fron/dom/fragment.rb +2 -0
  38. data/opal/fron/dom/modules/attributes.rb +43 -0
  39. data/opal/fron/dom/modules/classlist.rb +26 -13
  40. data/opal/fron/dom/modules/dimensions.rb +79 -9
  41. data/opal/fron/dom/modules/element_accessor.rb +35 -0
  42. data/opal/fron/dom/modules/events.rb +67 -20
  43. data/opal/fron/dom/node.rb +98 -39
  44. data/opal/fron/dom/nodelist.rb +9 -2
  45. data/opal/fron/dom/style.rb +23 -2
  46. data/opal/fron/dom/text.rb +4 -0
  47. data/opal/fron/dom/window.rb +31 -2
  48. data/opal/fron/event_mock.rb +54 -0
  49. data/opal/fron/js/syntetic_event.js +16 -0
  50. data/opal/fron/request.rb +2 -2
  51. data/opal/fron/request/request.rb +77 -14
  52. data/opal/fron/request/response.rb +33 -6
  53. data/opal/fron/storage.rb +1 -1
  54. data/opal/fron/storage/local_storage.rb +54 -0
  55. data/opal/fron/utils/drag.rb +135 -0
  56. data/opal/fron/utils/keyboard.rb +70 -0
  57. data/opal/fron/utils/point.rb +78 -0
  58. data/opal/fron/utils/render_proc.rb +27 -0
  59. data/spec/core-ext/array_spec.rb +15 -0
  60. data/spec/core-ext/date_spec.rb +54 -0
  61. data/spec/core-ext/hash_spec.rb +18 -2
  62. data/spec/core-ext/kernel_spec.rb +57 -0
  63. data/spec/core-ext/nil_spec.rb +9 -0
  64. data/spec/core-ext/numeric_spec.rb +25 -0
  65. data/spec/core-ext/proc_spec.rb +15 -0
  66. data/spec/core-ext/string_spec.rb +11 -0
  67. data/spec/core/behaviors/events_spec.rb +25 -0
  68. data/spec/core/behaviors/routes_spec.rb +59 -0
  69. data/spec/core/component_inheritance_spec.rb +26 -16
  70. data/spec/core/component_spec.rb +25 -29
  71. data/spec/core/eventable_spec.rb +19 -19
  72. data/spec/core/logger_spec.rb +5 -6
  73. data/spec/dom/document_spec.rb +4 -5
  74. data/spec/dom/element_spec.rb +106 -15
  75. data/spec/dom/event_spec.rb +101 -61
  76. data/spec/dom/file_reader_spec.rb +11 -0
  77. data/spec/dom/fragment_spec.rb +3 -4
  78. data/spec/dom/instance_retaining_spec.rb +58 -0
  79. data/spec/dom/modules/classlist_spec.rb +18 -19
  80. data/spec/dom/modules/dimensions_spec.rb +87 -22
  81. data/spec/dom/modules/events_spec.rb +22 -8
  82. data/spec/dom/node_spec.rb +25 -17
  83. data/spec/dom/nodelist_spec.rb +2 -3
  84. data/spec/dom/style_spec.rb +6 -5
  85. data/spec/dom/text_spec.rb +4 -3
  86. data/spec/dom/window_spec.rb +24 -9
  87. data/spec/js/mocks.js +14 -0
  88. data/spec/request/request_spec.rb +34 -15
  89. data/spec/request/response_spec.rb +9 -10
  90. data/spec/spec_helper.rb +11 -0
  91. data/spec/storage/{local-storage_spec.rb → local_storage_spec.rb} +6 -7
  92. data/spec/utils/drag_spec.rb +136 -0
  93. data/spec/utils/keyboard_spec.rb +75 -0
  94. data/spec/utils/point_spec.rb +55 -0
  95. data/spec/utils/render_proc_spec.rb +18 -0
  96. metadata +58 -36
  97. data/docs/application.md +0 -7
  98. data/docs/configuration.md +0 -29
  99. data/docs/controllers.md +0 -35
  100. data/docs/routing.md +0 -63
  101. data/opal/fron/core-ext.rb +0 -5
  102. data/opal/fron/core-ext/hash.rb +0 -31
  103. data/opal/fron/core-ext/kernel.rb +0 -10
  104. data/opal/fron/core-ext/numeric.rb +0 -9
  105. data/opal/fron/core-ext/proc.rb +0 -9
  106. data/opal/fron/core/adapters/local.rb +0 -43
  107. data/opal/fron/core/adapters/rails.rb +0 -65
  108. data/opal/fron/core/application.rb +0 -42
  109. data/opal/fron/core/configuration.rb +0 -29
  110. data/opal/fron/core/controller.rb +0 -41
  111. data/opal/fron/core/model.rb +0 -90
  112. data/opal/fron/core/router.rb +0 -86
  113. data/opal/fron/storage/local-storage.rb +0 -34
  114. data/spec/core/adapter/local_spec.rb +0 -65
  115. data/spec/core/adapter/rails_spec.rb +0 -77
  116. data/spec/core/application_spec.rb +0 -35
  117. data/spec/core/configuration_spec.rb +0 -20
  118. data/spec/core/controlller_spec.rb +0 -68
  119. data/spec/core/model_spec.rb +0 -125
  120. data/spec/core/router_spec.rb +0 -124
@@ -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
- def_delegators :@nodes, :length, :include?, :each, :index, :[]
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::NODE.new node }
18
+ @nodes = nodes.map { |node| DOM::Element.from_node node }
12
19
  end
13
20
  end
14
21
  end
@@ -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
- def method_missing(name,value)
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
- def []=(prop,value)
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
@@ -1,5 +1,9 @@
1
1
  module DOM
2
+ # Text
2
3
  class Text < NODE
4
+ # Initializes the text node with the given data
5
+ #
6
+ # @param data [String] The value of the node
3
7
  def initialize(data)
4
8
  @el = `typeof #{data} === 'string'` ? `document.createTextNode(#{data})` : data
5
9
  end
@@ -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
- def self.scrollY
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
- def self.scrollX
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
+ }
@@ -1,2 +1,2 @@
1
- require './request/response'
2
- require './request/request'
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
- attr_accessor :url, :headers
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
- def request( method = 'GET', data = nil, &callback)
16
- if ready_state == 0 or ready_state == 4
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 == "GET" && data
19
- `#{@request}.open(#{method},#{@url+"?"+data.to_query_string})`
20
- setHeaders
21
- `#{@request}.send()`
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
- `#{@request}.open(#{method},#{@url})`
24
- setHeaders
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
- raise "The request is already running!"
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
- def setHeaders
46
- @headers.each_pair do |header,value|
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
- if ready_state == 4
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
- attr_reader :body, :headers, :status
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
- d = DOM::Element.new 'div'
30
- d.html = @body
31
- f = DOM::Fragment.new()
32
- f << d
33
- f
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
@@ -1 +1 @@
1
- require './storage/local-storage'
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