lib/spiderfw/widget/widget.rb in spiderfw-0.5.13 vs lib/spiderfw/widget/widget.rb in spiderfw-0.5.14

- old
+ new

@@ -9,11 +9,11 @@ class Widget < PageController include HTTPMixin attr_accessor :parent - attr_accessor :request, :scene, :widgets, :template, :id, :id_path, :containing_template, :target_mode + attr_accessor :request, :scene, :widgets, :template, :id, :id_path, :containing_template, :is_target_ancestor, :is_target_descendant attr_reader :attributes, :widget_attributes, :css_classes, :widgets_runtime_content attr_accessor :active @@common_attributes = { :id => {} @@ -24,10 +24,14 @@ cattr_reader :tag_name, :plugins def inherited(subclass) subclass.instance_variable_set(:@attributes, attributes.clone) subclass.instance_variable_set(:@scene_attributes, @scene_attributes.clone) if @scene_attributes + subclass.instance_variable_set(:@plugins, @plugins.clone) if @plugins + subclass.instance_variable_set(:@default_assets, @default_assets.clone) if @default_assets + @subclasses ||= [] + @subclasses << subclass super end def attribute(name, params={}) # TODO: implement, this is just a placeholder @@ -167,16 +171,10 @@ overrides.each do |ovr| parse_override(ovr) end Hpricot::Elements[*overrides].remove - plugins.each do |plugin| - name = plugin['name'] - mod = self.plugin(name) - next unless mod - overrides += mod.get_overrides - end return [doc.to_s, overrides] end # This method is called on each override node found. The widget must return the node, # modifying it if needed. @@ -190,52 +188,83 @@ end def add_plugin(name, mod) @plugins ||= {} @plugins[name] = mod + @subclasses.each{ |sub| sub.add_plugin(name, mod) } if @subclasses end def plugin(name) return nil unless @plugins @plugins[name] end + def default_asset(ass) + @default_assets ||= [] + @default_assets << ass + end + + def assets + r = [] + if @default_assets + @default_assets.each do |ass| + if ass.is_a?(Hash) + ass[:app] ||= self.class.app + r << ass + else + r += Spider::Template.get_named_asset(ass) + end + end + end + if @plugins + @plugins.each do |name, mod| + r += mod.get_assets + end + end + r + end + end i_attribute :use_template attribute :"sp:target-only" attribute :class + default_asset 'jquery' + default_asset 'spider' + + def initialize(request, response, scene=nil) super @is_target = false @widgets = {} @attributes = WidgetAttributes.new(self) @id_path = [] @widget_attributes = {} locale = @request.locale.language - include_js = [ - '/js/jquery/jquery-1.4.2.js', '/js/inheritance.js', '/js/spider.js', '/js/jquery/plugins/jquery.query-2.1.6.js', - '/js/jquery/plugins/jquery.form.js', - '/js/plugins/plugin.js' - ] - # include_js << [ - # '/js/jquery/jquery-ui/development-bundle/ui/jquery-ui-1.7.2.custom.js', - # #'/js/jquery/jquery-ui/development-bundle/ui/jquery-ui-1.7.2.custom.min.js', - # "/js/jquery/jquery-ui/development-bundle/ui/i18n/ui.datepicker-#{locale}.js" + # include_js = [ + # '/js/jquery/jquery-1.4.2.js', '/js/inheritance.js', '/js/spider.js', '/js/jquery/plugins/jquery.query-2.1.6.js', + # '/js/jquery/plugins/jquery.form.js', + # '/js/plugins/plugin.js' # ] - include_css = [ - '/css/spider.css', '/js/jquery/jquery-ui/css/smoothness/jquery-ui-1.7.2.custom.css', - ] + # # include_js << [ + # # '/js/jquery/jquery-ui/development-bundle/ui/jquery-ui-1.7.2.custom.js', + # # #'/js/jquery/jquery-ui/development-bundle/ui/jquery-ui-1.7.2.custom.min.js', + # # "/js/jquery/jquery-ui/development-bundle/ui/i18n/ui.datepicker-#{locale}.js" + # # ] + # include_css = [ + # '/css/spider.css', '/js/jquery/jquery-ui/css/smoothness/jquery-ui-1.7.2.custom.css', + # ] @assets = [] - include_js.each{ |js| @assets << {:type => :js, :src => Spider::Components.pub_url+js, :path => Spider::Components.pub_path+js}} - include_css.each{ |css| @assets << {:type => :css, :src => Spider::Components.pub_url+css, :path => Spider::Components.pub_path+css}} - + # include_js.each{ |js| @assets << {:type => :js, :src => Spider::Components.pub_url+js, :path => Spider::Components.pub_path+js}} + # include_css.each{ |css| @assets << {:type => :css, :src => Spider::Components.pub_url+css, :path => Spider::Components.pub_path+css}} + # @use_template ||= self.class.default_template @css_classes = [] @widgets_runtime_content = {} @widget_procs = {} + @runtime_overrides = [] end def full_id @id_path.join('-') end @@ -266,35 +295,45 @@ p = p.sub(/\/+$/, '') return p end def before(action='') - Spider.logger.debug("Widget #{self} before(#{action})") + #Spider.logger.debug("Widget #{self} before(#{action})") widget_init(action) - init_widgets unless @init_widgets_done + @before_done = true super end def widget_before(action='') - Spider.logger.debug("Widget #{self} widget_before(#{action})") + #Spider.logger.debug("Widget #{self} widget_before(#{action})") widget_init(action) + return unless active? + #Spider.logger.debug("Preparing widget #{self}") prepare prepare_scene(@scene) @before_done = true end + # Active widgets get prepared. When calling a deep widget, the ancestors will be active. def active? - - return @active unless @active.nil? - return @active = true if @is_target - return @active = false if attributes[:"sp:target-only"] == "true" - @active = (!@request.params['_wt'] || @target_mode) + return true if @active + return true unless target_mode? || attributes[:"sp:target-only"] + return true if @is_target || @is_target_ancestor + return true if @is_target_descendant && !attributes[:"sp:target-only"] + return false end + # When in target mode, a widget will be run only if it is the target, or one of its subwidgets + def run? + return true unless target_mode? || attributes[:"sp:target-only"] + return true if @is_target # || @is_target_ancestor + return true if @is_target_descendant && !attributes[:"sp:target-only"] + return false + end + def active=(val) - @active = val end def before_done? @before_done @@ -336,10 +375,11 @@ end if (@attributes[:class]) @css_classes += @attributes[:class].split(/\s+/) end end + # Recursively instantiates the subwidgets. def prepare(action='') init_widgets unless @init_widgets_done set_widget_attributes @@ -348,27 +388,43 @@ res = res.clone @assets << res end end - # Instantiates this widget's own subwidgets. def init_widgets(template=@template) + load_widgets(template) + @widgets.each do |id, w| + w.parent = self + w.is_target_descendant = true if @is_target || @is_target_descendant + w.active = true if run? + end + if !@is_target && @widget_target + first, rest = @widget_target.split('/', 2) + @_widget = find_widget(first) + @_widget.is_target_ancestor = true + @_widget.widget_target = rest + @_widget.is_target = true unless rest + @_widget_rest = rest || '' + end + @init_widgets_done = true + + end + + # Instantiates this widget's own subwidgets. + def load_widgets(template=@template) if (self.class.scene_attributes) self.class.scene_attributes.each do |name| @scene[name] = instance_variable_get("@#{name}") end end template.request = @request template.response = @response + template.runtime_overrides += @runtime_overrides template.init(@scene) template.widgets.each do |name, w| add_widget(w) end - @widgets.each do |id, w| - w.parent = self - end - @init_widgets_done = true end def set_widget_attributes @widget_attributes.each do |w_id, a| w_id_parts = w_id.to_s.split('.', 2) @@ -412,14 +468,10 @@ def did_run? @did_run end - def run? - @is_target || (!@target_mode && !attributes[:"sp:target-only"]) - end - def init_widget_done? @init_widget_done end def index @@ -428,11 +480,11 @@ end def render prepare_scene(@scene) set_scene_vars(@scene) - @template.render(@scene) unless @target_mode && !@is_target + @template.render(@scene) unless @is_target_ancestor && !@is_target end def execute(action='', *params) Spider.logger.debug("Widget #{self} executing #{action}") widget_execute = @request.params['_we'] @@ -441,19 +493,14 @@ super(widget_execute, *params) else run render end - elsif (@widget_target) - first, rest = @widget_target.split('/', 2) - @_widget = find_widget(first) - @_widget.target_mode = true - @_widget.widget_target = rest - @_widget.is_target = true unless rest + elsif (@_widget) @_widget.set_action(widget_execute) - @_widget.before(rest, *params) - @_widget.execute(rest, *params) + @_widget.before(@_widget_rest, *params) + @_widget.execute(@_widget_rest, *params) else super end end @@ -494,10 +541,12 @@ def transient_session return session(@request.session.transient, Spider::TransientHash) end def create_widget(klass, id, *params) + params.unshift(@response) + params.unshift(@request) obj = klass.new(*params) obj.id = id add_widget(obj) return obj end @@ -541,11 +590,39 @@ return if xml.empty? doc = Hpricot(xml) parse_runtime_content(doc, src_path) if doc.children && doc.root && doc.root.children end + def replace_content_vars(str, scene=nil) + scene ||= @parent && @parent.scene ? @parent.scene : @scene + res = "" + Spider::Template.scan_text(str) do |type, val, full| + case type + when :plain, :escaped_expr + res << full + when :expr + Spider::Template.scan_scene_vars(val) do |vtype, vval| + case vtype + when :plain + res << vval + when :var + res << scene[vval.to_sym].to_s + end + end + end + end + end + def parse_runtime_content(doc, src_path=nil) + doc.search('sp:plugin').each do |plugin| + # we don't call add_plugin here because the overrides don't have to be added at runtime, since + # they have already been processed when compiling the instance + name = plugin['name'].to_sym + mod = self.class.plugin(name) + next unless mod + self.extend(mod) + end # doc.search('sp:plugin').each do |plugin| # name = plugin['name'] # mod = self.class.plugin(name) # next unless mod # (class <<self; self; end).instance_eval do @@ -634,11 +711,11 @@ return nil unless w.containing_template w = w.containing_template.owner end return w end - + def prepare_scene(scene) scene = super # FIXME: owner_controller should be (almost) always defined scene.controller[:request_path] = owner_controller.request_path if owner_controller @@ -647,10 +724,15 @@ scene.widget[:is_target] = @is_target scene.widget[:is_running] = run? if (@parent && @parent.respond_to?(:scene) && @parent.scene) scene._parent = @parent.scene end + par = @parent + while par && par.is_a?(Widget) + par = par.parent + end + scene.controller_scene = par.scene if par scene.extend(WidgetScene) return scene end def set_scene_vars(scene) @@ -687,14 +769,24 @@ def with_widget(path, &proc) first, rest = path.split('/', 2) @widget_procs[first.to_sym] ||= [] @widget_procs[first.to_sym] << {:target => rest, :proc => proc } end - + def add_plugin(name) + mod = self.class.plugin(name) + return unless mod + self.extend(mod) + @runtime_overrides << [name, mod.get_overrides, mod.overrides_path] + end + end module WidgetScene + + def _wt + self[:widget][:id_path].join('/') + end def widget_target "#{self[:request][:path]}?_wt=#{self[:widget][:id_path].join('/')}" end