fron 0.1.0 → 0.1.1

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +35 -0
  6. data/Rakefile +18 -0
  7. data/docs/configuration.md +8 -8
  8. data/lib/fron/version.rb +1 -1
  9. data/opal/fron/core.rb +1 -1
  10. data/opal/fron/core/adapters/{local-storage.rb → local.rb} +7 -6
  11. data/opal/fron/core/application.rb +13 -11
  12. data/opal/fron/core/configuration.rb +3 -4
  13. data/opal/fron/core/controller.rb +2 -2
  14. data/opal/fron/core/eventable.rb +5 -2
  15. data/opal/fron/core/logger.rb +7 -0
  16. data/opal/fron/core/model.rb +10 -8
  17. data/opal/fron/core/router.rb +1 -1
  18. data/opal/fron/dom.rb +1 -0
  19. data/opal/fron/dom/document.rb +4 -0
  20. data/opal/fron/dom/element.rb +22 -6
  21. data/opal/fron/dom/event.rb +71 -68
  22. data/opal/fron/dom/fragment.rb +1 -3
  23. data/opal/fron/dom/modules/classlist.rb +2 -2
  24. data/opal/fron/dom/modules/dimensions.rb +7 -8
  25. data/opal/fron/dom/modules/events.rb +57 -12
  26. data/opal/fron/dom/node.rb +45 -11
  27. data/opal/fron/dom/nodelist.rb +14 -0
  28. data/opal/fron/dom/style.rb +17 -15
  29. data/opal/fron/dom/text.rb +2 -4
  30. data/opal/fron/dom/window.rb +2 -3
  31. data/opal/fron/request/request.rb +17 -14
  32. data/opal/fron/storage/local-storage.rb +29 -13
  33. data/spec/core-ext/hash_spec.rb +18 -0
  34. data/spec/core/adapter/local_spec.rb +65 -0
  35. data/spec/core/adapter/rails_spec.rb +72 -0
  36. data/spec/core/application_spec.rb +35 -0
  37. data/spec/core/component_spec.rb +107 -0
  38. data/spec/core/configuration_spec.rb +20 -0
  39. data/spec/core/controlller_spec.rb +68 -0
  40. data/spec/core/eventable_spec.rb +74 -0
  41. data/spec/core/logger_spec.rb +28 -0
  42. data/spec/core/model_spec.rb +125 -0
  43. data/spec/core/router_spec.rb +127 -0
  44. data/spec/dom/document_spec.rb +41 -0
  45. data/spec/dom/element_spec.rb +164 -0
  46. data/spec/dom/event_spec.rb +121 -0
  47. data/spec/dom/fragment_spec.rb +13 -0
  48. data/spec/dom/modules/classlist_spec.rb +72 -0
  49. data/spec/dom/modules/dimensions_spec.rb +55 -0
  50. data/spec/dom/modules/events_spec.rb +73 -0
  51. data/spec/dom/node_spec.rb +189 -0
  52. data/spec/dom/nodelist_spec.rb +12 -0
  53. data/spec/dom/style_spec.rb +31 -0
  54. data/spec/dom/text_spec.rb +12 -0
  55. data/spec/dom/window_spec.rb +30 -0
  56. data/spec/request/request_spec.rb +71 -0
  57. data/spec/request/response_spec.rb +46 -0
  58. data/spec/storage/local-storage_spec.rb +58 -0
  59. metadata +36 -4
@@ -1,7 +1,5 @@
1
1
  module DOM
2
- class Fragment
3
- include Node
4
-
2
+ class Fragment < NODE
5
3
  def initialize
6
4
  @el = `document.createDocumentFragment()`
7
5
  end
@@ -16,8 +16,8 @@ module DOM
16
16
  `#{@el}.classList.contains(#{cls})`
17
17
  end
18
18
 
19
- def toggleClass(cls,value)
20
- if value
19
+ def toggleClass(cls,value = nil)
20
+ if value || (value == nil && !hasClass(cls))
21
21
  addClass cls
22
22
  else
23
23
  removeClass cls
@@ -4,34 +4,33 @@ module DOM
4
4
  module Dimensions
5
5
 
6
6
  def top
7
- clientRect[:top] + Window.scrollY
7
+ `#{clientRect}.top` + Window.scrollY
8
8
  end
9
9
 
10
10
  def left
11
- clientRect[:left] + Window.scrollX
11
+ `#{clientRect}.left` + Window.scrollX
12
12
  end
13
13
 
14
14
  def right
15
- clientRect[:right] + Window.scrollX
15
+ `#{clientRect}.right` + Window.scrollX
16
16
  end
17
17
 
18
18
  def bottom
19
- clientRect[:bottom] + Window.scrollY
19
+ `#{clientRect}.bottom` + Window.scrollY
20
20
  end
21
21
 
22
22
  def width
