fron 0.1.0 → 0.1.1

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