inesita 0.3.5 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,12 +2,9 @@ require 'opal'
2
2
  require 'js'
3
3
  require 'console'
4
4
 
5
- require 'browser'
6
- require 'browser/history'
7
- require 'browser/animation_frame'
8
-
9
5
  require 'virtual_dom'
10
6
 
7
+ require 'inesita/browser'
11
8
  require 'inesita/error'
12
9
  require 'inesita/component_virtual_dom_extension'
13
10
  require 'inesita/component_properties'
@@ -17,16 +17,16 @@ module Inesita
17
17
 
18
18
  def setup_router(router)
19
19
  if router
20
- fail Error, "Invalid #{router} class, should mixin Inesita::Router" unless router.include?(Inesita::Router)
20
+ raise Error, "Invalid #{router} class, should mixin Inesita::Router" unless router.include?(Inesita::Router)
21
21
  @router = router.new
22
22
  else
23
- @router = Class.new { define_method(:method_missing) { fail 'Router missing' } }.new
23
+ @router = Class.new { define_method(:method_missing) { raise 'Router missing' } }.new
24
24
  end
25
25
  end
26
26
 
27
27
  def setup_layout(layout)
28
28
  if layout
29
- fail Error, "Invalid #{layout} class, should mixin Inesita::Layout" unless layout.include?(Inesita::Layout)
29
+ raise Error, "Invalid #{layout} class, should mixin Inesita::Layout" unless layout.include?(Inesita::Layout)
30
30
  @layout = layout.new
31
31
  end
32
32
  end
@@ -37,14 +37,15 @@ module Inesita
37
37
  elsif @router
38
38
  @root = @router
39
39
  else
40
- fail Error, 'Router or Layout not found!'
40
+ raise Error, 'Router or Layout not found!'
41
41
  end
42
42
  end
43
43
 
44
44
  def setup_store(store)
45
45
  return unless store
46
- fail Error, "Invalid #{store} class, should mixin Inesita::Store" unless store.include?(Inesita::Store)
47
- @store = store.new.with_root_component(@root).store
46
+ raise Error, "Invalid #{store} class, should mixin Inesita::Store" unless store.include?(Inesita::Store)
47
+ @store = store.new.with_root_component(@root).with_router(@router).store
48
+ @store.init
48
49
  end
49
50
  end
50
51
  end
@@ -0,0 +1,63 @@
1
+ module Inesita
2
+ module Browser
3
+ module_function
4
+
5
+ Window = JS.global
6
+ Document = Window.JS[:document]
7
+ Location = Document.JS[:location]
8
+ History = Window.JS[:history]
9
+ AddEventListener = Window.JS[:addEventListener]
10
+
11
+ if Native(Window.JS[:requestAnimationFrame])
12
+ def animation_frame(&block)
13
+ Window.JS.requestAnimationFrame(block)
14
+ end
15
+ else
16
+ def animation_frame(&block)
17
+ block.call
18
+ end
19
+ end
20
+
21
+ def path
22
+ Location.JS[:pathname]
23
+ end
24
+
25
+ def query
26
+ Location.JS[:search]
27
+ end
28
+
29
+ def decode_uri_component(value)
30
+ JS.decodeURIComponent(value)
31
+ end
32
+
33
+ def push_state(path)
34
+ History.JS.pushState({}, nil, path)
35
+ end
36
+
37
+ def onpopstate(&block)
38
+ Window.JS[:onpopstate] = block
39
+ end
40
+
41
+ def hashchange(&block)
42
+ AddEventListener.call(:hashchange, block)
43
+ end
44
+
45
+ def ready?(&block)
46
+ AddEventListener.call('load', block)
47
+ end
48
+
49
+ def body
50
+ Document.JS[:body]
51
+ end
52
+
53
+ def append_child(node, new_node)
54
+ node = node.to_n unless native?(node)
55
+ new_node = new_node.to_n unless native?(new_node)
56
+ node.JS.appendChild(new_node)
57
+ end
58
+
59
+ def query_element(css)
60
+ Document.JS.querySelector(css)
61
+ end
62
+ end
63
+ end
@@ -5,17 +5,18 @@ module Inesita
5
5
  include ComponentProperties
6
6
  include ComponentVirtualDomExtension
7
7
 
8
+ def init; end
9
+
8
10
  def render
9
- fail Error, "Implement #render in #{self.class} component"
11
+ raise Error, "Implement #render in #{self.class} component"
10
12
  end
11
13
 
12
14
  def mount_to(element)
