Class: Spider::Widget

Inherits:
PageController show all
Includes:
HTTPMixin
Defined in:
lib/spiderfw/widget/widget.rb

Constant Summary collapse

@@common_attributes =
{
    :id => {:process => lambda{ |val| val.gsub('-', '_')}}
}

Class Attribute Summary collapse

Instance Attribute Summary collapse

Attributes inherited from Controller

#dispatch_action, #executed_method, #is_target, #response

Attributes included from Dispatcher

#dispatch_previous

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from PageController

#get_route

Methods inherited from Controller

#action_target?, #after, before, before_methods, before_unless, #call_after, #call_before, #check_action, controller_action, controller_action?, controller_actions, default_action, #done, #done=, #done?, find_resource, find_resource_path, #get_action_method, #get_scene, http_s_url, #init, #is_target?, layout_path, #request_path, route_path, url

Methods included from Annotations

included

Methods included from Logger

add, check_request_level, close, close_all, datetime_format, datetime_format=, #debug, debug, debug?, #debug?, enquire_loggers, #error, error, #error?, error?, fatal, #fatal, fatal?, #fatal?, info, #info, info?, #info?, #log, log, method_missing, open, reopen, request_level, send_to_loggers, set_request_level, unknown, #unknown, warn, #warn, warn?, #warn?

Methods included from Dispatcher

#add_chain_item, #can_dispatch?, #dispatch, #dispatch_chain, #dispatch_next, #dispatcher_get_route, #do_dispatch, #get_route, included, #route, #routes, #run_chain

Methods included from App::AppClass

#app, included

Constructor Details

#initialize(request, response, scene = nil) ⇒ Widget

Returns a new instance of Widget.



253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/spiderfw/widget/widget.rb', line 253

def initialize(request, response, scene=nil)
    super
    @is_target = false
    @widgets = {}
    Spider::GetText.in_domain(self.class.app.short_name){
        @attributes = WidgetAttributes.new(self)
    }
    @id_path = []
    @widget_attributes = {}
    @assets = []
    @use_template ||= self.class.default_template
    @css_classes = []
    @widgets_runtime_content = {}
    @widget_procs = {}
    @runtime_overrides = []
    @_plugins = []
end

Class Attribute Details

.attributesObject (readonly)

Returns the value of attribute attributes.



23
24
25
# File 'lib/spiderfw/widget/widget.rb', line 23

def attributes
  @attributes
end

.scene_attributesObject (readonly)

Returns the value of attribute scene_attributes.



23
24
25
# File 'lib/spiderfw/widget/widget.rb', line 23

def scene_attributes
  @scene_attributes
end

Instance Attribute Details

#activeObject

Returns the value of attribute active.



16
17
18
# File 'lib/spiderfw/widget/widget.rb', line 16

def active
  @active
end

#attributesObject

Returns the value of attribute attributes.



15
16
17
# File 'lib/spiderfw/widget/widget.rb', line 15

def attributes
  @attributes
end

#containing_templateObject

Returns the value of attribute containing_template.



14
15
16
# File 'lib/spiderfw/widget/widget.rb', line 14

def containing_template
  @containing_template
end

#css_classesObject (readonly)

Returns the value of attribute css_classes.



15
16
17
# File 'lib/spiderfw/widget/widget.rb', line 15

def css_classes
  @css_classes
end

#idObject

Returns the value of attribute id.



14
15
16
# File 'lib/spiderfw/widget/widget.rb', line 14

def id
  @id
end

#id_pathObject

Returns the value of attribute id_path.



14
15
16
# File 'lib/spiderfw/widget/widget.rb', line 14

def id_path
  @id_path
end

#is_target_ancestorObject

Returns the value of attribute is_target_ancestor.



14
15
16
# File 'lib/spiderfw/widget/widget.rb', line 14

def is_target_ancestor
  @is_target_ancestor
end

#is_target_descendantObject

Returns the value of attribute is_target_descendant.



14
15
16
# File 'lib/spiderfw/widget/widget.rb', line 14

def is_target_descendant
  @is_target_descendant
end

#parentObject

Returns the value of attribute parent.



13
14
15
# File 'lib/spiderfw/widget/widget.rb', line 13

def parent
  @parent
end

#requestObject

Returns the value of attribute request.



14
15
16
# File 'lib/spiderfw/widget/widget.rb', line 14

def request
  @request
