porous 0.1.0 → 0.2.0
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +20 -1
- data/CHANGELOG.md +14 -5
- data/README.md +16 -6
- data/Rakefile +3 -3
- data/exe/porous +2 -0
- data/lib/porous/application.rb +33 -0
- data/lib/porous/cli/build.rb +39 -3
- data/lib/porous/cli/new.rb +2 -0
- data/lib/porous/cli/server.rb +25 -4
- data/lib/porous/cli/template/pages/home.rb +11 -5
- data/lib/porous/cli.rb +2 -0
- data/lib/porous/component/class_methods.rb +2 -0
- data/lib/porous/component/render.rb +3 -2
- data/lib/porous/component/virtual.rb +2 -0
- data/lib/porous/component.rb +2 -1
- data/lib/porous/injection.rb +8 -8
- data/lib/porous/logger.rb +9 -0
- data/lib/porous/page.rb +6 -1
- data/lib/porous/router.rb +22 -13
- data/lib/porous/routes.rb +12 -4
- data/lib/porous/server.rb +29 -31
- data/lib/porous/version.rb +1 -1
- data/lib/porous.rb +8 -3
- data/lib/virtual_dom/dom.rb +13 -9
- data/lib/virtual_dom/virtual_node.rb +3 -1
- data/opal/porous/application.rb +15 -0
- data/opal/porous/component/class_methods.rb +5 -3
- data/opal/porous/component/render.rb +26 -23
- data/opal/porous/component/virtual.rb +2 -0
- data/opal/porous/component.rb +3 -1
- data/opal/porous/injection.rb +13 -9
- data/opal/porous/page.rb +16 -0
- data/opal/porous/router.rb +153 -0
- data/opal/porous/routes.rb +94 -0
- data/opal/porous.rb +31 -0
- metadata +18 -68
- data/opal/porous/browser.rb +0 -37
data/lib/porous/server.rb
CHANGED
@@ -1,44 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Porous
|
2
4
|
class Server
|
3
|
-
|
4
|
-
|
5
|
+
def initialize(*_args)
|
6
|
+
setup_rack_app
|
5
7
|
end
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def render
|
11
|
-
html do
|
12
|
-
head do
|
13
|
-
title do
|
14
|
-
text props[:title]
|
15
|
-
end
|
16
|
-
meta charset: 'UTF-8'
|
17
|
-
meta name: 'viewport', content: 'width=device-width, initial-scale=1.0'
|
18
|
-
script src: 'https://cdn.tailwindcss.com'
|
19
|
-
end
|
20
|
-
|
21
|
-
body class: 'bg-gray-50 dark:bg-gray-900' do
|
22
|
-
component Router, props: { path: props[:path], query: props[:query] }
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def initialize(*args, &block)
|
9
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
10
|
+
def setup_rack_app
|
29
11
|
@rack = Rack::Builder.new do
|
12
|
+
use Rack::ContentLength
|
30
13
|
use Rack::Static, urls: ['/static']
|
14
|
+
use Rack::CommonLogger
|
15
|
+
use Rack::ShowExceptions
|
16
|
+
use Rack::Lint
|
17
|
+
use Rack::TempfileReaper
|
18
|
+
|
31
19
|
run do |env|
|
32
|
-
[
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
20
|
+
router = Porous::Router.new path: env['PATH_INFO'], query: env['QUERY_STRING']
|
21
|
+
route = router.find_route
|
22
|
+
page = route[:component].new(route[:params])
|
23
|
+
|
24
|
+
[200, { 'content-type' => 'text/html' }, [
|
25
|
+
Porous::Application.new(
|
26
|
+
title: page.page_title,
|
27
|
+
description: page.page_description,
|
28
|
+
path: env['PATH_INFO'],
|
29
|
+
query: env['QUERY_STRING']
|
30
|
+
).to_s
|
31
|
+
]]
|
32
|
+
rescue Porous::InvalidRouteError => e
|
33
|
+
[404, { 'content-type' => 'text/plain' }, ["404 Page not found\n", e.message]]
|
34
|
+
rescue Porous::Error => e
|
35
|
+
[500, { 'content-type' => 'text/plain' }, ["500 Internal Server Error\n", e.message]]
|
39
36
|
end
|
40
37
|
end
|
41
38
|
end
|
39
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
42
40
|
|
43
41
|
def call(*args)
|
44
42
|
@rack.call(*args)
|
data/lib/porous/version.rb
CHANGED
data/lib/porous.rb
CHANGED
@@ -2,9 +2,11 @@
|
|
2
2
|
|
3
3
|
require 'opal'
|
4
4
|
require 'opal-browser'
|
5
|
-
Opal.append_path File.expand_path('../../opal', __FILE__)
|
6
|
-
|
7
5
|
require 'opal-virtual-dom'
|
6
|
+
|
7
|
+
Opal.append_path File.expand_path('../opal', __dir__)
|
8
|
+
Opal.append_path File.expand_path(Dir.pwd)
|
9
|
+
|
8
10
|
require 'listen'
|
9
11
|
|
10
12
|
require 'porous/version'
|
@@ -24,7 +26,10 @@ Dir.glob(File.join('{components,pages}', '**', '*.rb')).each do |relative_path|
|
|
24
26
|
require File.expand_path("#{Dir.pwd}/#{relative_path}")
|
25
27
|
end
|
26
28
|
|
27
|
-
require 'porous/
|
29
|
+
require 'porous/application'
|
30
|
+
require 'porous/server' unless RUBY_ENGINE == 'opal'
|
28
31
|
|
29
32
|
module Porous
|
33
|
+
class Error < StandardError; end
|
34
|
+
class InvalidRouteError < Error; end
|
30
35
|
end
|
data/lib/virtual_dom/dom.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module VirtualDOM
|
2
4
|
module DOM
|
3
|
-
HTML_TAGS = %w
|
5
|
+
HTML_TAGS = %w[a abbr address area article aside audio b base bdi bdo big blockquote body br
|
4
6
|
button canvas caption cite code col colgroup data datalist dd del details dfn
|
5
7
|
dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5
|
6
8
|
h6 head header hr html i iframe img input ins kbd keygen label legend li link
|
7
9
|
main map mark menu menuitem meta meter nav noscript object ol optgroup option
|
8
10
|
output p param picture pre progress q rp rt ruby s samp script section select
|
9
11
|
small source span strong style sub summary sup table tbody td textarea tfoot th
|
10
|
-
thead time title tr track u ul var video wbr
|
12
|
+
thead time title tr track u ul var video wbr].freeze
|
11
13
|
|
12
|
-
SVG_TAGS = %w
|
14
|
+
SVG_TAGS = %w[svg path].freeze
|
13
15
|
|
14
16
|
(HTML_TAGS + SVG_TAGS).each do |tag|
|
15
17
|
define_method tag do |params = {}, &block|
|
@@ -38,7 +40,8 @@ module VirtualDOM
|
|
38
40
|
self
|
39
41
|
end
|
40
42
|
|
41
|
-
|
43
|
+
# rubocop:disable Style/MissingRespondToMissing, Metrics/MethodLength, Metrics/AbcSize
|
44
|
+
def method_missing(klass, params = {}, &block)
|
42
45
|
return unless @__last_virtual_node__
|
43
46
|
return unless @__virtual_nodes__
|
44
47
|
|
@@ -51,28 +54,29 @@ module VirtualDOM
|
|
51
54
|
end
|
52
55
|
|
53
56
|
class_params = @__last_virtual_node__.params.delete(:className)
|
54
|
-
method_params = if
|
55
|
-
{ id:
|
57
|
+
method_params = if klass.end_with?('!')
|
58
|
+
{ id: klass[0..-2],
|
56
59
|
class: merge_string(class_params, params[:class]) }
|
57
60
|
else
|
58
|
-
{ class: merge_string(class_params, params[:class],
|
61
|
+
{ class: merge_string(class_params, params[:class], klass.to_s.gsub('_', '-').gsub('--', '_')) }
|
59
62
|
end
|
60
63
|
params = @__last_virtual_node__.params.merge(params).merge(method_params)
|
61
64
|
process_tag(@__last_virtual_node__.name, params, block, children)
|
62
65
|
end
|
66
|
+
# rubocop:enable Style/MissingRespondToMissing, Metrics/MethodLength, Metrics/AbcSize
|
63
67
|
|
64
68
|
def merge_string(*params)
|
65
69
|
arr = []
|
66
70
|
params.each do |string|
|
67
71
|
next unless string
|
68
72
|
|
69
|
-
arr << string.split
|
73
|
+
arr << string.split
|
70
74
|
end
|
71
75
|
arr.join(' ')
|
72
76
|
end
|
73
77
|
|
74
78
|
def process_params(params)
|
75
|
-
params.dup.
|
79
|
+
params.dup.each_key do |k|
|
76
80
|
case k
|
77
81
|
when 'for'
|
78
82
|
params['htmlFor'] = params.delete('for')
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module VirtualDOM
|
2
4
|
class VirtualNode
|
3
5
|
attr_reader :name, :params, :children
|
@@ -15,7 +17,7 @@ module VirtualDOM
|
|
15
17
|
def to_s_params
|
16
18
|
return unless @params.any?
|
17
19
|
|
18
|
-
|
20
|
+
" #{@params.map { |k, v| "#{k}=\"#{v}\"" }.join(" ")}"
|
19
21
|
end
|
20
22
|
|
21
23
|
def to_s_children
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Porous
|
2
4
|
module Component
|
3
5
|
module ClassMethods
|
@@ -5,10 +7,10 @@ module Porous
|
|
5
7
|
new.mount_to(element)
|
6
8
|
end
|
7
9
|
|
8
|
-
def inject(
|
9
|
-
method_name = opts[:as] ||
|
10
|
+
def inject(klass, opts = {})
|
11
|
+
method_name = opts[:as] || klass.to_s.downcase
|
10
12
|
@injections ||= {}
|
11
|
-
@injections[method_name] =
|
13
|
+
@injections[method_name] = klass
|
12
14
|
end
|
13
15
|
|
14
16
|
def injections
|
@@ -1,27 +1,30 @@
|
|
1
|
-
|
2
|
-
module Component
|
3
|
-
module Render
|
4
|
-
def render
|
5
|
-
raise Error, "Implement #render in #{self.class} component"
|
6
|
-
end
|
1
|
+
# frozen_string_literal: true
|
7
2
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
3
|
+
module Porous
|
4
|
+
module Component
|
5
|
+
module Render
|
6
|
+
def render
|
7
|
+
raise Error, "Implement #render in #{self.class} component"
|
8
|
+
end
|
15
9
|
|
16
|
-
|
10
|
+
def render_if_root
|
11
|
+
return unless @virtual_dom && @root_node
|
17
12
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
13
|
+
new_virtual_dom = render_virtual_dom
|
14
|
+
diff = VirtualDOM.diff @virtual_dom, new_virtual_dom
|
15
|
+
VirtualDOM.patch @root_node, diff
|
16
|
+
@virtual_dom = new_virtual_dom
|
17
|
+
end
|
18
|
+
|
19
|
+
def before_render; end
|
20
|
+
|
21
|
+
def render_virtual_dom
|
22
|
+
before_render
|
23
|
+
@cache_component_counter = 0
|
24
|
+
@__virtual_nodes__ = []
|
25
|
+
render
|
26
|
+
to_vnode
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
27
30
|
end
|
data/opal/porous/component.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Porous
|
2
4
|
module Component
|
3
5
|
include VirtualDOM::DOM
|
@@ -17,7 +19,7 @@ module Porous
|
|
17
19
|
inject
|
18
20
|
@virtual_dom = render_virtual_dom
|
19
21
|
@root_node = VirtualDOM.create @virtual_dom
|
20
|
-
|
22
|
+
element.replace_with @root_node
|
21
23
|
self
|
22
24
|
end
|
23
25
|
|
data/opal/porous/injection.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Porous
|
2
4
|
module Injection
|
3
5
|
def init; end
|
@@ -20,23 +22,25 @@ module Porous
|
|
20
22
|
|
21
23
|
def init_injections
|
22
24
|
@injections ||= {}
|
23
|
-
self.class.injections.each do |name,
|
24
|
-
|
25
|
-
|
26
|
-
.new
|
27
|
-
.with_root_component(@root_component)
|
28
|
-
else
|
29
|
-
raise Error, "Invalid #{clazz} class, should mixin Porous::Injection"
|
25
|
+
self.class.injections.each do |name, klass|
|
26
|
+
unless klass.included_modules.include?(Porous::Injection)
|
27
|
+
raise Error, "Invalid #{klass} class, should mixin Porous::Injection"
|
30
28
|
end
|
29
|
+
|
30
|
+
@injections[name] = klass.new.with_root_component(@root_component)
|
31
31
|
end
|
32
|
-
@injections.
|
32
|
+
@injections.each_value do |instance|
|
33
33
|
instance.inject
|
34
34
|
instance.init
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
def render!
|
39
|
-
Browser.
|
39
|
+
if Browser::AnimationFrame.supported?
|
40
|
+
animation_frame do
|
41
|
+
@root_component.render_if_root
|
42
|
+
end
|
43
|
+
else
|
40
44
|
@root_component.render_if_root
|
41
45
|
end
|
42
46
|
end
|
data/opal/porous/page.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Porous
|
4
|
+
module Page
|
5
|
+
# Define the route according to the Router::Routes rules
|
6
|
+
def route!
|
7
|
+
path = route
|
8
|
+
@route ||= Routes.new.tap do |routes|
|
9
|
+
routes.route path, to: self.class
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def page_title = 'Porous Web'
|
14
|
+
def page_description = nil
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Porous
|
4
|
+
# rubocop:disable Metrics/ClassLength
|
5
|
+
class Router
|
6
|
+
include Porous::Component
|
7
|
+
|
8
|
+
attr_reader :params
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@routes = Routes.new
|
12
|
+
# Extract the routes from all Pages
|
13
|
+
# Object.descendants.each { |klass| puts klass if klass.is_a?(Class) }
|
14
|
+
Object.descendants.select { |c| c.is_a?(Class) && c.included_modules.include?(Porous::Page) }.each do |klass|
|
15
|
+
# puts "Included in: #{klass}"
|
16
|
+
# next if klass.to_s.start_with? '#<Class:' # skip singleton classes
|
17
|
+
|
18
|
+
@routes.combine klass.new.route!
|
19
|
+
end
|
20
|
+
|
21
|
+
raise Error, 'No Porous::Page components found!' if @routes.routes.empty?
|
22
|
+
|
23
|
+
find_route
|
24
|
+
parse_url_params
|
25
|
+
add_listeners
|
26
|
+
end
|
27
|
+
|
28
|
+
# Handle anchor tags with router (requires router to be injected)
|
29
|
+
Component.module_eval do
|
30
|
+
unless respond_to?(:__a)
|
31
|
+
alias_method :__a, :a
|
32
|
+
define_method(:a) do |params = {}, &block|
|
33
|
+
if params['href'].include?('//') || params['target'] == '_blank'
|
34
|
+
# Retain behaviour
|
35
|
+
else
|
36
|
+
href = params['href']
|
37
|
+
params[:onclick] = lambda { |e|
|
38
|
+
e.prevent
|
39
|
+
raise Error, 'No router to handle navigation. Did you `inject Porous::Router`' unless router
|
40
|
+
|
41
|
+
router.go_to(href)
|
42
|
+
}
|
43
|
+
end
|
44
|
+
__a(params, &block)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_listeners
|
50
|
+
return unless Browser::History.supported?
|
51
|
+
|
52
|
+
$window.on(:popstate) do
|
53
|
+
find_route
|
54
|
+
parse_url_params
|
55
|
+
render!
|
56
|
+
end
|
57
|
+
$window.on(:hashchange) do
|
58
|
+
find_route
|
59
|
+
parse_url_params
|
60
|
+
render!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def route(*params, &block)
|
65
|
+
@routes.route(*params, &block)
|
66
|
+
end
|
67
|
+
|
68
|
+
def find_route
|
69
|
+
@routes.routes.each do |route|
|
70
|
+
next unless path.match(route[:regex])
|
71
|
+
return go_to(url_for(route[:redirect_to])) if route[:redirect_to]
|
72
|
+
|
73
|
+
return @route = route
|
74
|
+
end
|
75
|
+
raise Error, "Can't find route for url"
|
76
|
+
end
|
77
|
+
|
78
|
+
def find_component(route)
|
79
|
+
call_on_enter_callback(route)
|
80
|
+
@component_props = route[:component_props]
|
81
|
+
route[:component]
|
82
|
+
end
|
83
|
+
|
84
|
+
def render
|
85
|
+
component find_component(@route), props: @component_props if @route
|
86
|
+
end
|
87
|
+
|
88
|
+
def call_on_enter_callback(route)
|
89
|
+
return unless route[:on_enter]
|
90
|
+
|
91
|
+
return unless route[:on_enter].respond_to?(:call)
|
92
|
+
|
93
|
+
route[:on_enter].call
|
94
|
+
end
|
95
|
+
|
96
|
+
def go_to(path)
|
97
|
+
$window.history.push path
|
98
|
+
find_route
|
99
|
+
parse_url_params
|
100
|
+
render!
|
101
|
+
false
|
102
|
+
end
|
103
|
+
|
104
|
+
def parse_url_params
|
105
|
+
@params = component_url_params
|
106
|
+
return if query.empty?
|
107
|
+
|
108
|
+
query[1..].split('&').each do |param|
|
109
|
+
key, value = param.split('=')
|
110
|
+
@params[Browser.decode_uri_component(key)] = Browser.decode_uri_component(value)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def component_url_params
|
115
|
+
@route[:params].zip(path.match(@route[:regex])[1..]).to_h
|
116
|
+
end
|
117
|
+
|
118
|
+
def url_for(name, params = nil)
|
119
|
+
route = @routes.routes.find do |r|
|
120
|
+
case name
|
121
|
+
when String
|
122
|
+
r[:name] == name || r[:path] == name
|
123
|
+
when Object
|
124
|
+
r[:component] == name
|
125
|
+
else
|
126
|
+
false
|
127
|
+
end
|
128
|
+
end
|
129
|
+
route ? url_with_params(route, params) : raise(Error, "Route '#{name}' not found.")
|
130
|
+
end
|
131
|
+
|
132
|
+
def query
|
133
|
+
$window.location.query
|
134
|
+
end
|
135
|
+
|
136
|
+
def path
|
137
|
+
$window.location.path
|
138
|
+
end
|
139
|
+
|
140
|
+
def current_url?(name)
|
141
|
+
path == url_for(name, params)
|
142
|
+
end
|
143
|
+
|
144
|
+
def url_with_params(route, params)
|
145
|
+
path = route[:path]
|
146
|
+
params&.each do |key, value|
|
147
|
+
path = path.gsub(":#{key}", value.to_s)
|
148
|
+
end
|
149
|
+
path
|
150
|
+
end
|
151
|
+
end
|
152
|
+
# rubocop:enable Metrics/ClassLength
|
153
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Porous
|
4
|
+
class Routes
|
5
|
+
attr_reader :routes
|
6
|
+
|
7
|
+
def initialize(parent = nil)
|
8
|
+
@parent = parent
|
9
|
+
@routes = []
|
10
|
+
end
|
11
|
+
|
12
|
+
# rubocop:disable Metrics/AbcSize
|
13
|
+
def route(*params, &block)
|
14
|
+
path = params.first.gsub(%r{^/}, '')
|
15
|
+
path = @parent ? "#{@parent}/#{path}" : "/#{path}"
|
16
|
+
|
17
|
+
add_subroutes(path, &block) if block_given?
|
18
|
+
|
19
|
+
if params.last[:redirect_to]
|
20
|
+
add_redirect(path, params.last[:redirect_to])
|
21
|
+
else
|
22
|
+
add_route(params.last[:as], path, params.last[:to], params.last[:props], params.last[:on_enter])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
# rubocop:enable Metrics/AbcSize
|
26
|
+
|
27
|
+
def validate_component(component)
|
28
|
+
raise Error, 'Component not exists' unless component
|
29
|
+
|
30
|
+
return if component.include?(Porous::Component)
|
31
|
+
|
32
|
+
raise Error,
|
33
|
+
"Invalid #{component} class, should mixin Porous::Component"
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_redirect(path, redirect_to)
|
37
|
+
@routes << {
|
38
|
+
path: path,
|
39
|
+
redirect_to: redirect_to
|
40
|
+
}.merge(build_params_and_regex(path))
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_route(name, path, component, component_props, on_enter)
|
44
|
+
validate_component(component)
|
45
|
+
@routes << {
|
46
|
+
path: path,
|
47
|
+
component: component,
|
48
|
+
component_props: component_props,
|
49
|
+
on_enter: on_enter,
|
50
|
+
name: name || component.to_s.gsub(/(.)([A-Z])/, '\1_\2').downcase
|
51
|
+
}.merge(build_params_and_regex(path))
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_subroutes(path, &block)
|
55
|
+
subroutes = Routes.new(path)
|
56
|
+
subroutes.instance_exec(&block)
|
57
|
+
@routes += subroutes.routes
|
58
|
+
end
|
59
|
+
|
60
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
61
|
+
def build_params_and_regex(path)
|
62
|
+
regex = ['^']
|
63
|
+
params = []
|
64
|
+
parts = path.split('/')
|
65
|
+
regex << '\/' if parts.empty?
|
66
|
+
parts.each do |part|
|
67
|
+
next if part.empty?
|
68
|
+
|
69
|
+
regex << '\/'
|
70
|
+
case part[0]
|
71
|
+
when ':'
|
72
|
+
params << part[1..]
|
73
|
+
regex << '([^\/]+)'
|
74
|
+
when '*'
|
75
|
+
params << part[1..]
|
76
|
+
regex << '(.*)'
|
77
|
+
break
|
78
|
+
else
|
79
|
+
regex << part
|
80
|
+
end
|
81
|
+
end
|
82
|
+
regex << '$'
|
83
|
+
{
|
84
|
+
regex: Regexp.new(regex.join),
|
85
|
+
params: params
|
86
|
+
}
|
87
|
+
end
|
88
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
89
|
+
|
90
|
+
def combine(other)
|
91
|
+
@routes += other.routes
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/opal/porous.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'opal'
|
2
4
|
require 'native'
|
3
5
|
require 'promise'
|
@@ -8,3 +10,32 @@ require 'console'
|
|
8
10
|
|
9
11
|
require 'virtual_dom'
|
10
12
|
require 'virtual_dom/support/browser'
|
13
|
+
|
14
|
+
VirtualDOM::DOM::HTML_TAGS = %w[a abbr address area article aside audio b base bdi bdo big blockquote body br
|
15
|
+
button canvas caption cite code col colgroup data datalist dd del details dfn
|
16
|
+
dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5
|
17
|
+
h6 head header hr html i iframe img input ins kbd keygen label legend li link
|
18
|
+
main map mark menu menuitem meta meter nav noscript object ol optgroup option
|
19
|
+
output p param picture pre progress q rp rt ruby s samp script section select
|
20
|
+
small source span strong style sub summary sup table tbody td textarea tfoot th
|
21
|
+
thead time title tr track u ul var video wbr svg path].freeze
|
22
|
+
|
23
|
+
require 'porous/injection'
|
24
|
+
require 'porous/component/class_methods'
|
25
|
+
require 'porous/component/render'
|
26
|
+
require 'porous/component/virtual'
|
27
|
+
require 'porous/component'
|
28
|
+
require 'porous/page'
|
29
|
+
|
30
|
+
require 'porous/routes'
|
31
|
+
require 'porous/router'
|
32
|
+
require 'porous/application'
|
33
|
+
|
34
|
+
module Porous
|
35
|
+
class Error < StandardError; end
|
36
|
+
class InvalidRouteError < Error; end
|
37
|
+
end
|
38
|
+
|
39
|
+
$document.ready do
|
40
|
+
Porous::Application.mount_to($document.body)
|
41
|
+
end
|