13
- fail Error, "Can't mount #{self.class}, target element not found!" unless element
15
+ raise Error, "Can't mount #{self.class}, target element not found!" unless element
14
16
  @root_component = self
15
17
  @virtual_dom = render_virtual_dom
16
18
  @root_node = VirtualDOM.create(@virtual_dom)
17
- element.inner_dom = @root_node
18
- @root_component.call_after_render
19
+ Browser.append_child(element, @root_node)
19
20
  self
20
21
  end
21
22
 
@@ -28,36 +29,25 @@ module Inesita
28
29
  end
29
30
 
30
31
  def render_virtual_dom
31
- @after_render_callbacks = []
32
- @root_component.add_after_render(method(:after_render)) if respond_to?(:after_render)
33
32
  @cache_component_counter = 0
34
33
  @__virtual_nodes__ = []
35
34
  render
36
- if @__virtual_nodes__.length == 1
35
+ if @__virtual_nodes__.one?
37
36
  @__virtual_nodes__.first
38
37
  else
39
38
  VirtualDOM::VirtualNode.new('div', {}, @__virtual_nodes__).to_n
40
39
  end
41
40
  end
42
41
 
43
- def add_after_render(block)
44
- @after_render_callbacks << block
45
- end
46
-
47
- def call_after_render
48
- @after_render_callbacks.reverse_each(&:call)
49
- end
50
-
51
42
  def update_dom
52
43
  $console.warn "Use 'render!' instead of 'update_dom'"
53
44
  render!
54
45
  end
55
46
 
56
47
  def render!
57
- animation_frame do
48
+ Browser.animation_frame do
58
49
  if @root_component
59
50
  @root_component.render_if_root
60
- @root_component.call_after_render
61
51
  end
62
52
  end
63
53
  end
@@ -68,5 +58,13 @@ module Inesita
68
58
  @cache_component_counter += 1
69
59
  @cache_component["#{component}-#{@cache_component_counter}"] || @cache_component["#{component}-#{@cache_component_counter}"] = block.call
70
60
  end
61
+
62
+ def hook(mthd)
63
+ VirtualDOM::Hook.method(method(mthd))
64
+ end
65
+
66
+ def unhook(mthd)
67
+ VirtualDOM::UnHook.method(method(mthd))
68
+ end
71
69
  end
72
70
  end
@@ -3,19 +3,21 @@ module Inesita
3
3
  def self.included(base)
4
4
  base.alias_method :__a, :a
5
5
  base.define_method(:a) do |params, &block|
6
- params = { onclick: -> { @router.handle_link(params[:href]) } }.merge(params) if params[:href] && @router
6
+ params = { onclick: -> { @router.go_to(params[:href]) } }.merge(params) if params[:href] && @router
7
7
  __a(params, &block)
8
8
  end
9
9
  end
10
10
 
11
11
  def component(comp, opts = {})
12
- fail Error, "Component is nil in #{self.class} class" if comp.nil?
12
+ raise Error, "Component is nil in #{self.class} class" if comp.nil?
13
13
  @__virtual_nodes__ ||= []
14
14
  @__virtual_nodes__ << cache_component(comp) do
15
- (comp.is_a?(Class) ? comp.new : comp)
15
+ comp = (comp.is_a?(Class) ? comp.new : comp)
16
16
  .with_root_component(@root_component)
17
17
  .with_router(@router)
18
18
  .with_store(@store)
19
+ comp.init
20
+ comp
19
21
  end.with_props(opts[:props] || {}).render_virtual_dom
20
22
  end
21
23
  end
@@ -6,16 +6,17 @@ module Inesita
6
6
 
7
7
  def initialize
8
8
  @routes = Routes.new
9
- @url_params = parse_url_params
10
- fail Error, 'Add #routes method to router!' unless respond_to?(:routes)
9
+ raise Error, 'Add #routes method to router!' unless respond_to?(:routes)
11
10
  routes
12
- fail Error, 'Add #route to your #routes method!' if @routes.routes.empty?
11
+ raise Error, 'Add #route to your #routes method!' if @routes.routes.empty?
12
+ find_route
13
+ parse_url_params
13
14
  add_listeners
14
15
  end
15
16
 
16
17
  def add_listeners
17
- $window.on(:popstate) { render! }
18
- $window.on(:hashchange) { render! }
18
+ Browser.onpopstate { find_route; parse_url_params; render! }
19
+ Browser.hashchange { find_route; parse_url_params; render! }
19
20
  end
20
21
 
21
22
  def route(*params, &block)
@@ -25,39 +26,39 @@ module Inesita
25
26
  def find_route
26
27
  @routes.routes.each do |route|