end

#sceneObject

Returns the value of attribute scene.



14
15
16
# File 'lib/spiderfw/widget/widget.rb', line 14

def scene
  @scene
end

#templateObject

Returns the value of attribute template.



14
15
16
# File 'lib/spiderfw/widget/widget.rb', line 14

def template
  @template
end

#widget_attributesObject (readonly)

Returns the value of attribute widget_attributes.



15
16
17
# File 'lib/spiderfw/widget/widget.rb', line 15

def widget_attributes
  @widget_attributes
end

#widgetsObject

Returns the value of attribute widgets.



14
15
16
# File 'lib/spiderfw/widget/widget.rb', line 14

def widgets
  @widgets
end

#widgets_runtime_contentObject (readonly)

Returns the value of attribute widgets_runtime_content.



15
16
17
# File 'lib/spiderfw/widget/widget.rb', line 15

def widgets_runtime_content
  @widgets_runtime_content
end

Class Method Details

.add_plugin(name, mod) ⇒ Object



205
206
207
208
209
# File 'lib/spiderfw/widget/widget.rb', line 205

def add_plugin(name, mod)
    @plugins ||= {}
    @plugins[name] = mod
    @subclasses.each{ |sub| sub.add_plugin(name, mod) } if @subclasses
end

.assetsObject



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/spiderfw/widget/widget.rb', line 221

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

.attr_to_scene(*names) ⇒ Object



99
100
101
102
# File 'lib/spiderfw/widget/widget.rb', line 99

def attr_to_scene(*names)
    @scene_attributes ||= []
    names.each{ |name| @scene_attributes << name }
end

.attribute(name, params = {}) ⇒ Object



50
51
52
53
54
# File 'lib/spiderfw/widget/widget.rb', line 50

def attribute(name, params={})
    # TODO: implement, this is just a placeholder
    @attributes ||= @@common_attributes.clone
    @attributes[name] = params
end

.attribute?(name) ⇒ Boolean

Returns:

  • (Boolean)


60
61
62
# File 'lib/spiderfw/widget/widget.rb', line 60

def attribute?(name)
    @attributes[name.to_sym]
end

.default_asset(ass) ⇒ Object



216
217
218
219
# File 'lib/spiderfw/widget/widget.rb', line 216

def default_asset(ass)
    @default_assets ||= []
    @default_assets << ass
end

.default_template(val = nil) ⇒ Object



129
130
131
132
133
# File 'lib/spiderfw/widget/widget.rb', line 129

def default_template(val=nil)
    @default_template = val if val
    @default_template ||= Spider::Inflector.underscore(self.name).split('/')[-1]
    @default_template
end

.get_scene_elementsObject



118
119
120
# File 'lib/spiderfw/widget/widget.rb', line 118

def get_scene_elements
    @scene_elements
end

.i_attr_accessor(name, params = {}) ⇒ Object



85
86
87
88
89
90
# File 'lib/spiderfw/widget/widget.rb', line 85

def i_attr_accessor(name, params={})
    params[:instance_attr] = true
    params[:ruby_name] = name.to_s.gsub('-', '_').to_sym
    i_attribute(name, params)
    attr_accessor(params[:ruby_name])
end

.i_attribute(name, params = {}) ⇒ Object



64
65
66
67
68
69
70
# File 'lib/spiderfw/widget/widget.rb', line 64

def i_attribute(name, params={})
    params[:instance_attr] = true
    params[:ruby_name] = name.to_s.gsub('-', '_').to_sym
    params[:set_var] = true
    attribute(name, params)
    attr_reader(params[:ruby_name])
end

.inherited(subclass) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/spiderfw/widget/widget.rb', line 26

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
    # Do some magic to try and infer the widget's path, considering intermediate superclass callers
    cnt = 0
    s = subclass.superclass
    while s != Spider::Widget
        if caller[cnt].split(':')[-1] =~ /inherited/
            cnt += 1
        end
        s = s.superclass

    end
    raise "Unable to determine widget file" unless caller[cnt] =~ /(.+):(\d+)(:in .+)?$/
    file = $1
    subclass.instance_variable_set("@widget_path", File.dirname(file))
end

.is_attr_accessor(name, params = {}) ⇒ Object



92
93
94
95
96
97
# File 'lib/spiderfw/widget/widget.rb', line 92

