Class: Spider::Template

Inherits:
Object show all
Includes:
Logger
Defined in:
lib/spiderfw/templates/template.rb

Overview

This class manages SHTML templates.

Direct Known Subclasses

Layout

Constant Summary collapse

ExpressionOutputRegexp =
/\{?\{\s([^\s].*?)\s\}\}?/
GettextRegexp =
/_\(([^\)]+)?\)(\s%\s([^\s,]+(?:,\s*\S+\s*)?))?/
ERBRegexp =
/(<%(.+)?%>)/
SceneVarRegexp =
/@(\w[\w\d_]+)/
@@registered =
{}
@@widget_plugins =
{}
@@namespaces =
{}
@@overrides =
['content', 'override', 'override-content', 'override-attr', 'append-attr',
'append', 'prepend', 'delete', 'before', 'after']
@@asset_types =
{
    :css => {},
    :js => {},
    :less => {:processor => :Less}
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Logger

add, 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?, method_missing, open, reopen, send_to_loggers, unknown, #unknown, #warn, warn, warn?, #warn?

Constructor Details

#initialize(path = nil) ⇒ Template

Returns a new instance of Template.



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/spiderfw/templates/template.rb', line 221

def initialize(path=nil)
    @path = path
    @widgets = {}
    @subtemplates = {}
    @widget_templates = []
    @subtemplate_owners = {}
    @id_path = []
    @assets = []
    @content = {}
    @dependencies = []
    @overrides = []
    @widgets_overrides = {}
    @widget_procs = {}
    @runtime_overrides = []
end

Instance Attribute Details

#_actionObject

Returns the value of attribute _action.



24
25
26
# File 'lib/spiderfw/templates/template.rb', line 24

def _action
  @_action
end

#_action_toObject

Returns the value of attribute _action_to.



24
25
26
# File 'lib/spiderfw/templates/template.rb', line 24

def _action_to
  @_action_to
end

#_widget_actionObject

Returns the value of attribute _widget_action.



24
25
26
# File 'lib/spiderfw/templates/template.rb', line 24

def _widget_action
  @_widget_action
end

#asset_profilesObject

Returns the value of attribute asset_profiles.



31
32
33
# File 'lib/spiderfw/templates/template.rb', line 31

def asset_profiles
  @asset_profiles
end

#assetsObject

Returns the value of attribute assets.



28
29
30
# File 'lib/spiderfw/templates/template.rb', line 28

def assets
  @assets
end

#compiledObject

Returns the value of attribute compiled.



25
26
27
# File 'lib/spiderfw/templates/template.rb', line 25

def compiled
  @compiled
end

#contentObject (readonly)

Returns the value of attribute content.



30
31
32
# File 'lib/spiderfw/templates/template.rb', line 30

def content
  @content
end

#definer_classObject

Returns the value of attribute definer_class.



26
27
28
# File 'lib/spiderfw/templates/template.rb', line 26

def definer_class
  @definer_class
end

#id_pathObject

Returns the value of attribute id_path.



25
26
27
# File 'lib/spiderfw/templates/template.rb', line 25

def id_path
  @id_path
end

#modeObject

:widget, …



27
28
29
# File 'lib/spiderfw/templates/template.rb', line 27

def mode
  @mode
end

#overridesObject (readonly)

Returns the value of attribute overrides.



30
31
32
# File 'lib/spiderfw/templates/template.rb', line 30

def overrides
  @overrides
end

#ownerObject

Returns the value of attribute owner.



26
27
28
# File 'lib/spiderfw/templates/template.rb', line 26

def owner
  @owner
end

#owner_classObject

Returns the value of attribute owner_class.



26
27
28
# File 'lib/spiderfw/templates/template.rb', line 26

def owner_class
  @owner_class
end

#pathObject (readonly)

Returns the value of attribute path.



30
31
32
# File 'lib/spiderfw/templates/template.rb', line 30

def path
  @path
end

#requestObject

Returns the value of attribute request.



26
27
28
# File 'lib/spiderfw/templates/template.rb', line 26

def request
  @request
end

#responseObject

Returns the value of attribute response.



26
27
28
# File 'lib/spiderfw/templates/template.rb', line 26

def response
  @response
end

#runtime_overridesObject

Returns the value of attribute runtime_overrides.



29
30
31
# File 'lib/spiderfw/templates/template.rb', line 29

def runtime_overrides
  @runtime_overrides
end

#subtemplatesObject (readonly)

Returns the value of attribute subtemplates.



30
31
32
# File 'lib/spiderfw/templates/template.rb', line 30

def subtemplates
  @subtemplates
end

#widgetsObject

Returns the value of attribute widgets.



25
26
27
# File 'lib/spiderfw/templates/template.rb', line 25

def widgets
  @widgets
end

Class Method Details

.allow_blocks(*tags) ⇒ Object

Sets allowed blocks



53
54
55
# File 'lib/spiderfw/templates/template.rb', line 53

def allow_blocks(*tags) # :nodoc:
    @allowed_blocks = tags
end

.allowed_blocksObject

Returns allowed blocks



58
59
60
# File 'lib/spiderfw/templates/template.rb', line 58

def allowed_blocks # :nodoc:
    @allowed_blocks
end

.asset_typesObject

:nodoc:



62
63
64
# File 'lib/spiderfw/templates/template.rb', line 62

def asset_types # :nodoc:
    @@asset_types
end

.cacheObject

Returns the class TemplateCache instance



48
49
50
# File 'lib/spiderfw/templates/template.rb', line 48

def cache
    @@cache ||= TemplateCache.new(Spider.paths[:var]+'/cache/templates')
end

.define_named_asset(name, assets, options = {}) ⇒ Object



123
124
125
126
# File 'lib/spiderfw/templates/template.rb', line 123

def define_named_asset(name, assets, options={})
    @named_assets ||= {}
    @named_assets[name] = { :assets => assets, :options => options }
end

.define_runtime_asset(name, &proc) ⇒ Object



132
133
134
135
# File 'lib/spiderfw/templates/template.rb', line 132

def define_runtime_asset(name, &proc)
    @runtime_assets ||= {}
    @runtime_assets[name] = proc
end

.find_resource(path, cur_path = nil, owner_classes = nil, search_paths = []) ⇒ Object



119
120
121
# File 'lib/spiderfw/templates/template.rb', line 119

def find_resource(path, cur_path=nil, owner_classes=nil, search_paths=[])
    Spider.find_resource(:views, path, cur_path, owner_classes, search_paths)
end

.get_named_asset(name) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/spiderfw/templates/template.rb', line 141

def get_named_asset(name)
    res = []
    ass = self.named_assets[name] 
    raise "Named asset #{name} is not defined" unless ass
    deps = ass[:options][:depends] if ass[:options]
    deps = [deps] if deps && !deps.is_a?(Array)
    if deps
        deps.each do |dep|
            res += get_named_asset(dep)
        end
    end
    ass[:assets].each do |a|
        attributes = a[3] || {}
        res << {:type => a[0], :src => a[1], :app => a[2]}.merge(attributes)
    end
    res
end

.get_registered_class(name) ⇒ Object

Returns the Class registered for the given tag.



102
103
104
105
106
107
108
109
110
111
112
# File 'lib/spiderfw/templates/template.rb', line 102

def get_registered_class(name)
    if @@registered[name]
        klass = @@registered[name]
    else
        ns, tag = name.split(':')
        klass = @@namespaces[ns].get_tag(tag) if tag && @@namespaces[ns]
    end
    return nil unless klass
    klass = const_get_full(klass) if klass.is_a?(Symbol)
    return klass
end

.load(path) ⇒ Object

Returns a new instance, loading path.

Raises:

  • (RuntimeError)


67
68
69
70
71
72
# File 'lib/spiderfw/templates/template.rb', line 67

def load(path)
    raise RuntimeError, "Template #{path} does not exist" unless File.exist?(path)
    template = self.new(path)
    template.load(path)
    return template
end

.named_assetsObject



128
129
130
# File 'lib/spiderfw/templates/template.rb', line 128

def named_assets
    @named_assets || {}
end

.override_tagsObject

An array of possible override tags. Overrides may be used when placing a widget in a template, or when including another template. All except tpl:content may have the search attribute, that is a CSS or XPath expression specifing  the nodes to override. If the search attribute is missing, the override will be applied to the root node.

Example:

<div class="my_widget_template">
  <div class="a">aaa</div>
  <div class="b">bbb</div>
</div>

and

<div class="my_template">
  <my:widget id="my_widget_instance">
     <tpl:override search=".b">bbb and a c</tpl:override>
  </my:widget>
</div>

will result in the widget using the template

<div class="my_widget_template">
  <div class="a">aaa</div>
  <div class="b">bbb and c</div>
</div>

The tags are in the tpl namespace. *<tpl:content [name=‘…’] />* overrides the content of the found element.

If name is given, will override the named content found in the
original template.

*<tpl:override />* replaces the found nodes with given content *<tpl:override-attr name=‘…’ value=‘…’ />* overrides the given attribute *<tpl:append />* appends the given content to the container *<tpl:prepend />* prepends the given content *<tpl:delete />* removes the found nodes *<tpl:before />* inserts the given content before the found nodes *<tpl:after />* inserts the given content after the found nodes



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

def override_tags
    @@overrides
end

.parse_asset_element(el) ⇒ Object



200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/spiderfw/templates/template.rb', line 200

def parse_asset_element(el)
    h = {}
    el.attributes.to_hash.each do |k, v|
        h[k.to_sym] = v
    end
    h
    # end
    # {
    #     :type => el.get_attribute('type'),
    #     :src => el.get_attribute('src'),
    #     :attributes => el.attributes.to_hash
    # }
end

.real_path(path, cur_path = nil, owner_classes = nil, search_paths = []) ⇒ Object

Returns the view path (see #Spider::find_asset)



115
116
117
# File 'lib/spiderfw/templates/template.rb', line 115

def real_path(path, cur_path=nil, owner_classes=nil, search_paths=[])
    Spider.find_resource_path(:views, path, cur_path, owner_classes, search_paths)
end

.register(tag, symbol_or_class) ⇒ Object

Registers a tag



75
76
77
# File 'lib/spiderfw/templates/template.rb', line 75

def register(tag, symbol_or_class)
    @@registered[tag] = symbol_or_class
end

.register_namespace(ns, mod) ⇒ Object

Registers a namespace (mod should probably be a Spider::App, and must respond to get_tag and has_tag? methods).



97
98
99
# File 'lib/spiderfw/templates/template.rb', line 97

def register_namespace(ns, mod)
    @@namespaces[ns] = mod
end

.registeredObject

Returns an hash of registered tags.



80
81
82
# File 'lib/spiderfw/templates/template.rb', line 80

def registered
    @@registered
end

.registered?(tag) ⇒ Boolean

Checks if the tag is registered.

Returns:

  • (Boolean)


85
86
87
88
89
90
91
92
93
# File 'lib/spiderfw/templates/template.rb', line 85

def registered?(tag)
    return true if @@registered[tag]
    ns, tag = tag.split(':')
    if tag # that is, if there is a ns
        return false unless @@namespaces[ns]
        return @@namespaces[ns].has_tag?(tag)
    end
    return false
end

.runtime_assetsObject



137
138
139
# File 'lib/spiderfw/templates/template.rb', line 137

def runtime_assets
    @runtime_assets || {}
end

.scan_scene_vars(str) {|:plain, scanner.rest| ... } ⇒ Object

Yields:

  • (:plain, scanner.rest)


887
888
889
890
891
892
893
894
895
896
897
# File 'lib/spiderfw/templates/template.rb', line 887

def self.scan_scene_vars(str)
    scanner = ::StringScanner.new(str)
    pos = 0
    while scanner.scan_until(SceneVarRegexp)
        text = scanner.pre_match[pos..-1]
        yield :plain, text, text if text &&  text.length > 0
        pos = scanner.pos
        yield :var, scanner.matched[1..-1]
    end
    yield :plain, scanner.rest
end

.scan_text(text) {|:plain, scanner.rest, scanner.rest| ... } ⇒ Object

Yields:

  • (:plain, scanner.rest, scanner.rest)


860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
# File 'lib/spiderfw/templates/template.rb', line 860

def self.scan_text(text)
    text = text.gsub(/\302\240/u, ' ') # remove annoying fake space
    scanner = ::StringScanner.new(text)
    pos = 0
    c = ""
    while scanner.scan_until(Regexp.union(ExpressionOutputRegexp, GettextRegexp, ERBRegexp))
        t = scanner.pre_match[pos..-1]
        pos = scanner.pos
        yield :plain, t, t if t && t.length > 0
        case scanner.matched
        when ExpressionOutputRegexp
            if scanner.matched[1].chr == '{'
                yield :escaped_expr, $1, scanner.matched
            else
                yield :expr, $1, scanner.matched
            end
        when GettextRegexp
            gt = [$1]
            gt << $3 if $2 # interpolated vars
            yield :gettext, gt, scanner.matched
        when ERBRegexp
            yield :erb, $1, scanner.matched
        end
    end
    yield :plain, scanner.rest, scanner.rest
end

Instance Method Details

#add_overrides(overrides) ⇒ Object



734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
# File 'lib/spiderfw/templates/template.rb', line 734

def add_overrides(overrides)
    overrides.each do |ov|
        w = ov.get_attribute('widget')
        if w
            first, rest = w.split('/', 2)
            if rest
                ov.set_attribute('widget', rest)
            else
                ov.remove_attribute('widget')
            end
            @widgets_overrides[first] ||= []
            @widgets_overrides[first] << ov
        else
            @overrides << ov
        end
    end
end

#add_subtemplate(id, template, owner) ⇒ Object

:nodoc:



714
715
716
717
# File 'lib/spiderfw/templates/template.rb', line 714

def add_subtemplate(id, template, owner) # :nodoc:
    @subtemplates[id] = template
    @subtemplate_owners[id] = owner
end

#add_widget(id, widget, attributes = nil, content = nil, template = nil) ⇒ Object

Adds a widget instance to the template. This method is usually not called directly; widgets are added during the template init phase.



597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
# File 'lib/spiderfw/templates/template.rb', line 597

def add_widget(id, widget, attributes=nil, content=nil, template=nil)
    @widgets[id.to_sym] ||= widget
    widget.id = id
    widget.id_path = @id_path + [id]
    if attributes # don't use merge to trigger custom []=(k, v) method
        attributes.each{ |k, v| widget.attributes[k] = v }
    end
    widget.containing_template = self
    widget.template = template if template
    widget.parent = @owner
    widget.parse_runtime_content_xml(content, @path) if content
    if @widget_procs[id.to_sym]
        @widget_procs[id.to_sym].each do |wp|
            apply_widget_proc(widget, wp)
        end
    end
    widget
end

#add_widget_template(template, owner_class) ⇒ Object



719
720
721
722
# File 'lib/spiderfw/templates/template.rb', line 719

def add_widget_template(template, owner_class)
    template.owner_class = owner_class
    @widget_templates << template
end

#apply_override(el, override) ⇒ Object

Applies an override to an (Hpricot) element.



764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
# File 'lib/spiderfw/templates/template.rb', line 764

def apply_override(el, override)
    if override.is_a?(Proc)
        return override.call(el)
    end
    search_string = override.get_attribute('search')
    override.name = 'tpl:override-content' if override.name == 'tpl:inline-override'
    if search_string
        # # Fix Hpricot bug!
        # search_string.gsub!(/nth-child\((\d+)\)/) do |match|
        #     "nth-child(#{$1.to_i-2})"
        # end
        found = el.parent.search(search_string)
    elsif override.name == 'tpl:content'
        found = el.search("tpl:placeholder[@name='#{override.get_attribute('name')}']")
    else
        if ['sp:pass', 'tpl:pass', 'sp:template'].include?(el.name)
            found = el.children.select{ |child| child.is_a?(Hpricot::Elem) }
        else
            found = [el]
        end
    end
    
    if override.name == 'tpl:delete'
        found.remove
    else
        found.each do |f|
            o_doc = nil
            if override.name == 'tpl:override-content'
                overridden = f.innerHTML
                f.innerHTML = override.innerHTML
                f.search('tpl:overridden').each do |o| 
                    ovr = overridden
                    if o_search = o.get_attribute('search')
                        o_doc ||= Hpricot("<o>#{overridden}</o>")
                        ovr = o_doc.root.search(o_search).to_html
                    end 
                    o.swap(ovr)
                end
            elsif override.name == 'tpl:override' || override.name == 'tpl:content'
                overridden = f.to_html
                parent = f.parent
                f.swap(override.innerHTML)
                parent.search('tpl:overridden').each do |o| 
                    ovr = overridden
                    if o_search = o.get_attribute('search')
                        o_doc ||= Hpricot("<o>#{overridden}</o>")
                        ovr = o_doc.root.search(o_search).to_html
                    end
                    o.swap(ovr)
                end
            elsif override.name == 'tpl:override-attr'
                f.set_attribute(override.get_attribute("name"), override.get_attribute("value"))
            elsif override.name == 'tpl:append-attr'
                f.set_attribute(override.get_attribute("name"), \
                (f.get_attribute(override.get_attribute("name")) || '')+override.get_attribute("value")) 
            elsif override.name == 'tpl:append'
                f.innerHTML += override.innerHTML
            elsif override.name == 'tpl:prepend'
                f.innerHTML = override.innerHTML + f.innerHTML
            elsif override.name == 'tpl:before'
                f.before(override.innerHTML)
            elsif override.name == 'tpl:after'
                f.after(override.innerHTML)
            end
        end
    end
end

#apply_overrides(el) ⇒ Object



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

def apply_overrides(el)
    if @overrides
        @overrides.each{ |o| apply_override(el, o) }
    end
    el
end

#apply_widget_proc(widget, wp) ⇒ Object



843
844
845
846
847
848
849
# File 'lib/spiderfw/templates/template.rb', line 843

def apply_widget_proc(widget, wp)
    if wp[:target]
        widget.with_widget(wp[:target], &wp[:proc])
    else
        widget.instance_eval(wp[:proc])
    end
end

#bind(scene) ⇒ Object

Sets the scene.



238
239
240
241
# File 'lib/spiderfw/templates/template.rb', line 238

def bind(scene)
    @scene = scene
    return self
end

#compile(options = {}) ⇒ Object

Recompiles the template; returns a CompiledTemplate.



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/spiderfw/templates/template.rb', line 266

def compile(options={})
    compiled = CompiledTemplate.new
    compiled.source_path = @path
    doc = open(@path){ |f| Hpricot.XML(f) }
    root = get_el(doc)
    el = process_tags(root)
    apply_overrides(root)
    root.search('tpl:placeholder').remove # remove empty placeholders
    owner_class = @owner ? @owner.class : @owner_class
    @assets += owner_class.assets if owner_class
    res =  root.children ? root.children_of_type('tpl:asset') : []
    res_init = ""
    res.each do |r|
        @assets << Spider::Template.parse_asset_element(r)
        r.set_attribute('class', 'to_delete')
    end
    new_assets = []
    @assets.each do |ass|
        a = parse_asset(ass[:type], ass[:src], ass)
        new_assets += a
    end
    @assets = new_assets
    root.search('.to_delete').remove
    root.search('tpl:assets').each do |ass|
        if wattr = ass.get_attribute('widgets')
            widgets = []
            wattr.split(/,\s*/).each do |w|
                w_templates = nil
                if w =~ /(\.+)\((.+)\)/
                    w = $1
                    w_templates = $2.split('|')
                end
                klass = Spider::Template.get_registered_class(w)
                unless klass
                    Spider.logger.warn("tpl:assets requested non existent widget #{w}")
                    next
                end
                w_templates ||= [klass.default_template]
                w_templates.each do |wt| 
                    t = klass.load_template(wt)
                    add_widget_template(t, klass)
                end
            end
        elsif sattr = ass.get_attribute('src')
            sattr.split(/,\s*/).each do |s|
                s_template = Spider::Template.new(s)
                s_template.owner = @owner
                s_template.definer_class = @definer_class
                s_template.load(s)
                @assets = s_template.assets + @assets
            end
        end
    end
    root.search('tpl:assets').remove
    root_block = TemplateBlocks.parse_element(root, self.class.allowed_blocks, self)
    if doc.children && doc.children[0].is_a?(Hpricot::DocType)
        root_block.doctype = doc.children[0]
        options[:doctype] = DocType.new(root_block.doctype)
    else
        options[:doctype] ||= DocType.new(Spider.conf.get('template.default_doctype'))
    end
    options[:root] = true
    options[:owner] = @owner
    options[:owner_class] = @owner_class || @owner.class
    options[:template_path] = @path
    options[:template] = self
    compiled.block = root_block.compile(options)
    subtemplates.each do |id, sub|
        sub.owner_class = @subtemplate_owners[id]
        compiled.subtemplates[id] = sub.compile(options.merge({:mode => :widget})) # FIXME! :mode => :widget is wrong, it's just a quick kludge
        @assets += compiled.subtemplates[id].assets
    end
    @widget_templates.each do |wt|
        wt.mode = :widget
        wt.load
        # sub_c = sub.compile(options.merge({:mode => :widget}))
        @assets = wt.compiled.assets + @assets
    end
    
    seen = {}
    # @assets.each_index do |i|
    #     ass = @assets[i]
    #     if ass[:name]
    # end
    @assets.each do |ass|
        ass[:profiles] = ((ass[:profiles] || []) + @asset_profiles).uniq if @asset_profiles
        next if seen[ass.inspect]
        res_init += "@assets << #{ass.inspect}\n"
        # res_init += "@assets << {
        #     :type => :#{ass[:type]}, 
        #     :src => '#{ass[:src]}',
        #     :path => '#{ass[:path]}',
        #     :if => '#{ass[:if]}'"
        # res_init += ",\n :compiled => '#{ass[:compressed]}'" if ass[:compressed]
        # res_init += "}\n"
        seen[ass.inspect] = true
    end
    compiled.block.init_code = res_init + compiled.block.init_code
    compiled.devel_info["source.xml"] = root.to_html
    compiled.assets = @assets + assets
    return compiled
end

#do_widgets_beforeObject

Calls the before method of all widget instances.



637
638
639
640
641
642
# File 'lib/spiderfw/templates/template.rb', line 637

def do_widgets_before
    @widgets.each do |id, w|
        act = (@_action_to == id) ? @_action : ''
        w.widget_before(act) unless w.before_done?
    end
end

#execObject

Does #do_widgets_before and then #run_widgets.



653
654
655
656
# File 'lib/spiderfw/templates/template.rb', line 653

def exec
    do_widgets_before
    run_widgets
end

#find_widget(path) ⇒ Object



616
617
618
# File 'lib/spiderfw/templates/template.rb', line 616

def find_widget(path)
    return @widgets[path.to_sym]
end

#get_el(path_or_doc = nil) ⇒ Object

Returns the root node of the template at given path. Will apply overrides and process extends and inclusions.



457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
# File 'lib/spiderfw/templates/template.rb', line 457

def get_el(path_or_doc=nil)
    path = nil
    doc = nil
    if path_or_doc.is_a?(Hpricot::Doc)
        doc = path_or_doc
        path = @path
    else
        path = path_or_doc
        path ||= @path
        doc = open(path){ |f| Hpricot.XML(f) }
    end
    root = doc.root
    overrides = []
    orig_overrides = @overrides
    @overrides = []
    if root.children
        override_tags.each do |tag|
            overrides += root.children_of_type('tpl:'+tag)
        end
    end
    overrides.each{ |o| o.set_attribute('class', 'to_delete') }
    root.search('.to_delete').remove
    add_overrides overrides
    @overrides += orig_overrides
    if root.name == 'tpl:extend'
        orig_overrides = @overrides
        @overrides = []
        ext_src = root.get_attribute('src')
        ext_app = root.get_attribute('app')
        ext_widget = root.get_attribute('widget')
        if ext_widget
            ext_widget = Spider::Template.get_registered_class(ext_widget)
            ext_src ||= ext_widget.default_template
            ext_owner = ext_widget
            ext_app = ext_widget.app
        elsif ext_app
            ext_app = Spider.apps_by_path[ext_app]
            ext_owner = ext_app
        else 
            ext_owner = @owner.class
            ext_app = ext_owner.app
        end
        ext_search_paths = nil
        if ext_owner && ext_owner.respond_to?(:template_paths)
            ext_search_paths = ext_owner.template_paths
        end 
        ext = self.class.real_path(ext_src, path, ext_owner, ext_search_paths)
        raise "Extended template #{ext_src} not found (search path #{path}, owner #{ext_owner}, search paths #{ext_search_paths.inspect}" unless ext
        assets = []
        if root.children
            assets = root.children_of_type('tpl:asset')
            assets += root.children_of_type('tpl:assets')
        end
        @dependencies << ext
        tpl = Template.new(ext)
        root = get_el(ext)
        root.children_of_type('tpl:asset').each do |ass|
            ass_src = ass.get_attribute('src')
            if ass_src && ass_src[0].chr != '/'
                # ass.set_attribute('src', "/#{ext_app.relative_path}/#{ass_src}")
                ass.set_attribute('app', ext_app.relative_path) if ass.get_attribute('app').blank?
            end
        end
        @overrides += orig_overrides
        if assets && !assets.empty?
            assets.each do |ass|
                root.innerHTML += ass.to_html
            end
        end
    else
        assets_html = ""
        root.search('tpl:include').each do |incl|
            resource = Spider.find_resource(:views, incl.get_attribute('src'), @path, [@owner.class, @definer_class])
            src = resource.path
            @dependencies << src
            incl_el = self.get_el(src)
            assets = incl_el.children ? incl_el.children_of_type('tpl:asset') : []
            assets.each{ |ass| 
                ass.set_attribute('class', 'to_delete')
                ass_src = ass.get_attribute('src')
                if ass_src && ass_src[0].chr != '/'
                    # ass.set_attribute('src', "/#{resource.definer.relative_path}/#{ass_src}")
                    ass.set_attribute('app', resource.definer.relative_path)
                end
                assets_html += ass.to_html 
            }
            if incl_el.children
                incl_el.children_of_type('tpl:assets').each do |asss|
                    assets_html += asss.to_html
                end
            end
            incl_el.search('.to_delete').remove
            incl.swap(incl_el.to_html)
        end
        
        root.search('.to_delete').remove
        root.innerHTML = assets_html + root.innerHTML
    end
    return root
end

#init(scene) ⇒ Object

Does the init phase (evals the template’s compiled init.rb).



621
622
623
624
625
626
627
628
629
# File 'lib/spiderfw/templates/template.rb', line 621

def init(scene)
#            Spider::Logger.debug("Template #{@path} INIT")
    load unless loaded?
    # debug("Template #{@path} init")
    # debug(@compiled.init_code)
    @scene = scene
    instance_eval(@compiled.init_code, @compiled.cache_path+'/init.rb')
    @init_done = true
end

#init_done?Boolean

Returns:

  • (Boolean)


632
633
634
# File 'lib/spiderfw/templates/template.rb', line 632

def init_done?
    @init_done
end

#inspectObject



710
711
712
# File 'lib/spiderfw/templates/template.rb', line 710

def inspect
    self.class.to_s
end

#load(path = nil) ⇒ Object

Loads the compiled template (from cache if available).



245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/spiderfw/templates/template.rb', line 245

def load(path=nil)
    @path = real_path(path) if path
    @path = File.expand_path(@path)
#            debug("TEMPLATE LOADING #{@path}")
    cache_path = @path.sub(Spider.paths[:root], 'ROOT').sub(Spider.paths[:spider], 'SPIDER')
    unless @runtime_overrides.empty?
        cache_path_dir = File.dirname(cache_path)
        cache_path_file = File.basename(cache_path, '.shtml')
        suffix = @runtime_overrides.map{ |ro| ro[0].to_s }.sort.join('+')
        cache_path = cache_path_dir+'/'+cache_path_file+'+'+suffix+'.shtml'
        @runtime_overrides.each do |ro|
            @overrides += ro[1]
            @dependencies << ro[2]
        end
    end
    @compiled = self.class.cache.fetch(cache_path) do
        compile(:mode => @mode)
    end
end

#load_subtemplate(id, options = {}) ⇒ Object

:nodoc:



725
726
727
728
729
730
731
732
# File 'lib/spiderfw/templates/template.rb', line 725

def load_subtemplate(id, options={}) # :nodoc:
    load unless loaded?
    return nil unless @compiled.subtemplates[id]
    t = Template.new
    t.asset_profiles = options[:asset_profiles] if options[:asset_profiles]
    t.compiled = @compiled.subtemplates[id]
    return t
end

#loaded?Boolean

Returns:

  • (Boolean)


590
591
592
# File 'lib/spiderfw/templates/template.rb', line 590

def loaded?
    @compiled ? true : false
end

#override_tagsObject

Returns the class override_tags



217
218
219
# File 'lib/spiderfw/templates/template.rb', line 217

def override_tags
    @@overrides
end

#overrides_for(widget_id) ⇒ Object



752
753
754
# File 'lib/spiderfw/templates/template.rb', line 752

def overrides_for(widget_id)
    @widgets_overrides[widget_id] || []
end

#parse_asset(type, src, attributes = {}) ⇒ Object

Processes an asset. Returns an hash with :type, :src, :path.



370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
# File 'lib/spiderfw/templates/template.rb', line 370

def parse_asset(type, src, attributes={})
    # FIXME: use Spider.find_asset ?
    type = type.to_sym if type
    ass = {:type => type}
    if attributes[:name]
        named = Spider::Template.get_named_asset(attributes[:name])
        raise "Can't find named asset #{attributes[:name]}" unless named
        if attributes[:profiles]
            named.each{ |nmdass| nmdass[:profiles] = attributes[:profiles] }
        end
        return named.map{ |nmdass| 
            parse_asset(nmdass[:type], nmdass[:src], nmdass)
        }.flatten
    end
    if attributes[:profiles]
        ass[:profiles] = attributes[:profiles].split(/,\s*/).map{ |p| p.to_sym }
    end
    if attributes[:app] == :runtime
        ass[:runtime] = src
        return [ass]
    end
    if attributes[:app]
        owner_class = attributes[:app]
        owner_class = Spider.apps_by_path[owner_class] unless owner_class.is_a?(Module)
    else
        owner_class = (@owner ? @owner.class : @owner_class )
    end
    ass[:app] = owner_class.app 
    # FIXME! @definer_class is not correct for Spider::HomeController
    raise "Asset type not given for #{src}" unless type
    search_classes = [owner_class, @definer_class]
    dfnr = @definer_class.superclass if @definer_class && @definer_class.respond_to?(:superclass)
    while dfnr && dfnr < Spider::Widget
        search_classes << dfnr
        dfnr = dfnr.respond_to?(:superclass) ? dfnr.superclass : nil
    end
    res = Spider.find_resource(type.to_sym, src, @path, search_classes)
    controller = nil
    if res && res.definer
        controller = res.definer.controller
    elsif owner_class < Spider::Controller
        controller = owner_class
    end
    ass[:path] = res.path if res
    base_url = nil
    if controller.respond_to?(:pub_url)
        if src[0].chr == '/' 
            if controller <= Spider::HomeController
                src = src[(1+controller.pub_path.length)..-1]
            else
            # strips the app path from the src. FIXME: should probably be done somewhere else
                src = src[(2+controller.app.relative_path.length)..-1]
            end
        end
        base_url = controller.pub_url+'/'
        
    else
        base_url = ''
    end
    ass[:rel_path] = src
    ass[:src] = base_url + src
    ass_info = self.class.asset_types[type]
    if ass_info && ass_info[:processor]
        processor = TemplateAssets.const_get(ass_info[:processor])
        ass = processor.process(ass)
    end
    if cpr = attributes[:compressed] 
        if cpr == "true"
            ass[:compressed_path] = ass[:path]
            ass[:compressed_rel_path] = ass[:rel_path]
            ass[:compressed] = base_url + File.basename(ass[:path])
        else
            compressed_res = Spider.find_resource(type.to_sym, cpr, @path, [owner_class, @definer_class])
            ass[:compressed_path] = compressed_res.path
            ass[:compressed] = base_url+cpr
        end
    end
    ass[:copy_dir] = attributes[:copy_dir]
    ass[:copy_dir] = ass[:copy_dir] =~ /\d+/ ? ass[:copy_dir].to_i : true
    [:gettext, :media, :if_ie_lte, :cdn].each do |key|
        ass[key] = attributes[key] if attributes.key?(key)
    end
    return [ass]
end

#process_tags(el) ⇒ Object



558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
# File 'lib/spiderfw/templates/template.rb', line 558

def process_tags(el)
    block = TemplateBlocks.get_block_type(el, true)
    raise "Bad html in #{@path}, can't parse" if el.is_a?(Hpricot::BogusETag)
    if block == :Tag
        sp_attributes = {}
        # FIXME: should use blocks instead
        el.attributes.to_hash.each do |key, value|
            if key[0..1] == 'sp'
                sp_attributes[key] = value
                el.remove_attribute(key)
            end
        end
        klass = Spider::Template.get_registered_class(el.name)
        tag = klass.new(el)
        res = process_tags(Hpricot(tag.render).root)
        sp_attributes.each{ |key, value| res.set_attribute(key, value) }
        return res
    else
        el.each_child do |child|
            next if child.is_a?(Hpricot::Text) || child.is_a?(Hpricot::Comment)
            el.replace_child(child, process_tags(child))
        end
    end
    return el
end

#real_path(path) ⇒ Object

The full path of a template mentioned in this one.



585
586
587
# File 'lib/spiderfw/templates/template.rb', line 585

def real_path(path)
    self.class.real_path(path, File.dirname(@path), [@owner.class, @definer_class])
end

#render(scene = nil) ⇒ Object

Does the render phase. Will execute the following steps (if needed):

  • load

  • init

  • exec

  • eval the template’s compiled run code.



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
# File 'lib/spiderfw/templates/template.rb', line 664

def render(scene=nil)
    scene ||= @scene
    load unless loaded?
    init(scene) unless init_done?
    exec
    @content.merge!(@widgets)
    # if Spider.conf.get('template.safe')
    #     debug("RENDERING IN SAFE MODE!")
    #     debug(@compiled.run_code)
    #     # FIXME: must send header before safe mode
    #     current_thread = Thread.current
    #     t = Thread.new { 
    #         Thread.current[:stdout] = current_thread[:stdout]
    #         $SAFE = 4
    #         scene.instance_eval("def __run_template\n"[email protected]_code+"end\n", @compiled.cache_path+'/run.rb')
    #         scene.__run_template
    #         scene.__run_template do |widget|
    #             @content[widget].run
    #         end
    #     }
    #     t.join
    # else
    scene.instance_eval("def __run_template\n"+@compiled.run_code+"end\n", @compiled.cache_path+'/run.rb', 0)
    scene.__run_template do |yielded|
        if yielded == :_parent
            @owner.parent.template.content.merge!(@content)
            @owner.parent.template.run_block
        else
            @content[yielded].render if @content[yielded]
        end
    end
    # end
end

#runObject

Alias for #render.



705
706
707
# File 'lib/spiderfw/templates/template.rb', line 705

def run
    render(@scene)
end

#run_blockObject



698
699
700
701
702
# File 'lib/spiderfw/templates/template.rb', line 698

def run_block
    @scene.__run_block do |yielded, block|
        @content[yielded].render if @content[yielded]
    end
end

#run_widgetsObject

Calls the run method on all widget instances.



645
646
647
648
649
650
# File 'lib/spiderfw/templates/template.rb', line 645

def run_widgets
    @widgets.each do |id, w|
        w.run if w.run? && !w.did_run?
    end
    
end

#with_widget(path, &proc) ⇒ Object



833
834
835
836
837
838
839
840
841
# File 'lib/spiderfw/templates/template.rb', line 833

def with_widget(path, &proc)
    first, rest = path.split('/', 2)
    @widget_procs[first.to_sym] ||= []
    wp = {:target => rest, :proc => proc }
    @widget_procs[first.to_sym] << wp
    if @widgets[first.to_sym]
        apply_widget_proc(@widgets[first.to_sym], wp)
    end
end