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