fron 0.1.4 → 0.2.0rc1

Sign up to get free protection for your applications and to get access to all the features.
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