23
- clientRect[:width]
23
+ `#{clientRect}.width`
24
24
  end
25
25
 
26
26
  def height
27
-
28
- clientRect[:height]
27
+ `#{clientRect}.height`
29
28
  end
30
29
 
31
30
  private
32
31
 
33
32
  def clientRect
34
- Hash.new `JSON.parse(JSON.stringify(#{@el}.getBoundingClientRect()))`
33
+ `#{@el}.getBoundingClientRect()`
35
34
  end
36
35
  end
37
36
  end
@@ -1,19 +1,64 @@
1
1
  module DOM
2
2
  module Events
3
- def on(event, &listener)
4
- `#{@el}.addEventListener(#{event},function(e){#{ listener.call Event.new(`e`)}})`
5
- self
6
- end
7
-
8
- def delegate(event,selector, &listener)
3
+ def trigger(type, data = {})
9
4
  %x{
10
- #{@el}.addEventListener(#{event},function(e){
11
- if(e.target.webkitMatchesSelector(#{selector})){
12
- #{ listener.call Event.new(`e`)}
13
- }
14
- },true)
5
+ event = document.createEvent("HTMLEvents");
6
+ event.initEvent(#{type}, true, true);
7
+ for (key in #{data}) {
8
+ value = #{data}[key];
9
+ event[key] = value;
10
+ }
11
+ #{@el}.dispatchEvent(event);
15
12
  }
16
- self
13
+ end
14
+
15
+ def on(type, &listener)
16
+ klass = if defined? self.class::EVENT_TARGET_CLASS
17
+ self.class::EVENT_TARGET_CLASS
18
+ else
19
+ Hash
20
+ end
21
+ method = `function(e){#{ listener.call Event.new(`e`,klass)}}`
22
+
23
+ @listeners ||= {}
24
+ @listeners[type] ||= []
25
+ @listeners[type] << method
26
+
27
+ `#{@el}.addEventListener(#{type},#{method})`
28
+ method
29
+ end
30
+
31
+ def off(type = nil, method = nil)
32
+ return unless @listeners
33
+
34
+ if type == nil
35
+ @listeners.keys.each do |type|
36
+ removeListeners type
37
+ end
38
+ elsif method == nil
39
+ removeListeners type
40
+ else
41
+ return unless @listeners[type].index(method)
42
+ @listeners[type].delete method
43
+ `#{@el}.removeEventListener(#{type},#{method})`
44
+ end
45
+ end
46
+
47
+ def delegate(type,selector, &listener)
48
+ on type do |event|
49
+ if event.target.matches selector
50
+ listener.call event
51
+ end
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def removeListeners(type)
58
+ @listeners[type].each do |method|
59
+ @listeners[type].delete method
60
+ `#{@el}.removeEventListener(#{type},#{method})`
61
+ end
17
62
  end
18
63
  end
19
64
  end
@@ -1,6 +1,17 @@
1
+ require 'native'
2
+
1
3
  module DOM
2
- module Node
4
+ class NODE
5
+ EVENT_TARGET_CLASS = self
6
+
3
7
  include Events
8
+ include Comparable
9
+
10
+ def initialize(node = nil)
11
+ raise "A node must be provided!" unless node
12
+ raise "Not a HTML Node given!" unless `#{node} instanceof Node`
13
+ @el = node
14
+ end
4
15
 
5
16
  # Cloning
6
17
  # ---------------------------------------
@@ -15,11 +26,13 @@ module DOM
15
26
  # Hierarchy
16
27
  # ---------------------------------------
17
28
  def parentNode
18
- DOM::Node.new `#{@el}.parentNode`
29
+ el = `#{@el}.parentNode || false`
30
+ el ? DOM::NODE.new(el) : nil
19
31
  end
20
32
 
21
33
  def parent
22
- DOM::Node.new `#{@el}.parentElement`
34
+ el = `#{@el}.parentElement || false`
35
+ el ? DOM::NODE.new(el) : nil
23
36
  end
24
37
 
25
38
  def empty?
@@ -27,13 +40,13 @@ module DOM
27
40
  end
28
41
 
29
42
  def children
30
- `Array.prototype.slice.call(#{@el}.childNodes)`
43
+ NodeList.new `Array.prototype.slice.call(#{@el}.childNodes)`
31
44
  end
32
45
 
33
46
  # Remove
34
47
  # ---------------------------------------
35
48
  def remove(el)
36
- `#{@el}.removeChild(#{getEl el})`
49
+ `#{@el}.removeChild(#{NODE.getElement el})`
37
50
  end
38
51
 
39
52
  def remove!
@@ -44,12 +57,11 @@ module DOM
44
57
  # Hierarchy Manipulation
45
58
  # ---------------------------------------
46
59
  def << el
47
- `#{@el}.appendChild(#{getEl el})`
48
- self
60
+ `#{@el}.appendChild(#{NODE.getElement el})`
49
61
  end