27
28
  next unless path.match(route[:regex])
28
- return handle_link(url_for(route[:redirect_to])) if route[:redirect_to]
29
- return route
29
+ return go_to(url_for(route[:redirect_to])) if route[:redirect_to]
30
+ return @route = route
30
31
  end
31
- fail Error, "Can't find route for url"
32
+ raise Error, "Can't find route for url"
32
33
  end
33
34
 
34
35
  def find_component(route)
35
- params = path.match(route[:regex])
36
- @params = @url_params.merge(Hash[route[:params].zip(params[1..-1])])
37
36
  @component_props = route[:component_props]
38
37
  route[:component]
39
38
  end
40
39
 
41
40
  def render
42
- if route = find_route
43
- component find_component(route), props: @component_props
44
- end
41
+ component find_component(@route), props: @component_props if @route
45
42
  end
46
43
 
47
- def handle_link(path)
48
- $window.history.push(path)
44
+ def go_to(path)
45
+ Browser.push_state(path)
46
+ find_route
47
+ parse_url_params
49
48
  render!
50
49
  false
51
50
  end
52
51
 
53
52
  def parse_url_params
54
- params = {}
55
- url_query = $window.location.query.to_s
56
- url_query[1..-1].split('&').each do |param|
53
+ @params = compotent_url_params
54
+ query[1..-1].split('&').each do |param|
57
55
  key, value = param.split('=')
58
- params[key.decode_uri_component] = value.decode_uri_component
59
- end unless url_query.length == 0
60
- params
56
+ @params[Browser.decode_uri_component(key)] = Browser.decode_uri_component(value)
57
+ end unless query.empty?
58
+ end
59
+
60
+ def compotent_url_params
61
+ Hash[@route[:params].zip(path.match(@route[:regex])[1..-1])]
61
62
  end
62
63
 
63
64
  def url_for(name, params = nil)
@@ -71,11 +72,15 @@ module Inesita
71
72
  false
72
73
  end
73
74
  end
74
- route ? url_with_params(route, params) : fail(Error, "Route '#{name}' not found.")
75
+ route ? url_with_params(route, params) : raise(Error, "Route '#{name}' not found.")
76
+ end
77
+
78
+ def query
79
+ Browser.query
75
80
  end
76
81
 
77
82
  def path
78
- $window.location.path
83
+ Browser.path
79
84
  end
80
85
 
81
86
  def current_url?(name)
@@ -8,7 +8,7 @@ module Inesita
8
8
  end
9
9
 
10
10
  def route(*params, &block)
11
- path = params.first.delete('/')
11
+ path = params.first.gsub(/^\//, '')
12
12
  path = @parent ? "#{@parent}/#{path}" : "/#{path}"
13
13
 
14
14
  add_subroutes(path, &block) if block_given?
@@ -21,15 +21,15 @@ module Inesita
21
21
  end
22
22
 
23
23
  def validate_component(component)
24
- fail Error, 'Component not exists' unless component
25
- fail Error, "Invalid #{component} class, should mixin Inesita::Component" unless component.include?(Inesita::Component)
24
+ raise Error, 'Component not exists' unless component
25
+ raise Error, "Invalid #{component} class, should mixin Inesita::Component" unless component.include?(Inesita::Component)
26
26
  end
27
27
 
28
28
  def add_redirect(path, redirect_to)
29
29
  @routes << {
30
30
  path: path,
31
31
  redirect_to: redirect_to
32
- }.merge(params_and_regex(path))
32
+ }.merge(build_params_and_regex(path))
33
33
  end
34
34
 
35
35
  def add_route(name, path, component, component_props)
@@ -39,7 +39,7 @@ module Inesita
39
39
  component: component,
40
40
  component_props: component_props,
41
41
  name: name || component.to_s.gsub(/(.)([A-Z])/, '\1_\2').downcase
42
- }.merge(params_and_regex(path))
42
+ }.merge(build_params_and_regex(path))
43
43
  end
44
44
 
45
45
  def add_subroutes(path, &block)
@@ -48,7 +48,7 @@ module Inesita
48
48
  @routes += subroutes.routes
49
49
  end
50
50
 
51
- def params_and_regex(path)
51
+ def build_params_and_regex(path)
52
52
  regex = ['^']
53
53
  params = []
54
54
  parts = path.split('/')
@@ -56,9 +56,14 @@ module Inesita
56
56
  parts.each do |part|
57
57
  next if part.empty?
58
58
  regex << '\/'
59
- if part[0] == ':'
59
+ case part[0]
60
+ when ':'
60
61
  params << part[1..-1]
