browserio 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,326 +0,0 @@
1
- module BrowserIO
2
- class Component
3
- include Methods
4
-
5
- REJECTED_CLIENT_OPTS = %i(scope file_path methods_wrapped events klass on on_server_methods added_class_events)
6
-
7
- class << self
8
- # Override the default new behaviour
9
- def new(*args, &block)
10
- obj = allocate
11
-
12
- obj.bio_opts.js = args.delete(:js)
13
- obj.bio_opts.init = args.delete(:init)
14
-
15
- # Merge other args into opts
16
- args.each { |a| a.each {|k, v| obj.bio_opts[k] = v } } if args.any?
17
-
18
- # Set all the requires
19
- unless RUBY_ENGINE == 'opal'
20
- obj.bio_opts.requires = obj.bio_config.get_requires
21
- end
22
-
23
- obj.bio_opts.events.scope = obj
24
-
25
- # Set all the on events
26
- obj.bio_opts.on.each do |*a, &b|
27
- obj.bio_opts.events.add(*a.first.first, &a.first.last)
28
- end
29
- bio_opts.added_class_events = true
30
-
31
- if obj.bio_opts.init
32
- if obj.bio_opts.init.is_a? Array
33
- obj.send :initialize, *obj.bio_opts.init, &block
34
- else
35
- obj.send :initialize, obj.bio_opts.init, &block
36
- end
37
- else
38
- obj.send :initialize, &block
39
- end
40
-
41
- unless bio_opts.methods_wrapped
42
- obj.bio_opts.methods_wrapped = bio_opts.methods_wrapped = true
43
-
44
- public_instance_methods(false).each do |meth|
45
- alias_method :"bio_original_#{meth}", :"#{meth}"
46
- define_method "#{meth}" do |*d_args, &blk|
47
- if bio_opts.js
48
- bio_opts.method_called = meth
49
- bio_opts.method_args = *d_args
50
- end
51
-
52
- o_name = "bio_original_#{meth}"
53
-
54
- if client? || method(o_name).parameters.length > 0
55
- result = send(o_name, *d_args, &blk)
56
- else
57
- result = send(o_name, &blk)
58
- end
59
-
60
- # Append the initialize javscript
61
- if server? && opts.js
62
- result = result.to_html if result.is_a? DOM
63
- result << bio_javascript
64
- end
65
-
66
- result
67
- end
68
- end
69
- end
70
-
71
- obj
72
- end
73
-
74
- # Used to setup the component with default options.
75
- #
76
- # @example
77
- # class SomeComponent < Component
78
- # setup do |config|
79
- # config.name :some
80
- # end
81
- # end
82
- # @yield [Config]
83
- def bio_setup(&block)
84
- block.call bio_config
85
- end
86
- alias_method :setup, :bio_setup
87
-
88
- # Set templates
89
- #
90
- # @example
91
- # tmpl :some_name, dom.find('#some-div')
92
- # @return dom [DOM]
93
- def bio_tmpl(name, dom = false, remove = true)
94
- if dom
95
- dom = remove ? dom.remove : dom
96
- bio_opts.tmpl[name] = {
97
- dom: dom,
98
- html: dom.to_html
99
- }
100
- elsif t = bio_opts.tmpl[name]
101
- dom = DOM.new t[:html]
102
- else
103
- false
104
- end
105
-
106
- dom
107
- end
108
- alias_method :tmpl, :bio_tmpl
109
-
110
- def bio_dom
111
- @bio_dom ||= DOM.new bio_opts.html
112
- end
113
- alias_method :dom, :bio_dom
114
-
115
- # Shortcut for BrowserIO.components
116
- #
117
- # @return [Hash, BrowserIO.components]
118
- def bio_components
119
- BrowserIO.components ||= {}
120
- end
121
- alias_method :components, :bio_components
122
-
123
- # Shortcut for the Config#opts
124
- #
125
- # @return [Openstruct, Config#opts]
126
- def bio_opts
127
- bio_config.opts
128
- end
129
- alias_method :opts, :bio_opts
130
-
131
- def bio_config
132
- @bio_config ||= begin
133
- args = BrowserIO.config.opts_dup.merge(klass: self, object_events: {})
134
-
135
- if server?
136
- args[:file_path] = caller.first.gsub(/(?<=\.rb):.*/, '')
137
- args[:path_name] = args[:file_path]
138
- .gsub(%r{(#{Dir.pwd}/|.*(?=browserio))}, '')
139
- .gsub(/\.rb$/, '')
140
- end
141
-
142
- c = Config.new(args)
143
-
144
- # If extending from a plugin it will automatically require it.
145
- ancestors.each do |klass|
146
- next if klass.to_s == name.to_s
147
-
148
- if klass.method_defined?(:bio_opts) && klass.bio_opts.name.to_s =~ /_plugin$/
149
- c.requires klass.bio_opts.name
150
- end
151
- end
152
-
153
- c
154
- end
155
- end
156
- alias_method :config, :bio_config
157
-
158
- def bio_on(*args, &block)
159
- if args.first.to_s != 'server'
160
- bio_opts.on << [args, block]
161
- else
162
- bio_on_server(&block)
163
- end
164
- end
165
- alias_method :on, :bio_on
166
-
167
- def method_missing(method, *args, &block)
168
- if bio_opts.scope.respond_to?(method, true)
169
- bio_opts.scope.send method, *args, &block
170
- else
171
- super
172
- end
173
- end
174
-
175
- def client_bio_opts
176
- bio_config.opts_dup.reject {|k, v| REJECTED_CLIENT_OPTS.include? k }
177
- end
178
-
179
- def bio_on_server(&block)
180
- if server?
181
- yield
182
- else
183
- m = Module.new(&block)
184
-
185
- m.public_instance_methods(false).each do |meth|
186
- bio_opts.on_server_methods << meth.to_s
187
-
188
- define_method "#{meth}" do |*args, &blk|
189
- path_name = bio_opts.path_name
190
- # event_id = "comp-event-#{$faye.generate_id}"
191
-
192
- payload = client_bio_opts.reject do |k, _|
193
- %w(html tmpl requires plugins object_events).include? k
194
- end
195
- payload[:method_called] = meth
196
- payload[:method_args] = args
197
-
198
- HTTP.post("/#{bio_opts.assets_url}/#{path_name}.call",
199
- headers: {
200
- 'X-CSRF-TOKEN' => Element.find('meta[name=_csrf]').attr('content')
201
- },
202
- payload: payload) do |response|
203
-
204
- # We set the new csrf token
205
- xhr = Native(response.xhr)
206
- csrf = xhr.getResponseHeader('BIO-CSRF-TOKEN')
207
- Element.find('meta[name=_csrf]').attr 'content', csrf
208
- ###########################
209
-
210
- res = JSON.from_object(`response`)
211
-
212
- blk.call res[:body], res
213
- end
214
-
215
- true
216
- end
217
- end
218
-
219
- include m
220
- end
221
- end
222
- end
223
-
224
- # Duplicate of class condig [Config]
225
- # @return config [Config]
226
- def bio_config
227
- @bio_config ||= begin
228
- c = Config.new(self.class.bio_config.opts_dup.merge(events: Events.new))
229
- c.opts.events.object_events = c.opts.object_events.dup
230
- c.opts.object_events = {}
231
- c
232
- end
233
- end
234
- alias_method :config, :bio_config
235
-
236
- # Duplicated of config.opts [Config#opts]
237
- # @return opts [Config#opts]
238
- def bio_opts
239
- bio_config.opts
240
- end
241
- alias_method :opts, :bio_opts
242
-
243
- # Grab a copy of the template
244
- # @return dom [DOM]
245
- def bio_tmpl(name)
246
- self.class.bio_tmpl name
247
- end
248
- alias_method :tmpl, :bio_tmpl
249
-
250
- # Dom
251
- # @return bio_dom [Dom]
252
- def bio_dom
253
- @bio_dom ||= begin
254
- if server?
255
- DOM.new self.class.bio_dom.to_html
256
- else
257
- DOM.new(Element)
258
- end
259
- end
260
- end
261
- alias_method :dom, :bio_dom
262
-
263
- # Special method that acts like the javascript equivalent
264
- # @example
265
- # foo = {
266
- # bar: function { |moo|
267
- # moo.call 'something'
268
- # }
269
- # }.to_n
270
- def bio_function(*args, &block)
271
- args.any? && raise(ArgumentError, '`function` does not accept arguments')
272
- block || raise(ArgumentError, 'block required')
273
- proc do |*a|
274
- a.map! {|x| Native(`x`)}
275
- @this = Native(`this`)
276
- %x{
277
- var bs = block.$$s,
278
- result;
279
- block.$$s = null;
280
- result = block.apply(self, a);
281
- block.$$s = bs;
282
-
283
- return result;
284
- }
285
- end
286
- end
287
- alias_method :function, :bio_function
288
-
289
- def bio_javascript
290
- return unless server?
291
-
292
- compiled_opts = Base64.encode64 client_bio_opts.to_json
293
- name = bio_opts.file_path.gsub("#{Dir.pwd}/", '').gsub(/\.rb$/, '')
294
-
295
- javascript = <<-JS
296
- BrowserIO.javascript('#{name}', JSON.parse(Base64.decode64('#{compiled_opts}')))
297
- JS
298
- "<script>#{Opal.compile(javascript)}</script>"
299
- end
300
- alias_method :javscript, :bio_javascript
301
-
302
- def client_bio_opts
303
- bio_config.opts_dup.reject {|k, v| REJECTED_CLIENT_OPTS.include? k }
304
- end
305
- alias_method :client_opts, :client_bio_opts
306
-
307
- def bio_trigger(*args)
308
- bio_opts.events.trigger(*args)
309
- end
310
- alias_method :trigger, :bio_trigger
311
-
312
- if RUBY_ENGINE == 'opal'
313
- def bio(*args)
314
- BrowserIO[*args]
315
- end
316
- end
317
-
318
- def method_missing(method, *args, &block)
319
- if bio_opts.scope.respond_to?(method, true)
320
- bio_opts.scope.send method, *args, &block
321
- else
322
- super
323
- end
324
- end
325
- end
326
- end
@@ -1,120 +0,0 @@
1
- require 'ostruct'
2
- require 'browserio/events'
3
-
4
- module BrowserIO
5
- class Config
6
- include Methods
7
-
8
- # Stores the options for the config
9
- #
10
- # @return [OpenStruct]
11
- attr_accessor :opts
12
-
13
- # Setup initial opts values
14
- #
15
- # @param opts [Hash] The initial params for #opts.
16
- def initialize(opts = {})
17
- opts = {
18
- tmpl: IndifferentHash.new,
19
- scope: false,
20
- loaded: false,
21
- requires: [],
22
- on: [],
23
- on_server_methods: [],
24
- object_events: {},
25
- is_plugin: false,
26
- plugins: []
27
- }.merge opts
28
-
29
- @opts = OpenStruct.new(opts)
30
- end
31
-
32
- # Set the unique name of the component
33
- #
34
- # @param name [<String, Symbol>, #to_sym]
35
- def name(name)
36
- opts.name = name.to_sym
37
- opts.is_plugin = true if name.to_s =~ /_plugin$/
38
- BrowserIO.components ||= {}
39
- BrowserIO.components[opts.name] = opts
40
- end
41
-
42
- def is_plugin?
43
- opts.is_plugin
44
- end
45
-
46
- %w(scope assets_url).each do |m|
47
- define_method m do |v|
48
- opts[m] = v
49
- end
50
- end
51
-
52
- # Used to set and update the dom
53
- def dom
54
- if server?
55
- yield
56
- end
57
- end
58
-
59
- # Set the raw html
60
- # @param html [String]
61
- def html(html)
62
- unless RUBY_ENGINE == 'opal'
63
- opts.html = begin
64
- File.read html
65
- rescue
66
- html
67
- end.strip
68
- end
69
- end
70
-
71
- def requires(*args)
72
- unless RUBY_ENGINE == 'opal'
73
- args.each do |a|
74
- if a.to_s[/_plugin$/]
75
- require "browserio/plugins/#{a.to_s.gsub(/_plugin$/, '')}"
76
- end
77
- opts.requires << a
78
- end
79
- end
80
- end
81
-
82
- def opts_dup
83
- opts.to_h.inject({}) {|copy, (key, value)| copy[key] = value.dup rescue value; copy}
84
- end
85
-
86
- def plugin(name)
87
- unless RUBY_ENGINE == 'opal'
88
- require "browserio/plugins/#{name}"
89
- end
90
- end
91
-
92
- def get_requires(requires = false, previous_requires = [])
93
- list = []
94
-
95
- unless requires
96
- requires ||= opts.requires.dup
97
- previous_requires << opts.name.to_sym
98
- end
99
-
100
- previous_requires.each { |p| requires.delete(p) }
101
-
102
- requires.each do |r|
103
- klass = BrowserIO.components[r.to_sym].klass
104
- o = klass.client_bio_opts.select do |k, v|
105
- %w(path_name name assets_url requires).include? k.to_s
106
- end
107
-
108
- # We don't want to get a stack limit error so we stop something
109
- # requiring itself
110
- pr = previous_requires.dup << o[:name].to_sym
111
-
112
- o[:requires] = get_requires o[:requires].dup, pr if o[:requires].present?
113
-
114
- list << o
115
- end
116
-
117
- list
118
- end
119
- end
120
- end
@@ -1,139 +0,0 @@
1
- module BrowserIO
2
- class DOM
3
- include Methods
4
-
5
- attr_accessor :dom, :raw_html
6
-
7
- class << self
8
- # Shortcut for creating dom
9
- # @param html [String]
10
- # @return dom [DOM]
11
- def [] html
12
- new html
13
- end
14
- end
15
-
16
- def initialize html
17
- @raw_html = html
18
-
19
- if server?
20
- @dom = raw_html.is_a?(String) ? HTML[raw_html.dup] : raw_html
21
- else
22
- @dom = raw_html.is_a?(String) ? Element[raw_html.dup] : raw_html
23
- end
24
- end
25
-
26
- def find string, &block
27
- if client?
28
- node = DOM.new dom.find(string)
29
- elsif server?
30
- if block_given?
31
- node = DOM.new dom.css(string)
32
- else
33
- node = DOM.new dom.at(string)
34
- end
35
- end
36
-
37
- if block_given?
38
- node.each_with_index do |n, i|
39
- block.call DOM.new(n), i
40
- end
41
- end
42
-
43
- node
44
- end
45
-
46
- if RUBY_ENGINE == 'ruby'
47
- def data key = false, value = false
48
- d = Hash[node.xpath("@*[starts-with(name(), 'data-')]").map{|a| [a.name, a.value]}]
49
-
50
- if !key
51
- d
52
- elsif key && !value
53
- d[key]
54
- else
55
- node["data-#{key}"] = value
56
- end
57
- end
58
-
59
- def val value
60
- node.content = value
61
- end
62
-
63
- def add_class classes
64
- classes = (classes || '').split ' ' unless classes.is_a? Array
65
- new_classes = ((node.attr('class') || '').split(' ') << classes).uniq.join(' ')
66
- node['class'] = new_classes
67
- end
68
-
69
- def remove_class classes
70
- classes = (classes || '').split ' ' unless classes.is_a? Array
71
- (node.attr('class') || '').split(' ').reject { |n| n =~ /active|asc|desc/i }.join(' ')
72
- end
73
-
74
- def attr key, value = false
75
- if value
76
- value = value.join ' ' if value.is_a? Array
77
- node[key] = value
78
- else
79
- super key
80
- end
81
- end
82
- end
83
-
84
- def html= content
85
- if server?
86
- node.inner_html = content
87
- else
88
- content = content.dom if content.is_a? BrowserIO::DOM
89
- node.html content
90
- end
91
-
92
- node
93
- end
94
-
95
- if RUBY_ENGINE == 'opal'
96
- # make it supply the jquery element so it will use that as it doesn't
97
- # know how to handle the DOM element.
98
- %w(append prepend replace_with after before).each do |meth|
99
- define_method meth do |obj|
100
- obj = obj.dom if obj.is_a? BrowserIO::DOM
101
- super obj
102
- end
103
- end
104
-
105
- def to_html
106
- @dom ||= DOM.new '<div>'
107
- el = dom.first
108
- DOM.new('<div>').append(el).html
109
- end
110
- end
111
-
112
- def html content = false
113
- if !content
114
- if server?
115
- node.inner_html
116
- else
117
- node ? node.html : dom.html
118
- end
119
- else
120
- self.html = content
121
- end
122
- end
123
-
124
- def node
125
- @node || dom
126
- end
127
-
128
- # This allows you to use all the nokogiri or opal jquery methods if a
129
- # global one isn't set
130
- def method_missing method, *args, &block
131
- # respond_to?(symbol, include_all=false)
132
- if dom.respond_to? method, true
133
- dom.send method, *args, &block
134
- else
135
- super
136
- end
137
- end
138
- end
139
- end