diff --git a/app/javascript/vue_r.rb b/app/javascript/vue_r.rb new file mode 100644 index 0000000..baf4b4c --- /dev/null +++ b/app/javascript/vue_r.rb @@ -0,0 +1,2 @@ +require "vue_r/application" +require "vue_r/mounter" diff --git a/app/javascript/vue_r/application.rb b/app/javascript/vue_r/application.rb new file mode 100644 index 0000000..b89d570 --- /dev/null +++ b/app/javascript/vue_r/application.rb @@ -0,0 +1,67 @@ +module VueR + class Application + + def initialize(hash) + hash.each do |k,v| + wrap_attr(k,v) + end + @effect = nil + @subscribers = {} + end + + def wrap_attr(k,v) + instance_variable_set "@#{k}" , v + define_getter(k) + define_setter(k) + end + + def define_getter(k) + self.class.define_method k.to_sym do + track(k) + instance_variable_get "@#{k}".to_sym + end + end + + def define_setter(k) + self.class.define_method "#{k}=".to_sym do |new_v| + instance_variable_set "@#{k}" , new_v + trigger(k) + end + end + + def track( key ) + puts "Tracking:#{key}-#{@effect.hash}" + return unless @effect + get_subscribers_for(key) << @effect + end + + def trigger(key) + puts "Trigger:#{key}" + effects = get_subscribers_for(key) + effects.each {|effect| effect.call() } + end + + def get_subscribers_for(key) + key = key.to_sym + unless @subscribers.has_key?(key) + @subscribers[key] = Set.new + end + @subscribers[key] + end + + def mount(on_class) + @mounter = Mounter.new(on_class , self) + @mounter.mount + end + + def watch_effect( update_proc ) + effect = Proc.new do + @effect = effect + update_proc.call + @effect = nil + end + effect.call + end + + end +end diff --git a/app/javascript/vue_r/mounter.rb b/app/javascript/vue_r/mounter.rb new file mode 100644 index 0000000..61da525 --- /dev/null +++ b/app/javascript/vue_r/mounter.rb @@ -0,0 +1,64 @@ +require 'opal-parser' + +module VueR + class Mounter + HANDLEBARS = /{{\s?([^}]*)\s?}}/ + def initialize( id , app ) + @root = $document[id] + @application = app + end + + def mount + mount_Element(@root) + end + + def mount_Text elem + text = elem.text + scan = text.scan(HANDLEBARS) + return unless scan.length > 0 + raise "only one curly per text implemented not:#{scan.length}" if scan.length > 1 + match = text.match(HANDLEBARS) + str_before = text[0 ... match.begin(0)] + str_after = text[ match.end(0) .. -1] + ruby = match[0][2 ... -2] + puts "Text: #{ruby}" + proc = Proc.new do + elem.text = str_before + @application.eval(ruby).to_s + str_after + end + @application.watch_effect(proc) + end + + def mount_Element(elem) + elem.attributes.each do |name , value| + mount_attribute(elem , name) if name.start_with?("r_") + mount_event(elem , name) if name.start_with?("e_") + end + elem.children.each do |elem| + base_name = elem.class.to_s.split("::").last + send "mount_#{base_name}" , elem + end + end + + def mount_attribute(element , name) + native_name = name[2 .. -1] + ruby = element[name] + old_value = element[native_name] + puts "Attribute: #{ruby}" + proc = Proc.new do + element[native_name] = old_value + " " + @application.eval(ruby).to_s + end + @application.watch_effect(proc) + end + + + def mount_event(element , name) + native_name = name.gsub("e_" , "") + ruby = element[name] + puts "Event: #{native_name}:#{ruby}" + element.on!(native_name) do + got = @application.eval(ruby) + puts "Clicked #{got}" + end + end + end +end diff --git a/test/dummy/app/views/images/_form.html.haml b/test/dummy/app/views/images/_form.html.haml new file mode 100644 index 0000000..99b17e7 --- /dev/null +++ b/test/dummy/app/views/images/_form.html.haml @@ -0,0 +1,10 @@ += form_for @kantum do |f| + - if @kantum.errors.any? + #error_explanation + %h2= "#{pluralize(@kantum.errors.count, "error")} prohibited this kantum from being saved:" + %ul + - @kantum.errors.full_messages.each do |message| + %li= message + + .actions + = f.submit 'Save' diff --git a/test/dummy/app/views/images/edit.html.haml b/test/dummy/app/views/images/edit.html.haml new file mode 100644 index 0000000..d2becac --- /dev/null +++ b/test/dummy/app/views/images/edit.html.haml @@ -0,0 +1,7 @@ +%h1 Editing kantum + += render 'form' + += link_to 'Show', @kantum +\| += link_to 'Back', kanta_path diff --git a/test/dummy/app/views/images/index.html.haml b/test/dummy/app/views/images/index.html.haml new file mode 100644 index 0000000..fe2ed70 --- /dev/null +++ b/test/dummy/app/views/images/index.html.haml @@ -0,0 +1,19 @@ +%h1 Listing kanta + +%table + %thead + %tr + %th + %th + %th + + %tbody + - @kanta.each do |kantum| + %tr + %td= link_to 'Show', kantum + %td= link_to 'Edit', edit_kantum_path(kantum) + %td= link_to 'Destroy', kantum, method: :delete, data: { confirm: 'Are you sure?' } + +%br + += link_to 'New Kantum', new_kantum_path diff --git a/test/dummy/app/views/images/new.html.haml b/test/dummy/app/views/images/new.html.haml new file mode 100644 index 0000000..0524e57 --- /dev/null +++ b/test/dummy/app/views/images/new.html.haml @@ -0,0 +1,5 @@ +%h1 New kantum + += render 'form' + += link_to 'Back', kanta_path diff --git a/test/dummy/app/views/images/show.html.haml b/test/dummy/app/views/images/show.html.haml new file mode 100644 index 0000000..c127eb1 --- /dev/null +++ b/test/dummy/app/views/images/show.html.haml @@ -0,0 +1,19 @@ +#app + .flex.justify-center + = #@image.attributes + + .flex.justify-center + %a.underline{ e_click: "bg_change" , r_class: 'back'} + {{ back }} +:opal + class Clicker < VueR::Application + def bg_change + self.state = !self.state + end + def back + self.state ? "bg-cyan-50" : "bg-cyan-200" + end + end + + kanta = Clicker.new(bg: 'bg-cyan-200' , state: true) + kanta.mount("#app")