def is_attr_accessor(name, params={})
    params[:instance_attr] = true
    params[:ruby_name] = name.to_s.gsub('-', '_').to_sym
    is_attribute(name, params)
    attr_accessor(params[:ruby_name])
end

.is_attribute(name, params = {}) ⇒ Object



72
73
74
75
76
77
78
# File 'lib/spiderfw/widget/widget.rb', line 72

def is_attribute(name, params={})
    params[:instance_attr] = true
    params[:ruby_name] = name.to_s.gsub('-', '_').to_sym
    i_attribute(name, params)
    attr_to_scene(params[:ruby_name])
    attr_reader(params[:ruby_name])
end

.override_tagsObject

An array of custom tags that will be processed at compile time by the widget.



201
202
203
# File 'lib/spiderfw/widget/widget.rb', line 201

def override_tags
    return []
end

.parse_content(doc) ⇒ Object

Parses widget content at compile time. Must return a pair consisting of:

  • runtime content XML

  • an array of overrides (as Hpricot nodes)



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/spiderfw/widget/widget.rb', line 171

def parse_content(doc)
    overrides = []
    plugins = []
    to_del = []
    doc.root.each_child do |child|
        if child.respond_to?(:name)
            namespace, short_name = child.name.split(':', 2)
            if (namespace == 'tpl' && (Spider::Template.override_tags.include?(short_name) || self.override_tags.include?(child.name)))
                overrides << child unless child.is_a?(Hpricot::BogusETag)
            end
            if (child.name == 'sp:plugin')
                plugins << child
            end
        end
    end
    overrides.each do |ovr|
        parse_override(ovr)
    end

    Hpricot::Elements[*overrides].remove
    return [doc.to_s, overrides]
end

.parse_content_xml(xml) ⇒ Object



162
163
164
165
# File 'lib/spiderfw/widget/widget.rb', line 162

def parse_content_xml(xml)
    return ["", []] if !xml || xml.strip.empty?
    return parse_content(Hpricot("<sp:widget-content>#{xml}</sp:widget-content>"))
end

.parse_override(el) ⇒ Object

This method is called on each override node found. The widget must return the node, modifying it if needed.



196
197
198
# File 'lib/spiderfw/widget/widget.rb', line 196

def parse_override(el)
    return el
end

.plugin(name) ⇒ Object



211
212
213
214
# File 'lib/spiderfw/widget/widget.rb', line 211

def plugin(name)
    return nil unless @plugins
    @plugins[name]
end

.pub_pathObject



154
155
156
# File 'lib/spiderfw/widget/widget.rb', line 154

def pub_path
    self.app.pub_path
end

.pub_urlObject



143
144
145
146
147
148
149
150
151
152
# File 'lib/spiderfw/widget/widget.rb', line 143

def pub_url
    return self.app.pub_url
    w = self
    # FIXME! this is a quick hack to make extended templates work
    # but what we need is a better method to handle asset ownership
    #
    # Is it needed anymore?
    # w = w.superclass while w.superclass != Spider::Widget && w.superclass.subclass_of?(Spider::Widget)
    w.route_url+'/pub'
end

.register_tag(name) ⇒ Object



109
110
111
# File 'lib/spiderfw/widget/widget.rb', line 109

def register_tag(name)
    Spider::Template.register(name, self)
end

.relative_urlObject



135
136
137
# File 'lib/spiderfw/widget/widget.rb', line 135

def relative_url
    ::File.dirname(@widget_path)
end

.route_urlObject



139
140
141
# File 'lib/spiderfw/widget/widget.rb', line 139

def route_url
    Spider::ControllerMixins::HTTPMixin.reverse_proxy_mapping('/'+self.app.route_url+'/w/'+relative_url)
end

.runtime_content_tagsObject



158
159
160
# File 'lib/spiderfw/widget/widget.rb', line 158

def 
    ['sp:attribute']
end

.s_attribute(name, params = {}) ⇒ Object



80
81
82
83
# File 'lib/spiderfw/widget/widget.rb', line 80

def s_attribute(name, params={})
    attribute(name, params)
    attr_to_scene(name)
end

.scene_elements(*list) ⇒ Object



113
114
115
116
# File 'lib/spiderfw/widget/widget.rb', line 113

def scene_elements(*list)
    @scene_elements ||= []
    @scene_elements += list
end

.tag(name) ⇒ Object