50
62
 
51
63
  def >> el
52
- `#{getEl el}.appendChild(#{@el})`
64
+ `#{NODE.getElement el}.appendChild(#{@el})`
53
65
  end
54
66
 
55
67
  def insertBefore(what,where)
@@ -66,14 +78,36 @@ module DOM
66
78
  `#{@el}.textContent = #{text}`
67
79
  end
68
80
 
69
- def normalize
81
+ def normalize!
70
82
  `#{@el}.normalize()`
71
83
  end
72
84
 
85
+ # Comparabe methods
86
+ # ---------------------------------------
87
+ def ==(obj)
88
+ `#{NODE.getElement(obj)} === #{@el}`
89
+ end
90
+
91
+ def <=>(obj)
92
+ if obj == self then return 0 end
93
+ if obj.parent != parent then raise 'Nodes not Comparable!' end
94
+ obj.index <=> index
95
+ end
96
+
97
+ def index
98
+ parent.children.index self
99
+ end
100
+
73
101
  private
74
102
 
75
- def getEl(obj)
76
- obj.is_a?(Node) ? obj.instance_variable_get('@el') : obj
103
+ def self.getElement(obj)
104
+ if `#{obj} instanceof Node`
105
+ obj
106
+ elsif obj.is_a?(NODE)
107
+ obj.instance_variable_get('@el')
108
+ else
109
+ nil
110
+ end
77
111
  end
78
112
  end
79
113
  end
@@ -0,0 +1,14 @@
1
+ require 'forwardable'
2
+
3
+ module DOM
4
+ class NodeList
5
+ include Enumerable
6
+ extend Forwardable
7
+
8
+ def_delegators :@nodes, :length, :include?, :each, :index, :[]
9
+
10
+ def initialize(nodes)
11
+ @nodes = nodes.map { |node| DOM::NODE.new node }
12
+ end
13
+ end
14
+ end
@@ -1,21 +1,23 @@
1
- class Style
2
- def initialize(el)
3
- @el = el
4
- end
1
+ module DOM
2
+ class Style
3
+ def initialize(el)
4
+ @el = el
5
+ end
5
6
 
6
- def method_missing(name,value)
7
- if name =~ /\=$/
8
- self[name[0..-2]] = value
9
- else
10
- self[name]
7
+ def method_missing(name,value)
8
+ if name =~ /\=$/
9
+ self[name[0..-2]] = value
10
+ else
11
+ self[name]
12
+ end
11
13
  end
12
- end
13
14
 
14
- def [](prop)
15
- `#{@el}.style[#{prop}]`
16
- end
15
+ def [](prop)
16
+ `#{@el}.style[#{prop}]`
17
+ end
17
18
 
18
- def []=(prop,value)
19
- `#{@el}.style[#{prop}] = #{value}`
19
+ def []=(prop,value)
20
+ `#{@el}.style[#{prop}] = #{value}`
21
+ end
20
22
  end
21
23
  end
@@ -1,9 +1,7 @@
1
1
  module DOM
2
- class Text
3
- include Node
4
-
2
+ class Text < NODE
5
3
  def initialize(data)
6
- @el = `typeof #{data} === 'string'` ? `document.createTextNode(#{data})` : data
4
+ @el = `typeof #{data} === 'string'` ? `document.createTextNode(#{data})` : data
7
5
  end
8
6
  end
9
7
  end
@@ -1,8 +1,7 @@
1
1
  module DOM
2
2
  module Window
3
- def self.on(event, &listener)
4
- `window.addEventListener(#{event},#{listener})`
5
- end
3
+ extend Events
4
+ @el = `window`
6
5
 
7
6
  def self.hash
8
7
  `window.location.hash.slice(1)`
@@ -11,26 +11,16 @@ module Fron
11
11
  self
12
12
  end
13
13
 
14
- def handle_state_change
15
- if ready_state == 4
16
- response = Response.new `#{@request}.status`, `#{@request}.response`, `#{@request}.getAllResponseHeaders()`
17
- @callback.call response
18
- end
19
- end
20
-
21
- def ready_state
22
- `#{@request}.readyState`
23
- end
24
-
25
- def request( method = 'GET',data = nil, &callback)
14
+ def request( method = 'GET', data = nil, &callback)
26
15
  if ready_state == 0 or ready_state == 4
16
+ @callback = callback
27
17
  if method.upcase == "GET" && data
28
18
  `#{@request}.open(#{method},#{@url+"?"+data.to_query_string})`
19
+ `#{@request}.send()`
29
20
  else
30
21
  `#{@request}.open(#{method},#{@url})`
22
+ `#{@request}.send(#{data.to_form_data if data})`
31
23
  end
32
- @callback = callback
33
- `#{@request}.send(#{data.to_form_data if data})`
34
24
  else