61
62
  regex << '([^\/]+)'
63
+ when '*'
64
+ params << part[1..-1]
65
+ regex << '(.*)'
66
+ break
62
67
  else
63
68
  regex << part
64
69
  end
@@ -1,8 +1,8 @@
1
1
  module Inesita
2
2
  module Store
3
- def store
4
- self
5
- end
3
+
4
+ def init; end
5
+ def store; self end
6
6
 
7
7
  def update_dom
8
8
  $console.warn "Use 'render!' instead of 'update_dom'"
@@ -18,5 +18,11 @@ module Inesita
18
18
  @root_component = component
19
19
  self
20
20
  end
21
+
22
+ attr_reader :router
23
+ def with_router(router)
24
+ @router = router
25
+ self
26
+ end
21
27
  end
22
28
  end
@@ -37,7 +37,7 @@ describe Inesita::Router do
37
37
  end
38
38
 
39
39
  let(:element) do
40
- $document.create_element('div')
40
+ Inesita::Browser::Document.JS.createElement('div')
41
41
  end
42
42
 
43
43
  it 'should fail when no #render method' do
@@ -46,11 +46,11 @@ describe Inesita::Router do
46
46
 
47
47
  it 'should render html' do
48
48
  component.new.mount_to(element)
49
- expect(element.inner_html).to eq '<h1 class="test">Test</h1>'
49
+ expect(element.JS[:innerHTML]).to eq '<h1 class="test">Test</h1>'
50
50
  end
51
51
 
52
52
  it 'should render html with nested components' do
53
53
  nested_component.new.mount_to(element)
54
- expect(element.inner_html).to eq '<h1 class="test"><div>Inner</div></h1>'
54
+ expect(element.JS[:innerHTML]).to eq '<h1 class="test"><div>Inner</div></h1>'
55
55
  end
56
56
  end
@@ -2,4 +2,3 @@ include RSpec
2
2
 
3
3
  require 'virtual-dom'
4
4
  require 'inesita'
5
- require 'browser'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inesita
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michał Kalbarczyk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-10 00:00:00.000000000 Z
11
+ date: 2016-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opal
@@ -24,34 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.9'
27
- - !ruby/object:Gem::Dependency
28
- name: opal-browser
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '0.2'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '0.2'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: opal-virtual-dom
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
31
  - - "~>"
46
32
  - !ruby/object:Gem::Version
47
- version: 0.3.0
33
+ version: 0.4.0
48
34
  type: :runtime
49
35
  prerelease: false
50
36
  version_requirements: !ruby/object:Gem::Requirement
51
37
  requirements:
52
38
  - - "~>"
53
39
  - !ruby/object:Gem::Version
54
- version: 0.3.0
40
+ version: 0.4.0
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: slim
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -122,20 +108,6 @@ dependencies:
122
108
  - - "~>"
123
109
  - !ruby/object:Gem::Version
124
110
  version: '3.0'
125
- - !ruby/object:Gem::Dependency
126
- name: websocket
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: '1.0'
132
- type: :runtime
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: '1.0'
139
111
  description: Frontent web framework for Opal
140
112
  email: fazibear@gmail.com
141
113
  executables:
@@ -153,7 +125,6 @@ files:
153
125
  - bin/inesita
154
126
  - inesita.gemspec
155
127
  - lib/inesita.rb
156
- - lib/inesita/app_files_listener.rb
157
128
  - lib/inesita/cli.rb
158
129
  - lib/inesita/cli/build.rb
159
130
  - lib/inesita/cli/new.rb
@@ -174,19 +145,17 @@ files:
174
145
  - lib/inesita/cli/template/static/inesita-rb.png
175
146
  - lib/inesita/cli/watch.rb
176
147
  - lib/inesita/config.rb
177
- - lib/inesita/live_reload.rb
178
148
  - lib/inesita/minify.rb
179
149
  - lib/inesita/server.rb
180
- - lib/rubame.rb
181
150
  - opal/inesita.rb
182
151
  - opal/inesita/application.rb
152
+ - opal/inesita/browser.rb
183
153
  - opal/inesita/component.rb
184
154
  - opal/inesita/component_helpers.rb
185
155
  - opal/inesita/component_properties.rb
186
156
  - opal/inesita/component_virtual_dom_extension.rb
187
157
  - opal/inesita/error.rb
188
158
  - opal/inesita/layout.rb
189
- - opal/inesita/live_reload.rb
190
159
  - opal/inesita/router.rb
191
160
  - opal/inesita/routes.rb
192
161
  - opal/inesita/store.rb