wedgeio 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +49 -0
- data/Rakefile +9 -0
- data/lib/roda/plugins/wedge.rb +93 -0
- data/lib/wedge.rb +238 -0
- data/lib/wedge/component.rb +321 -0
- data/lib/wedge/config.rb +128 -0
- data/lib/wedge/dom.rb +139 -0
- data/lib/wedge/events.rb +136 -0
- data/lib/wedge/html.rb +29 -0
- data/lib/wedge/opal.rb +18 -0
- data/lib/wedge/plugins/form.rb +431 -0
- data/lib/wedge/plugins/history.rb +92 -0
- data/lib/wedge/plugins/location.rb +78 -0
- data/lib/wedge/plugins/pjax.rb +65 -0
- data/lib/wedge/plugins/validations.rb +251 -0
- data/lib/wedge/utilis/blank.rb +133 -0
- data/lib/wedge/utilis/element.rb +23 -0
- data/lib/wedge/utilis/hash.rb +77 -0
- data/lib/wedge/utilis/indifferent_hash.rb +209 -0
- data/lib/wedge/utilis/methods.rb +25 -0
- data/lib/wedge/utilis/nokogiri.rb +44 -0
- data/lib/wedge/utilis/titleize.rb +97 -0
- data/lib/wedge/utilis/try.rb +106 -0
- data/lib/wedge/version.rb +3 -0
- data/test.rb +44 -0
- data/test/dummy/app.rb +34 -0
- data/test/dummy/components/bar.rb +14 -0
- data/test/dummy/components/base.rb +5 -0
- data/test/dummy/components/root.rb +42 -0
- data/test/dummy/config.ru +6 -0
- data/test/dummy/forms/bar.rb +5 -0
- data/test/dummy/forms/foo.rb +6 -0
- data/test/test.js +59 -0
- data/test/test_basic_component.rb +34 -0
- data/test/test_browserio.rb +13 -0
- data/test/test_helper.rb +38 -0
- data/wedge.gemspec +32 -0
- metadata +236 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5b5ef8331c8e2f16ac456cb505444d1e3216c6c4
|
4
|
+
data.tar.gz: 4428bcba77f4bac04352eef544889d1c406db4ae
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 74a76dc6fd77a6290920a74a4ddc8e38835904a7225c0a35233ec5ab32025b007b053f2a8f388344253ba4857b484cd8b087880f3004a3d7bc2d251b8dcd3651
|
7
|
+
data.tar.gz: 92b1d152855d4d71b19f38585f9e0108f231828742ebb16165f0567176d5247a7963f7a081777cb14159a674c1fe3012a3f5a0e633968459f2e99ffe22686f25
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 cj
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# BrowserIO
|
2
|
+
|
3
|
+
Components for Ruby.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'browserio'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install browserio
|
20
|
+
|
21
|
+
## Basic Usage
|
22
|
+
|
23
|
+
### Setup
|
24
|
+
|
25
|
+
class BasicComponent < BrowserIO::Component
|
26
|
+
setup do |config|
|
27
|
+
config.name :basic
|
28
|
+
end
|
29
|
+
|
30
|
+
def foo
|
31
|
+
'bar'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
### Call
|
36
|
+
|
37
|
+
Browser[:basic].foo
|
38
|
+
|
39
|
+
### Response
|
40
|
+
|
41
|
+
'bar'
|
42
|
+
|
43
|
+
## Contributing
|
44
|
+
|
45
|
+
1. Fork it ( https://github.com/[my-github-username]/BrowserIO/fork )
|
46
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
47
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
48
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
49
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
class Roda
|
2
|
+
module RodaPlugins
|
3
|
+
module Wedge
|
4
|
+
def self.configure(app, opts = {})
|
5
|
+
if app.opts[:wedge]
|
6
|
+
app.opts[:wedge].merge!(opts)
|
7
|
+
else
|
8
|
+
app.opts[:wedge] = opts.dup
|
9
|
+
end
|
10
|
+
|
11
|
+
opts = app.opts[:wedge]
|
12
|
+
|
13
|
+
opts.each do |k, v|
|
14
|
+
case k.to_s
|
15
|
+
when 'plugins'
|
16
|
+
v.each { |p| ::Wedge.config.plugin p }
|
17
|
+
when 'scope'
|
18
|
+
begin
|
19
|
+
::Wedge.config.scope v.new
|
20
|
+
rescue
|
21
|
+
::Wedge.config.scope v.new('')
|
22
|
+
end
|
23
|
+
else
|
24
|
+
::Wedge.config.send(k, v)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module InstanceMethods
|
30
|
+
def wedge(*args)
|
31
|
+
args << { scope: self }
|
32
|
+
::Wedge[*args]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module RequestClassMethods
|
37
|
+
def wedge_route_regex
|
38
|
+
assets_url = ::Wedge.assets_url.gsub(%r{^(http://[^\/]*\/|\/)}, '')
|
39
|
+
%r{#{assets_url}/(.*)\.(.*)$}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module RequestMethods
|
44
|
+
def wedge_assets
|
45
|
+
on self.class.wedge_route_regex do |component, ext|
|
46
|
+
case ext
|
47
|
+
when 'map'
|
48
|
+
::Wedge.source_map component
|
49
|
+
when 'rb'
|
50
|
+
if component =~ /^wedge/
|
51
|
+
path = ::Wedge.opts.file_path.gsub(/\/wedge.rb$/, '')
|
52
|
+
File.read("#{path}/#{component}.rb")
|
53
|
+
else
|
54
|
+
File.read("#{ROOT_PATH}/#{component}.rb")
|
55
|
+
end
|
56
|
+
when 'call'
|
57
|
+
body = scope.request.body.read
|
58
|
+
data = scope.request.params
|
59
|
+
|
60
|
+
begin
|
61
|
+
data.merge!(body ? JSON.parse(body) : {})
|
62
|
+
rescue
|
63
|
+
# can't be parsed by json
|
64
|
+
end
|
65
|
+
|
66
|
+
data = data.indifferent
|
67
|
+
name = data.delete(:name)
|
68
|
+
method_called = data.delete(:method_called)
|
69
|
+
method_args = data.delete(:method_args)
|
70
|
+
|
71
|
+
res = scope.wedge(name, data).send(method_called, *method_args) || ''
|
72
|
+
|
73
|
+
scope.response.headers["BIO-CSRF-TOKEN"] = scope.csrf_token if scope.methods.include? :csrf_token
|
74
|
+
|
75
|
+
if res.is_a? Hash
|
76
|
+
scope.response.headers["Content-Type"] = 'application/json; charset=UTF-8'
|
77
|
+
res = res.to_json
|
78
|
+
else
|
79
|
+
res = res.to_s
|
80
|
+
end
|
81
|
+
|
82
|
+
res
|
83
|
+
else
|
84
|
+
"#{::Wedge.javascript(component)}\n//# sourceMappingURL=/assets/wedge/#{component}.map"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
register_plugin(:wedge, Wedge)
|
92
|
+
end
|
93
|
+
end
|
data/lib/wedge.rb
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
require 'wedge/opal'
|
2
|
+
require 'wedge/version'
|
3
|
+
require 'wedge/utilis/indifferent_hash'
|
4
|
+
require 'wedge/utilis/hash'
|
5
|
+
require 'wedge/utilis/blank'
|
6
|
+
require 'wedge/utilis/methods'
|
7
|
+
require 'wedge/utilis/try'
|
8
|
+
require 'wedge/utilis/titleize'
|
9
|
+
require 'wedge/utilis/element'
|
10
|
+
require 'base64'
|
11
|
+
unless RUBY_ENGINE == 'opal'
|
12
|
+
require 'nokogiri'
|
13
|
+
require 'wedge/utilis/nokogiri'
|
14
|
+
end
|
15
|
+
require 'wedge/html'
|
16
|
+
require 'wedge/dom'
|
17
|
+
require 'wedge/config'
|
18
|
+
require 'wedge/component'
|
19
|
+
|
20
|
+
module Wedge
|
21
|
+
include Methods
|
22
|
+
|
23
|
+
class << self
|
24
|
+
attr_accessor :requires, :loaded_requires, :loaded_requires_events, :javascript_cache,
|
25
|
+
:wedge_javascript_loaded
|
26
|
+
|
27
|
+
def cache
|
28
|
+
javascript
|
29
|
+
end
|
30
|
+
|
31
|
+
def assets_url
|
32
|
+
"#{opts.assets_url}#{opts.cache_assets ? "/#{opts.assets_key}" : ''}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def script_tag
|
36
|
+
"<script src='#{assets_url}/wedge.js'></script>"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Used to call a component.
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
# Browser[:foo].bar
|
43
|
+
#
|
44
|
+
# @param name [String, Symbol, #to_s] The unique name given to a component.
|
45
|
+
# @return [Wedge::Component#method] Last line of the method called.
|
46
|
+
def [](name, *args)
|
47
|
+
component = components[name.to_sym]
|
48
|
+
|
49
|
+
component.klass.new(*args)
|
50
|
+
end
|
51
|
+
|
52
|
+
def components
|
53
|
+
@components ||= OpenStruct.new
|
54
|
+
end
|
55
|
+
|
56
|
+
unless RUBY_ENGINE == 'opal'
|
57
|
+
# Returns the build object for opal.
|
58
|
+
#
|
59
|
+
# @param path [String] require path to file to build.
|
60
|
+
# @return [String, Opal::Builder#build]
|
61
|
+
def build(path = 'wedge', options = {})
|
62
|
+
append_paths
|
63
|
+
Opal::Builder.build(path, options)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Source maps for the javascript
|
67
|
+
def source_map(path = 'wedge', options = {})
|
68
|
+
build(path, options).source_map
|
69
|
+
end
|
70
|
+
|
71
|
+
# Append the correct paths to opal.
|
72
|
+
#
|
73
|
+
# @return [Array] List of opal paths.
|
74
|
+
def append_paths
|
75
|
+
@append_paths ||= begin
|
76
|
+
file = method(:components).source_location.first.sub('/wedge.rb', '')
|
77
|
+
Wedge::Opal.append_path file
|
78
|
+
Wedge::Opal.append_path Dir.pwd
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Return the opal javascript.
|
84
|
+
def javascript(path_name = 'wedge', options = {}, promise = false)
|
85
|
+
if server?
|
86
|
+
if path_name == 'wedge'
|
87
|
+
@wedge_javascript ||= begin
|
88
|
+
@wedge_javascript_loaded = true
|
89
|
+
requires = {}
|
90
|
+
|
91
|
+
@javascript_cache ||= {}
|
92
|
+
|
93
|
+
components.to_h.each do |k, v|
|
94
|
+
requires[k] = v.klass.wedge_config.get_requires
|
95
|
+
javascript(v.klass.wedge_opts[:path_name])
|
96
|
+
end
|
97
|
+
|
98
|
+
compiled_requires = Base64.encode64 requires.to_json
|
99
|
+
assets_key = opts.assets_key
|
100
|
+
cache_assets = opts.cache_assets
|
101
|
+
|
102
|
+
js = build(path_name, options).javascript
|
103
|
+
js << Opal.compile("Wedge.instance_variable_set(:@requires, JSON.parse(Base64.decode64('#{compiled_requires}')))")
|
104
|
+
# fix: we need to just merge in all config opts and just reject
|
105
|
+
# certain ones
|
106
|
+
js << Opal.compile("Wedge.config.assets_key('#{assets_key}')") if assets_key
|
107
|
+
js << Opal.compile("Wedge.config.cache_assets('#{cache_assets}')") if cache_assets
|
108
|
+
##############################################################
|
109
|
+
js
|
110
|
+
end
|
111
|
+
else
|
112
|
+
@javascript_cache[path_name] ||= begin
|
113
|
+
js = build(path_name, options).javascript
|
114
|
+
comp_name = components.to_h.select { |k, v| v.path_name == path_name }.first.last.name
|
115
|
+
comp = Wedge[comp_name]
|
116
|
+
options = comp.client_wedge_opts
|
117
|
+
compiled_opts = Base64.encode64 options.to_json
|
118
|
+
js << Opal.compile("Wedge.components[:#{comp_name}].klass.instance_variable_set(:@wedge_config, Wedge::Config.new(Wedge.components[:#{comp_name}].klass.wedge_config.opts_dup.merge(JSON.parse(Base64.decode64('#{compiled_opts}')))))")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
else
|
122
|
+
Wedge.loaded_requires ||= []
|
123
|
+
Wedge.loaded_requires_events ||= []
|
124
|
+
reqs = Wedge.requires[options[:name].to_sym].dup
|
125
|
+
promise = Promise.new
|
126
|
+
requires = get_requires(reqs)
|
127
|
+
|
128
|
+
load_requires(requires.dup, promise)
|
129
|
+
|
130
|
+
promise.then do
|
131
|
+
load_comp(options).then do
|
132
|
+
method_called = options[:method_called]
|
133
|
+
method_args = options[:method_args]
|
134
|
+
name = options[:name]
|
135
|
+
comp = Wedge[name, options]
|
136
|
+
|
137
|
+
Document.ready? do
|
138
|
+
trigger_requires_events requires.dup
|
139
|
+
comp.send(method_called, *method_args) if method_called
|
140
|
+
comp.wedge_trigger :browser_events
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def trigger_requires_events requires
|
148
|
+
reqs = requires.shift
|
149
|
+
|
150
|
+
reqs.each do |r|
|
151
|
+
next if Wedge.loaded_requires_events.include? r[:name]
|
152
|
+
Wedge.loaded_requires_events << r[:name]
|
153
|
+
comp = Wedge[r[:name], r]
|
154
|
+
comp.wedge_trigger :browser_events
|
155
|
+
end
|
156
|
+
|
157
|
+
trigger_requires_events requires if requires.any?
|
158
|
+
end
|
159
|
+
|
160
|
+
def load_requires requires, promise = Promise.new
|
161
|
+
reqs = requires.shift
|
162
|
+
promises = []
|
163
|
+
|
164
|
+
reqs.each do |r|
|
165
|
+
next if Wedge.loaded_requires.include? r[:name]
|
166
|
+
|
167
|
+
Wedge.loaded_requires << r[:name]
|
168
|
+
|
169
|
+
promises << -> { load_comp r }
|
170
|
+
end
|
171
|
+
|
172
|
+
Promise.when(*promises.map!(&:call)).then do
|
173
|
+
requires.any?? load_requires(requires, promise) : promise.resolve(true)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def get_requires reqs, requires_array = []
|
178
|
+
new_reqs = []
|
179
|
+
|
180
|
+
reqs.each do |r|
|
181
|
+
if r[:requires].any?
|
182
|
+
get_requires(r[:requires], requires_array)
|
183
|
+
end
|
184
|
+
|
185
|
+
new_reqs << r
|
186
|
+
end
|
187
|
+
|
188
|
+
requires_array << new_reqs if new_reqs.any?
|
189
|
+
|
190
|
+
requires_array
|
191
|
+
end
|
192
|
+
|
193
|
+
def load_comp options = {}, promise = Promise.new
|
194
|
+
path_name = options[:path_name]
|
195
|
+
assets_url = Wedge.assets_url
|
196
|
+
|
197
|
+
# fix: this could give people unwanted behaviour, change getScript to just
|
198
|
+
# use ajax.
|
199
|
+
`jQuery.ajaxSetup({ cache: true })` if Wedge.opts.cache_assets
|
200
|
+
`$.getScript(assets_url + "/" + path_name + ".js").done(function(){`
|
201
|
+
promise.resolve true
|
202
|
+
`}).fail(function(jqxhr, settings, exception){ window.console.log(exception); });`
|
203
|
+
#########################################################################
|
204
|
+
|
205
|
+
promise
|
206
|
+
end
|
207
|
+
|
208
|
+
# Used to setup the component with default options.
|
209
|
+
#
|
210
|
+
# @example
|
211
|
+
# class SomeComponent < Component
|
212
|
+
# setup do |config|
|
213
|
+
# config.name :some
|
214
|
+
# end
|
215
|
+
# end
|
216
|
+
# @yield [Config]
|
217
|
+
def setup(&block)
|
218
|
+
block.call config if block_given?
|
219
|
+
end
|
220
|
+
|
221
|
+
def config
|
222
|
+
@config ||= begin
|
223
|
+
args = { klass: self }
|
224
|
+
|
225
|
+
unless RUBY_ENGINE == 'opal'
|
226
|
+
args[:file_path] = caller.first.gsub(/(?<=\.rb):.*/, '')
|
227
|
+
args[:assets_key] = ENV.fetch('SOURCE_VERSION') { `git rev-parse HEAD 2>/dev/null`.to_s.strip }
|
228
|
+
end
|
229
|
+
|
230
|
+
Config.new(args)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def opts
|
235
|
+
config.opts
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|