104
105
106
107
# File 'lib/spiderfw/widget/widget.rb', line 104

def tag(name)
    self.app.register_tag(name, self)
    @tag_name ||= name
end

.template_pathObject



122
123
124
125
126
127
# File 'lib/spiderfw/widget/widget.rb', line 122

def template_path
    return @template_path if @template_path
    @template_path = @widget_path
    @template_path += '/templates' if @template_path && ::File.directory?(@template_path+'/templates')
    @template_path
end

Instance Method Details

#active?Boolean

Active widgets get prepared. When calling a deep widget, the ancestors will be active.

Returns:

  • (Boolean)


322
323
324
325
326
327
328
# File 'lib/spiderfw/widget/widget.rb', line 322

def active?
    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

#add_plugin(name) ⇒ Object



792
793
794
795
796
797
798
# File 'lib/spiderfw/widget/widget.rb', line 792

def add_plugin(name)
    mod = self.class.plugin(name)
    return unless mod
    self.extend(mod)
    @_plugins << mod
    @runtime_overrides << [name, mod.get_overrides, mod.overrides_path]
end

#add_widget(widget) ⇒ Object



570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
# File 'lib/spiderfw/widget/widget.rb', line 570

def add_widget(widget)
    widget.id_path = @id_path + [widget.id]
    widget.parent = self
    # widget.active = true if @is_target || @active
    @widgets[widget.id.to_sym] = widget
    if (@widgets_runtime_content[widget.id.to_sym])
        @widgets_runtime_content[widget.id.to_sym].each do |content|
            if (content[:widget])
                first, rest = content[:widget].split('/', 2)
                content[:widget] = rest
                widget.widgets_runtime_content[first.to_sym] ||= [] 
                widget.widgets_runtime_content[first.to_sym] << content
            else
                next if (content[:params] && !check_subwidget_conditions(widget, content[:params]))
                widget.parse_runtime_content_xml(content[:xml])
            end
        end
    end
    if (@widget_procs[widget.id.to_sym])
        @widget_procs[widget.id.to_sym].each do |wp|
            if (wp[:target])
                widget.with_widget(wp[:target], &wp[:proc])
            else
                widget.instance_eval(&wp[:proc])
            end
        end
    end
    widget
end

#assetsObject



710
711
712
713
# File 'lib/spiderfw/widget/widget.rb', line 710

def assets
    res = @assets.clone + widget_assets
    return res
end

#before(action = '') ⇒ Object



301
302
303
304
305
306
# File 'lib/spiderfw/widget/widget.rb', line 301

def before(action='')
    #Spider.logger.debug("Widget #{self} before(#{action})")
    widget_init(action)
    @before_done = true
    super
end

#before_done?Boolean

Returns:

  • (Boolean)


342
343
344
# File 'lib/spiderfw/widget/widget.rb', line 342

def before_done?
    @before_done
end

#check_subwidget_conditionsObject



600
601
602
# File 'lib/spiderfw/widget/widget.rb', line 600

def check_subwidget_conditions
    return false
end

#controller_action?(method) ⇒ Boolean

Returns:

  • (Boolean)


800
801
802
803
804
805
806
807
# File 'lib/spiderfw/widget/widget.rb', line 800

def controller_action?(method)
    r = super
    return r if r
    @_plugins.each do |pl|
        return r if r = pl.controller_action?(method)
    end
    return false
end

#create_widget(klass, id, *params) ⇒ Object



560
561
562
563
564
565
566
567
568
# File 'lib/spiderfw/widget/widget.rb', line 560

def create_widget(klass, id,  *params)
    klass = Spider::Template.get_registered_class(klass) unless klass.is_a?(Class)
    params.unshift(@response)
    params.unshift(@request)
    obj = klass.new(*params)
    obj.id = id
    add_widget(obj)
    return obj
end

#css_classObject



763
764
765
766
767
# File 'lib/spiderfw/widget/widget.rb', line 763

def css_class
    return @css_class if @css_class
    supers = self.class.ancestors.select{ |c| c != Spider::Widget && c.subclass_of?(Spider::Widget)}
    @css_class = Inflector.underscore(supers.join('/')).gsub('_', '-').gsub('/', ' ').split(' ').uniq.join(' ')
end

#css_model_class(model) ⇒ Object



769
770
771
# File 'lib/spiderfw/widget/widget.rb', line 769

