require 'opal' require 'opal-jquery' unless RUBY_ENGINE == 'opal' require 'tilt' if defined? Oga require 'roda/component/oga' end end require "base64" require 'roda/component/faye' require 'roda/component/instance' require 'roda/component/dom' require 'roda/component/events' if RUBY_ENGINE == 'opal' class Element alias_native :val alias_native :serialize_array, :serializeArray end $component_opts ||= { events: {}, comp: {}, cache: {}, tmpl: {} } end class Roda class Component attr_accessor :scope, :cache def initialize(scope = false) @scope = scope if client? $faye.subscribe "/components/#{self.class._name}" do |msg| msg = Native(msg) trigger :"#{msg[:type]}", msg['local'], msg unless $faye.public_id == msg[:public_id] end $faye.on 'transport:up' do $faye.online = true if $faye.disconnected trigger :reconnect else trigger :connect end end $faye.on 'transport:down' do $faye.disconnected = true $faye.online = false trigger :disconnect end end end class << self attr_accessor :_name if RUBY_ENGINE == 'ruby' def inherited(subclass) super # We want to set the app for all sub classes subclass.set_app app end end def on_server &block if server? yield else m = Module.new(&block) m.public_instance_methods(false).each do |meth| define_method "#{meth}" do |*args, &blk| name = self.class._name # event_id = "comp-event-#{$faye.generate_id}" HTTP.post("/components/#{name}/call/#{meth}", headers: { 'X-CSRF-TOKEN' => Element.find('meta[name=_csrf]').attr('content'), 'X-RODA-COMPONENT-ON-SERVER' => true }, payload: args.first) do |response| # We set the new csrf token xhr = Native(response.xhr) csrf = xhr.getResponseHeader('NEW-CSRF') Element.find('meta[name=_csrf]').attr 'content', csrf ########################### blk.call Native(response.body), response end # Element['body'].on event_id do |event, local, data| # blk.call local, event, data # end # # $faye.publish("/components/outgoing/#{$faye.private_id}/#{$faye.public_id}", { # name: name, # type: 'event', # event_type: 'call', # event_method: meth, # event_id: event_id, # local: args.first || nil # }) true end end include m end end # The name of the component alias_method :name_original, :name def comp_name(_name = nil) return name_original unless _name @_name = _name.to_s if server? component_opts[:class_name][@_name] = self.to_s end end # The html source def comp_html _html, &block if server? if _html.is_a? String if _html[%r{\A./}] cache[:html] = File.read _html else cache[:html] = File.read "#{component_opts[:path]}/#{_html}" end else cache[:html] = yield end cache[:dom] = DOM.new(cache[:html]) end end def HTML raw_html if raw_html[/\A