35
25
  raise "The request is already running!"
36
26
  end
@@ -47,5 +37,18 @@ module Fron
47
37
  def put(data, &callback)
48
38
  request 'PUT', data, &callback
49
39
  end
40
+
41
+ private
42
+
43
+ def ready_state
44
+ `#{@request}.readyState`
45
+ end
46
+
47
+ def handle_state_change
48
+ if ready_state == 4
49
+ response = Response.new `#{@request}.status`, `#{@request}.response`, `#{@request}.getAllResponseHeaders()`
50
+ @callback.call response if @callback
51
+ end
52
+ end
50
53
  end
51
54
  end
@@ -1,18 +1,34 @@
1
- module LocalStorage
2
- def self.get(key)
3
- value = `window.localStorage.getItem(#{key}) || false`
4
- value ? JSON.parse(value) : nil
5
- end
1
+ module Fron
2
+ module Storage
3
+ module LocalStorage
4
+ def self.get(key)
5
+ value = `window.localStorage.getItem(#{key}) || false`
6
+ value ? JSON.parse(value) : nil
7
+ end
6
8
 
7
- def self.set(key, data)
8
- `window.localStorage.setItem(#{key},#{data.to_json})`
9
- end
9
+ def self.set(key, data)
10
+ `window.localStorage.setItem(#{key},#{data.to_json})`
11
+ end
10
12
 
11
- def self.keys
12
- `ret = []; for (var key in localStorage){ ret.push(key) }; return ret;`
13
- end
13
+ def self.remove(key)
14
+ `window.localStorage.removeItem(#{key})`
15
+ end
16
+
17
+ def self.keys
18
+ %x{
19
+ ret = []
20
+ for (var key in localStorage){ ret.push(key) }
21
+ return ret
22
+ }
23
+ end
24
+
25
+ def self.all
26
+ self.keys.map{ |key| self.get key }
27
+ end
14
28
 
15
- def self.all
16
- self.keys.map{ |key| self.get key }
29
+ def self.clear
30
+ `window.localStorage.clear()`
31
+ end
32
+ end
17
33
  end
18
34
  end
@@ -0,0 +1,18 @@
1
+ require 'fron/core-ext/hash'
2
+
3
+ describe Hash do
4
+
5
+ subject { { a: 'test', b: 'user' } }
6
+
7
+ describe "#to_query_string" do
8
+ it 'should return the hash in query string format' do
9
+ subject.to_query_string.should eq 'a=test&b=user'
10
+ end
11
+ end
12
+
13
+ describe '#to_form_data' do
14
+ it 'should return the hash in FormData format' do
15
+ `#{subject.to_form_data} instanceof FormData`.should be true
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,65 @@
1
+ require 'fron/storage'
2
+ require 'fron/core'
3
+
4
+ describe Fron::Adapters::LocalAdapter do
5
+
6
+ subject { described_class.new({fields: [:name]}) }
7
+ let(:proc) { Proc.new {} }
8
+
9
+ describe "#all" do
10
+ it "should call localStorage#all" do
11
+ Fron::Storage::LocalStorage.should receive(:all).once
12
+ subject.all &proc
13
+ end
14
+
15
+ it "should run the block" do
16
+ proc.should receive(:call)
17
+ subject.all &proc
18
+ end
19
+ end
20
+
21
+ describe "#get" do
22
+ it "should call localStorage#get" do
23
+ Fron::Storage::LocalStorage.should receive(:get).once
24
+ subject.get 0, &proc
25
+ end
26
+
27
+ it "should run the block" do
28
+ proc.should receive(:call)
29
+ subject.get 0, &proc
30
+ end
31
+ end
32
+
33
+ describe "#set" do
34
+ it "should call localStorage#set" do
35
+ Fron::Storage::LocalStorage.should receive(:set).once
36
+ subject.set 0, {name: 'test'}, &proc
37
+ end
38
+
39
+ it "should run the block with nil if there are no errors" do
40
+ proc.should receive(:call).with nil
41
+ subject.set 0, {name: 'test'}, &proc
42
+ end
43
+
44
+ it "should run the block with erros if ther are any" do
45
+ proc.should receive(:call).with({name: ["can't be blank"]})
46
+ subject.set 0, {name: ''}, &proc
47
+ end
48
+
49
+ it "should add id if there isn't any" do
50
+ result = subject.set nil, {name: ''}, &proc
51
+ result[:id].should_not be nil
52
+ end
53
+ end
54
+
55
+ describe "#validate" do
56
+ it "should return errors for undefined fields" do
57
+ subject.validate.should eq({name: ["can't be blank"]})
58
+ end
59
+
60
+ it "should return errors for empty fields" do
61
+ subject.validate({name: ''}).should eq({name: ["can't be blank"]})
62
+ end
63
+ end
64
+ end
65
+