def css_model_class(model)
    "model-#{model.name.gsub('::', '-')}"
end

#did_run?Boolean

Returns:

  • (Boolean)


474
475
476
# File 'lib/spiderfw/widget/widget.rb', line 474

def did_run?
    @did_run
end

#do_runObject



487
488
489
490
491
# File 'lib/spiderfw/widget/widget.rb', line 487

def do_run
    Spider::GetText.in_domain(self.class.app.short_name){
        run
    }
end

#execute(action = '', *params) ⇒ Object



501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
# File 'lib/spiderfw/widget/widget.rb', line 501

def execute(action='', *params)
    Spider.logger.debug("Widget #{self} executing #{action}")
    Spider::GetText.in_domain(self.class.app.short_name){
        widget_execute = @request.params['_we']
        if (@is_target)
            if (widget_execute)
                super(widget_execute, *params)
            else
                do_run
                render
            end
        elsif (@_widget)
            @_widget.set_action(widget_execute)
            @_widget.before(@_widget_rest, *params)
            @_widget.execute(@_widget_rest, *params)
        else
            super
        end
    }
end

#find_widget(name) ⇒ Object



781
782
783
# File 'lib/spiderfw/widget/widget.rb', line 781

def find_widget(name)
    @widgets[name.to_sym] || super
end

#flashObject



551
552
553
554
# File 'lib/spiderfw/widget/widget.rb', line 551

def flash
    s = session(@request.session.flash, Spider::FlashHash)
    return s
end

#full_idObject



271
272
273
# File 'lib/spiderfw/widget/widget.rb', line 271

def full_id
    @id_path.join('-')
end

#has_params?Boolean

Returns:

  • (Boolean)


540
541
542
# File 'lib/spiderfw/widget/widget.rb', line 540

def has_params?
    !params.empty?
end

#indexObject



482
483
484
485
# File 'lib/spiderfw/widget/widget.rb', line 482

def index
    do_run
    render
end

#init_widget_done?Boolean

Returns:

  • (Boolean)


478
479
480
# File 'lib/spiderfw/widget/widget.rb', line 478

def init_widget_done?
    @init_widget_done
end

#init_widgets(template = @template) ⇒ Object



397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
# File 'lib/spiderfw/widget/widget.rb', line 397

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)
        raise "#{self} couldn't find widget #{first} for target #{@widget_target}" unless @_widget
        @_widget.is_target_ancestor = true
        @_widget.widget_target = rest
        @_widget.is_target = true unless rest
        @_widget_rest = rest || ''
    end
    @init_widgets_done = true
    
end

#inspectObject



773
774
775
# File 'lib/spiderfw/widget/widget.rb', line 773

def inspect
    super + ", id: #{@id}"
end

#load_widgets(template = @template) ⇒ Object

Instantiates this widget’s own subwidgets.



418
419
420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/spiderfw/widget/widget.rb', line 418

