pakyow-presenter/lib/presenter/view.rb in pakyow-presenter-0.6.3.1 vs pakyow-presenter/lib/presenter/view.rb in pakyow-presenter-0.7.0

- old
+ new

@@ -1,24 +1,28 @@ module Pakyow module Presenter class View class << self - attr_accessor :binders, :cache, :default_view_path, :default_is_root_view + attr_accessor :binders, :default_view_path, :default_is_root_view def view_path(dvp, dirv=false) self.default_view_path = dvp self.default_is_root_view = dirv end end attr_accessor :doc - + + def dup + self.class.new(@doc.dup) + end + def initialize(arg=nil, is_root_view=false) arg = self.class.default_view_path if arg.nil? && self.class.default_view_path is_root_view = self.class.default_is_root_view if arg.nil? && self.class.default_is_root_view - if arg.is_a?(Nokogiri::XML::Element) + if arg.is_a?(Nokogiri::XML::Element) || arg.is_a?(Nokogiri::XML::Document) @doc = arg elsif arg.is_a?(Pakyow::Presenter::Views) @doc = arg.first.doc.dup elsif arg.is_a?(Pakyow::Presenter::View) @doc = arg.doc.dup @@ -26,22 +30,15 @@ if arg[0, 1] == '/' view_path = "#{Configuration::Presenter.view_dir}#{arg}" else view_path = "#{Configuration::Presenter.view_dir}/#{arg}" end - # Only load one time if view caching is enabled - self.class.cache ||= {} - - if !self.class.cache.has_key?(view_path) || !Configuration::Base.presenter.view_caching - if is_root_view then - self.class.cache[view_path] = Nokogiri::HTML::Document.parse(File.read(view_path)) - else - self.class.cache[view_path] = Nokogiri::HTML.fragment(File.read(view_path)) - end + if is_root_view then + @doc = Nokogiri::HTML::Document.parse(File.read(view_path)) + else + @doc = Nokogiri::HTML.fragment(File.read(view_path)) end - - @doc = self.class.cache[view_path].dup else raise ArgumentError, "No View for you! Come back, one year." end end @@ -89,12 +86,12 @@ def in_context(&block) ViewContext.new(self).instance_eval(&block) end - def bind(object, type = nil) - type = type || StringUtils.underscore(object.class.name) + def bind(object, opts = {}) + bind_as = opts[:to] ? opts[:to].to_s : StringUtils.underscore(object.class.name.split('::').last) @doc.traverse do |o| if attribute = o.get_attribute('itemprop') selector = attribute elsif attribute = o.get_attribute('name') @@ -103,36 +100,30 @@ next end next unless attribute - if selector.include?('[') - type_len = type.length - object_type = selector[0,type_len] - attribute = selector[type_len + 1, attribute.length - type_len - 2] - else - object_type = nil - attribute = selector - end + type_len = bind_as.length + next if selector[0, type_len + 1] != "#{bind_as}[" - next if !object_type.nil? && object_type != type + attribute = selector[type_len + 1, attribute.length - type_len - 2] binding = { :element => o, :attribute => attribute.to_sym, :selector => selector } - bind_object_to_binding(object, binding, object_type.nil?) + bind_object_to_binding(object, binding, bind_as) end end - def repeat_for(objects, &block) + def repeat_for(objects, opts = {}, &block) if o = @doc objects.each do |object| view = View.new(self) - view.bind(object) + view.bind(object, opts) ViewContext.new(view).instance_exec(object, &block) if block_given? o.add_previous_sibling(view.doc) end @@ -237,36 +228,28 @@ def append(content) self.doc.add_child(Nokogiri::HTML.fragment(content.to_s)) end alias :render :append - - def +(value) - if @previous_method - append_value(val) - else - super - end - end - - def <<(value) - if @previous_method - append_value(val) - else - super - end - end - + def method_missing(method, *args) return unless @previous_method == :attributes @previous_method = nil if method.to_s.include?('=') attribute = method.to_s.gsub('=', '') value = args[0] - self.doc[attribute] = value + if value.is_a? Proc + value = value.call(self.doc[attribute]) + end + + if value.nil? + self.doc.remove_attribute(attribute) + else + self.doc[attribute] = value + end else return self.doc[method.to_s] end end @@ -296,47 +279,41 @@ elements end protected - def append_value(value_to_append) - case @previous_method - when :content - append(value_to_append) - end - - @previous_method = nil - end - - def bind_object_to_binding(object, binding, wild = false) + def bind_object_to_binding(object, binding, bind_as) binder = nil - # fetch value - if object.is_a? Hash - value = object[binding[:attribute]] + if View.binders + b = View.binders[bind_as.to_sym] and binder = b.new(object, binding[:element]) + end + + if binder && binder.class.method_defined?(binding[:attribute]) + value = binder.send(binding[:attribute]) else - if View.binders - b = View.binders[object.class.to_s.to_sym] and binder = b.new(object, binding[:element]) - end - - if binder && binder.class.method_defined?(binding[:attribute]) - value = binder.send(binding[:attribute]) + if object.is_a? Hash + value = object[binding[:attribute]] else - if wild && !object.class.method_defined?(binding[:attribute]) - return - elsif Configuration::Base.app.dev_mode == true && !object.class.method_defined?(binding[:attribute]) + if Configuration::Base.app.dev_mode == true && !object.class.method_defined?(binding[:attribute]) Log.warn("Attempting to bind object to #{binding[:html_tag]}#{binding[:selector].gsub('*', '').gsub('\'', '')} but #{object.class.name}##{binding[:attribute]} is not defined.") return else value = object.send(binding[:attribute]) end end end if value.is_a? Hash value.each do |k, v| - if k == :content + if v.is_a? Proc + v = v.call(binding[:element][k.to_s]) + end + + if v.nil? + binding[:element].remove_attribute(k.to_s) + elsif k == :content bind_value_to_binding(v, binding, binder) else binding[:element][k.to_s] = v.to_s end end @@ -380,10 +357,10 @@ end else binding[:element].inner_html = Nokogiri::HTML.fragment(value.to_s) end elsif binding[:element].name == 'input' && binding[:element][:type] == 'checkbox' - if value == true || binding[:element].attributes['value'].value == value.to_s + if value == true || (binding[:element].attributes['value'] && binding[:element].attributes['value'].value == value.to_s) binding[:element]['checked'] = 'checked' else binding[:element].delete('checked') end elsif binding[:element].name == 'input' && binding[:element][:type] == 'radio'