Class: Wedge::Component

Inherits:
Object show all
Includes:
Methods
Defined in:
lib/wedge/component.rb

Direct Known Subclasses

Plugins::Form, Plugins::History, Plugins::Pjax

Constant Summary collapse

ALLOWED_CLIENT_OPTS =
%i(name path_name method_args method_called cache tmpl key cache_assets assets_key assets_url assets_url_with_host requires skip_method_wrap on_server_methods)

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Methods

#client?, included, #server?

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object



381
382
383
384
385
386
387
# File 'lib/wedge/component.rb', line 381

def method_missing(method, *args, &block)
  if wedge_opts.scope.respond_to?(method, true)
    wedge_opts.scope.send method, *args, &block
  else
    super
  end
end

Class Method Details

.client_wedge_optsObject



185
186
187
# File 'lib/wedge/component.rb', line 185

def client_wedge_opts
  wedge_config.opts_dup.select {|k, v| ALLOWED_CLIENT_OPTS.include? k }
end

.configObject



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/wedge/component.rb', line 166

def wedge_config
  @wedge_config ||= begin
    args = Wedge.config.opts_dup.merge(klass: self, object_events: {})

    unless RUBY_ENGINE == 'opal'
      args[:file_path] = caller.first.gsub(/(?<=\.rb):.*/, '')
      args[:path_name] = args[:file_path]
        .gsub(%r{(#{Dir.pwd}/|.*(?=wedge))}, '')
        .gsub(/\.rb$/, '')
    end

    c = Config.new(args)

    # If extending from a plugin it will automatically require it.
    ancestors.each do |klass|
      next if klass.to_s == name.to_s

      if klass.method_defined?(:wedge_opts) && klass.wedge_opts.name.to_s =~ /_plugin$/
        c.requires klass.wedge_opts.name
      end
    end

    c
  end
end

.domObject



123
124
125
# File 'lib/wedge/component.rb', line 123

def wedge_dom
  @wedge_dom ||= DOM.new wedge_opts.html
end

.method_missing(method, *args, &block) ⇒ Object



177
178
179
180
181
182
183
# File 'lib/wedge/component.rb', line 177

def method_missing(method, *args, &block)
  if wedge_opts.scope.respond_to?(method, true)
    wedge_opts.scope.send method, *args, &block
  else
    super
  end
end

.new(*args, &block) ⇒ Object

Override the default new behaviour



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/wedge/component.rb', line 9

def new(*args, &block)
  obj                 = allocate
  obj.wedge_opts.js   = args.delete(:js)
  obj.wedge_opts.init = args.delete(:init)

  if args.any? && obj.wedge_opts.skip_method_wrap
    obj.wedge_opts.init = args
  end

  # Merge other args into opts
  args.each { |a| a.each {|k, v| obj.wedge_opts[k] = v } } if args.any?

  obj.wedge_opts.events.scope = obj

  # Set all the on events
  obj.wedge_opts.on.each do |*a, &b|
    obj.wedge_opts.events.add(*a.first.first, &a.first.last)
  end
  wedge_opts.added_class_events = true

  if obj.wedge_opts.init
    if obj.wedge_opts.init.is_a? Array
      obj.send :initialize, *obj.wedge_opts.init, &block
    else
      obj.send :initialize, obj.wedge_opts.init, &block
    end
  else
    obj.send :initialize, &block
  end

  # don't need to wrap the method if it's opal
  unless RUBY_ENGINE == 'opal' || wedge_opts.methods_wrapped || wedge_opts.skip_method_wrap
    obj.wedge_opts.methods_wrapped = wedge_opts.methods_wrapped = true

    public_instance_methods(false).each do |meth|
      alias_method :"wedge_original_#{meth}", :"#{meth}"
      define_method "#{meth}" do |*d_args, &blk|
        if server? && !wedge_opts.method_called && wedge_opts.js
          wedge_opts.method_called = meth
          wedge_opts.method_args   = *d_args
        end

        o_name = "wedge_original_#{meth}"

        if client? || method(o_name).parameters.length > 0
          result = send(o_name, *d_args, &blk)
        else
          result = send(o_name, &blk)
        end

        # Append the initialize javscript
        if server? && meth == wedge_opts.method_called && opts.js
          result = result.to_html if result.is_a? DOM
          result << wedge_javascript if result.is_a? String
        end

        result
      end
    end
  end

  if obj.wedge_opts.call
    method_args = args.first
    method_called = method_args.delete(:call)

    if method_args.any?
      obj.send(method_called, method_args)
    else
      obj.send(method_called)
    end
  else
    obj
  end
end

.optsOpenstruct, Config#opts

Shortcut for the Config#opts

Returns:



139
140
141
# File 'lib/wedge/component.rb', line 139

def wedge_opts
  wedge_config.opts
end

.tmplObject

Set templates

Examples:

tmpl :some_name, dom.find('#some-div')


118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/wedge/component.rb', line 118

def wedge_tmpl(name, dom = false, remove = true)
  if dom
    dom = remove ? dom.remove : dom
    wedge_opts.tmpl[name] = {
      dom:  dom,
      html: dom.to_html
    }
  elsif t = wedge_opts.tmpl[name]
    dom = DOM.new t[:html]
  else
    false
  end

  dom
end

.wedge_componentsHash, Wedge.components Also known as: components

Shortcut for Wedge.components

Returns:



128
129
130
# File 'lib/wedge/component.rb', line 128

def wedge_components
  Wedge.components ||= {}
end

.wedge_configObject



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/wedge/component.rb', line 141

def wedge_config
  @wedge_config ||= begin
    args = Wedge.config.opts_dup.merge(klass: self, object_events: {})

    unless RUBY_ENGINE == 'opal'
      args[:file_path] = caller.first.gsub(/(?<=\.rb):.*/, '')
      args[:path_name] = args[:file_path]
        .gsub(%r{(#{Dir.pwd}/|.*(?=wedge))}, '')
        .gsub(/\.rb$/, '')
    end

    c = Config.new(args)

    # If extending from a plugin it will automatically require it.
    ancestors.each do |klass|
      next if klass.to_s == name.to_s

      if klass.method_defined?(:wedge_opts) && klass.wedge_opts.name.to_s =~ /_plugin$/
        c.requires klass.wedge_opts.name
      end
    end

    c
  end
end

.wedge_domObject



120
121
122
# File 'lib/wedge/component.rb', line 120

def wedge_dom
  @wedge_dom ||= DOM.new wedge_opts.html
end

.wedge_on(*args, &block) ⇒ Object Also known as: on



168
169
170
171
172
173
174
# File 'lib/wedge/component.rb', line 168

def wedge_on(*args, &block)
  if args.first.to_s != 'server'
    wedge_opts.on << [args, block]
  else
    wedge_on_server(&block)
  end
end

.wedge_on_server(&block) ⇒ Object



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/wedge/component.rb', line 189

def wedge_on_server(&block)
  if server?
    m = Module.new(&block)

    yield

    m.public_instance_methods(false).each do |meth|
      wedge_opts.on_server_methods << meth.to_s

      alias_method :"wedge_on_server_#{meth}", :"#{meth}"
      define_method "#{meth}" do |*args, &blk|
        o_name = "wedge_on_server_#{meth}"

        if method(o_name).parameters.length > 0
          result = send(o_name, *args, &block)
        else
          result = send(o_name, &block)
        end

        blk ? blk.call(result) : result
      end
    end
  else
    m = Module.new(&block)

    m.public_instance_methods(false).each do |meth|
      wedge_opts.on_server_methods << meth.to_s

      define_method "#{meth}" do |*args, &blk|
        path_name = wedge_opts.path_name
        # event_id = "comp-event-#{$faye.generate_id}"

        payload = client_wedge_opts.reject do |k, _|
          %w(html tmpl requires plugins object_events js_loaded).include? k
        end
        payload[:wedge_name]          = payload[:name]
        payload[:wedge_method_called] = meth
        payload[:wedge_method_args]   = args

        call_url = "#{Wedge.assets_url}/#{path_name}.call"

        HTTP.post(call_url,
          headers: {
            'X-CSRF-TOKEN' => Element.find('meta[name=_csrf]').attr('content'),
            'X-WEDGE-METHOD-REQUEST' => true
          },
          payload: payload) do |response|

            # We set the new csrf token
            xhr  = Native(response.xhr)
            csrf = xhr.getResponseHeader('WEDGE-CSRF-TOKEN')
            Element.find('meta[name=_csrf]').attr 'content', csrf
            ###########################

            res = JSON.from_object(`response`)

            blk.call res[:body], res
        end

        true
      end
    end

    include m
  end
end

.wedge_optsOpenstruct, Config#opts

Shortcut for the Config#opts

Returns:



136
137
138
# File 'lib/wedge/component.rb', line 136

def wedge_opts
  wedge_config.opts
end

.wedge_setup {|Config| ... } ⇒ Object Also known as: setup

Used to setup the component with default options.

Examples:

class SomeComponent < Component
  setup do |config|
    config.name :some
  end
end

Yields:



93
94
95
# File 'lib/wedge/component.rb', line 93

def wedge_setup(&block)
  block.call wedge_config
end

.wedge_tmpl(name, dom = false, remove = true) ⇒ Object

Set templates

Examples:

tmpl :some_name, dom.find('#some-div')


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/wedge/component.rb', line 103

def wedge_tmpl(name, dom = false, remove = true)
  if dom
    dom = remove ? dom.remove : dom
    wedge_opts.tmpl[name] = {
      dom:  dom,
      html: dom.to_html
    }
  elsif t = wedge_opts.tmpl[name]
    dom = DOM.new t[:html]
  else
    false
  end

  dom
end

Instance Method Details

#client_wedge_optsObject Also known as: client_opts



355
356
357
# File 'lib/wedge/component.rb', line 355

def client_wedge_opts
  wedge_config.opts_dup.select {|k, v| ALLOWED_CLIENT_OPTS.include? k }
end

#wedge(*args) ⇒ Object



376
377
378
# File 'lib/wedge/component.rb', line 376

def wedge(*args)
  Wedge[*args]
end

#wedge_cacheObject Also known as: cache



262
263
264
# File 'lib/wedge/component.rb', line 262

def wedge_cache
  wedge_opts[:cache]
end

#wedge_configObject Also known as: config

Duplicate of class condig [Config]



269
270
271
272
273
274
275
276
# File 'lib/wedge/component.rb', line 269

def wedge_config
  @wedge_config ||= begin
    c = Config.new(self.class.wedge_config.opts_dup.merge(events: Events.new))
    c.opts.events.object_events = c.opts.object_events.dup
    c.opts.object_events = {}
    c
  end
end

#wedge_domObject Also known as: dom

Dom



295
296
297
298
299
300
301
302
303
# File 'lib/wedge/component.rb', line 295

def wedge_dom
  @wedge_dom ||= begin
    if server?
      DOM.new self.class.wedge_dom.to_html
    else
      DOM.new(Element)
    end
  end
end

#wedge_from_client?Boolean Also known as: from_client?

Returns:

  • (Boolean)


337
338
339
# File 'lib/wedge/component.rb', line 337

def wedge_from_client?
  !wedge_from_server?
end

#wedge_from_server?Boolean Also known as: from_server?

Returns:

  • (Boolean)


332
333
334
# File 'lib/wedge/component.rb', line 332

def wedge_from_server?
  !scope.respond_to?(:request) || (request && !request.env.include?('HTTP_X_WEDGE_METHOD_REQUEST'))
end

#wedge_function(*args, &block) ⇒ Object Also known as: function

Special method that acts like the javascript equivalent

Examples:

foo = {
  bar: function { |moo|
    moo.call 'something'
  }
}.to_n


313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/wedge/component.rb', line 313

def wedge_function(*args, &block)
  args.any? && raise(ArgumentError, '`function` does not accept arguments')
  block || raise(ArgumentError, 'block required')
  proc do |*a|
    a.map! {|x| Native(`x`)}
    @this = Native(`this`)
    %x{
     var bs = block.$$s,
        result;
      block.$$s = null;
      result = block.apply(self, a);
      block.$$s = bs;

      return result;
    }
  end
end

#wedge_javascriptObject Also known as: javscript



342
343
344
345
346
347
348
349
350
351
352
# File 'lib/wedge/component.rb', line 342

def wedge_javascript
  return unless server?

  compiled_opts = Base64.encode64 client_wedge_opts.to_json
  name          = wedge_opts.file_path.gsub("#{Dir.pwd}/", '').gsub(/\.rb$/, '')

  javascript = <<-JS
    Wedge.javascript('#{name}', JSON.parse(Base64.decode64('#{compiled_opts}')))
  JS
  "<script>#{Opal.compile(javascript)}</script>"
end

#wedge_optsObject Also known as: opts

Duplicated of config.opts [Config#opts]



281
282
283
# File 'lib/wedge/component.rb', line 281

def wedge_opts
  wedge_config.opts
end

#wedge_scopeObject Also known as: scope



257
258
259
# File 'lib/wedge/component.rb', line 257

def wedge_scope
  wedge_opts[:scope]
end

#wedge_super(*args, &block) ⇒ Object



365
366
367
368
369
370
371
372
373
# File 'lib/wedge/component.rb', line 365

def wedge_super *args, &block
  if server?
    caller_str = "#{caller[0]}"
    calling_method = (caller_str =~ /`([^']*)'/ and $1)
    self.class.superclass.instance_method(:"wedge_original_#{calling_method}").bind(self).call(*args, &block)
  else
    super *args, &block
  end
end

#wedge_tmpl(name) ⇒ Object Also known as: tmpl

Grab a copy of the template



288
289
290
# File 'lib/wedge/component.rb', line 288

def wedge_tmpl(name)
  self.class.wedge_tmpl name
end

#wedge_trigger(*args) ⇒ Object Also known as: trigger



360
361
362
# File 'lib/wedge/component.rb', line 360

def wedge_trigger(*args)
  wedge_opts.events.trigger(*args)
end