def load_widgets(template=@template)
    if self.class.scene_attributes
        self.class.scene_attributes.each do |name|
            @scene[name] = instance_variable_get("@#{name}") || attributes[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
end

#local_idObject



275
276
277
# File 'lib/spiderfw/widget/widget.rb', line 275

def local_id
    @id_path.last
end

#owner_controllerObject



724
725
726
727
728
729
730
731
# File 'lib/spiderfw/widget/widget.rb', line 724

def owner_controller
    w = self
    while (w.is_a?(Widget) && w.template && w.template.owner)
        return nil unless w.containing_template
        w = w.containing_template.owner
    end
    return w
end

#paramsObject



530
531
532
533
534
535
536
537
538
# File 'lib/spiderfw/widget/widget.rb', line 530

def params
    p = @request.params['_w']
    return {} unless p
    @id_path.each do |id| 
        p = p[id.to_s]
        return {} unless p
    end
    return p
end

#parse_runtime_content(doc, src_path = nil) ⇒ Object



631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
# File 'lib/spiderfw/widget/widget.rb', line 631

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
    #         debugger
    #         include mod
    #     end
    #     shadow = (class <<self; self; end)
    #     
    #     debugger
    #     a = 3
    # end
    doc.search('sp:runtime-content').each do |cont|
        w = cont.get_attribute('widget')
        first, rest = w.split('/', 2)
        params = nil
        if (first =~ /(.+)\[(.+)\]/)
            params = {}
            parts = $2.split(',')
            parts.each do |p|
                key, val = p.split('=')
                params[key] = val
            end
        end
        if (w)
            @widgets_runtime_content[first.to_sym] ||= []
            @widgets_runtime_content[first.to_sym] << {
                :widget => rest,
                :xml => "<sp:widget-content>#{cont.innerHTML}</sp:widget-content>",
                :params => params
            }
        end
    end
    doc.search('sp:runtime-content').remove
    
    attributes = doc.search('sp:attribute')
    attributes.each do |a|
        name = a.get_attribute('name').to_sym
        kvs = a.children ? a.children_of_type('sp:value') : []
        if (kvs.length > 0)
            value = {}
            kvs.each do |kv|
                key = kv.get_attribute('key')
                val = kv.innerText
                value[key] = val
            end
        else
            value = a.get_attribute('value')
        end
        if w = a.get_attribute('widget')
            @widget_attributes[w] ||= {}
            @widget_attributes[w][name] = value
        else
            @attributes[name] = value
        end
    end
    attributes.remove
    doc.search('sp:use-template').each do |templ|
        if templ.has_attribute?('app')
            owner = Spider.apps_by_path[templ.get_attribute('app')]
        else
            owner = self
        end
        @template = load_template(templ.get_attribute('src'), nil, owner)
    end
    return doc
end

#parse_runtime_content_xml(xml, src_path = nil) ⇒ Object



605
606
607
608
609
# File 'lib/spiderfw/widget/widget.rb', line 605

def parse_runtime_content_xml(xml, src_path=nil)
    return if xml.empty?
    doc = Hpricot(xml)
    parse_runtime_content(doc, src_path) if doc.children && doc.root && doc.root.children
end

#prepare(action = '') ⇒ Object

Recursively instantiates the subwidgets.



387
388
389
390
391
392
393
394
395
# File 'lib/spiderfw/widget/widget.rb', line 387

def prepare(action='')
    init_widgets unless @init_widgets_done
    set_widget_attributes
    prepare_widgets
    @template.assets.each do |res|
        res = res.clone
        @assets << res
    end
end

#prepare_scene(scene) ⇒ Object



733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
# File 'lib/spiderfw/widget/widget.rb', line 733

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
    scene.widget[:request_path] = widget_request_path
    scene.widget[:target_only] = attributes[:"sp:target-only"]
    scene.widget[:is_target] = @is_target
    scene.widget[:is_running] = run?
    scene.widget[:id] = @id
    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

#prepare_widgetsObject

Runs widget_before on all subwidgets.



452
453
454
455
456
457
458
459
460
461
# File 'lib/spiderfw/widget/widget.rb', line 452

def prepare_widgets
    r = route_widget
    @widgets.each do |id, w|
        if (r && r[0].to_sym == id)
            act = r[1]
        end
        act ||= ''
        w.widget_before(act)
    end
end

#renderObject



493
494
495
496
497
498
499
# File 'lib/spiderfw/widget/widget.rb', line 493

def render
    Spider::GetText.in_domain(self.class.app.short_name){
        prepare_scene(@scene)
        set_scene_vars(@scene)
        @template.render(@scene) unless @is_target_ancestor && !@is_target 
    }
end

#replace_content_vars(str, scene = nil) ⇒ Object



611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
# File 'lib/spiderfw/widget/widget.rb', line 611

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

#route_widgetObject



286
287
288
# File 'lib/spiderfw/widget/widget.rb', line 286

def route_widget
    return nil
end

#run(action = '') ⇒ Object



464
465
466
467
468
469
470
471
472
# File 'lib/spiderfw/widget/widget.rb', line 464

def run(action='')
    @widgets.each do |wname, w|
        w.do_run if w.run?
    end
    if (@parent)
        @parent.after_widget(@id.to_sym)
    end
    @did_run = true
end

#run?Boolean

When in target mode, a widget will be run only if it is the target, or one of its subwidgets

Returns:

  • (Boolean)


331
332
333
334
335
336
# File 'lib/spiderfw/widget/widget.rb', line 331

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

#session(container = @request.session, klass = Hash) ⇒ Object



544
545
546
547
548
549
# File 'lib/spiderfw/widget/widget.rb', line 544

def session(container=@request.session, klass=Hash)
    s = (container['_w'] ||= klass.new)
    @id_path[0..-2].each{ |id| s = (s[id] ||= klass.new) }
    s = (s[@id_path[-1]] ||= klass.new)
    return s
end

#set_scene_vars(scene) ⇒ Object



755
756
757
758
759
760
761
# File 'lib/spiderfw/widget/widget.rb', line 755

def set_scene_vars(scene)
    if self.class.scene_attributes # Repeat for new instance variables
        self.class.scene_attributes.each do |name|
            @scene[name] = instance_variable_get("@#{name}") || attributes[name]
        end
    end
end

#set_widget_attributesObject



433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
# File 'lib/spiderfw/widget/widget.rb', line 433

def set_widget_attributes
    @widget_attributes.each do |w_id, a|
        w_id_parts = w_id.to_s.split('.', 2)
        if (w_id_parts[1])
            w_id = w_id_parts[0]
            sub_w = w_id_parts[1]
        end
        w_id = w_id.to_sym
        if (@widgets[w_id])
            if (sub_w)
                @widgets[w_id].widget_attributes[sub_w] = a
            else
                a.each{ |key, value| @widgets[w_id].attributes[key] = value}
            end
        end
    end
end

#to_sObject



777
778
779
# File 'lib/spiderfw/widget/widget.rb', line 777

def to_s
    super + ", id: #{@id}"
end

#transient_sessionObject



556
557
558
# File 'lib/spiderfw/widget/widget.rb', line 556

def transient_session
    return session(@request.session.transient, Spider::TransientHash)
end

#try_rescue(exc) ⇒ Object



522
523
524
525
526
527
528
# File 'lib/spiderfw/widget/widget.rb', line 522

def try_rescue(exc)
    if (exc.is_a?(NotFound))
        error("Widget path not found: #{exc.path}")
    else
        raise exc
    end
end

#widget_assetsObject



715
716
717
718
719
720
721
# File 'lib/spiderfw/widget/widget.rb', line 715

def widget_assets
    res = []
    @widgets.each do |id, w|
        res += w.assets
    end
    return res
end

#widget_before(action = '') ⇒ Object



308
309
310
311
312
313
314
315
316
317
318
# File 'lib/spiderfw/widget/widget.rb', line 308

def widget_before(action='')
    Spider::GetText.in_domain(self.class.app.short_name){
        widget_init(action)
        if active?
            prepare_scene(@scene)
            prepare
            @before_done = true
        end
    }

end

#widget_init(action = '') ⇒ Object

Loads the template and sets the widget attributes



347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
# File 'lib/spiderfw/widget/widget.rb', line 347

def widget_init(action='')
    action ||= ''
    if (@request.params['_wa'] && @request.params['_wa'][full_id])
        action = @request.params['_wa'][full_id]
    end
    @_action = action
    @_action_local, @_action_rest = action.split('/', 2)
    unless @template
        @template = load_template(@use_template)
    end
    prepare_template(@template)
    @id ||= @attributes[:id]
    @template.id_path = @id_path
    @template.mode = :widget
    required_groups = {}
    self.class.attributes.each do |k, params|
        if (params[:required])
            if (params[:required] == true && !@attributes[k])
                raise ArgumentError, "Attribute #{k} is required by widget #{self}"
            else
                if (!@attributes[k] && required_groups[params[:required]] != false)
                    required_groups[params[:required]] ||= []
                    required_groups[params[:required]] << k
                else
                    required_groups[params[:required]] = false
                end
            end 
        end
    end
    required_groups.each do |group_name, attributes|
        next if attributes == false
        raise ArgumentError, "Widget #{self} requires attribute #{attributes.join(' or ')} to be set"
    end
    if (@attributes[:class])
        @css_classes += @attributes[:class].split(/\s+/)
    end
end

#widget_request_pathObject



294
295
296
297
298
299
# File 'lib/spiderfw/widget/widget.rb', line 294

def widget_request_path
    p = @request.path
    p = p.sub(/\/#{Regexp.escape(@_action)}$/, '') unless @_action.blank?
    p = p.sub(/\/+$/, '')
    return p
end

#widget_target=(target) ⇒ Object



290
291
292
# File 'lib/spiderfw/widget/widget.rb', line 290

def widget_target=(target)
    @widget_target = target
end

#with_widget(path, &proc) ⇒ Object

FIXME: is the same in template. Refactor out.



786
787
788
789
790
# File 'lib/spiderfw/widget/widget.rb', line 786

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