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 =
/([snp][snp]?)?_\(([^\)]+)?\)(\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, 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?

Constructor Details

#initialize(path = nil) ⇒ Template

Returns a new instance of Template.



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/spiderfw/templates/template.rb', line 226

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

#subtemplate_ofObject

Returns the value of attribute subtemplate_of.



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

def subtemplate_of
  @subtemplate_of
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



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

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

.allowed_blocksObject

Returns allowed blocks



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

def allowed_blocks # :nodoc:
    @allowed_blocks
end

.asset_typesObject

:nodoc:



66
67
68
# File 'lib/spiderfw/templates/template.rb', line 66

def asset_types # :nodoc:
    @@asset_types
end

.cacheObject

Returns the class TemplateCache instance



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

def cache
    @@cache ||= TemplateCache.new(self.cache_path)
end

.cache_pathObject



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

def cache_path
    File.join(Spider.paths[:var], 'cache', 'templates')
end

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



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

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

.define_runtime_asset(name, &proc) ⇒ Object



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

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



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

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



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/spiderfw/templates/template.rb', line 145

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.



106
107
108
109
110
111
112
113
114
115
116
# File 'lib/spiderfw/templates/template.rb', line 106

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)


71
72
73
74
75
76
# File 'lib/spiderfw/templates/template.rb', line 71

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



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

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 *<tpl:content name=“content-name” />* replaces a <tpl:placeholder> with the same name



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

def override_tags
    @@overrides
end

.parse_asset_element(el) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/spiderfw/templates/template.rb', line 205

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)



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

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



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

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).



101
102
103
# File 'lib/spiderfw/templates/template.rb', line 101

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

.registeredObject

Returns an hash of registered tags.



84
85
86
# File 'lib/spiderfw/templates/template.rb', line 84

def registered
    @@registered
end

.registered?(tag) ⇒ Boolean

Checks if the tag is registered.

Returns:

  • (Boolean)


89
90
91
92
93
94
95
96
97
# File 'lib/spiderfw/templates/template.rb', line 89

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



141
142
143
# File 'lib/spiderfw/templates/template.rb', line 141

def runtime_assets
    @runtime_assets || {}
end

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

Yields:

  • (:plain, scanner.rest)


980
981
982
983
984
985
986
987
988
989
990
# File 'lib/spiderfw/templates/template.rb', line 980

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)


953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
# File 'lib/spiderfw/templates/template.rb', line 953

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 = {:val => $2, :func => $1}
            gt[:vars] = $4 if $3 # 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



793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
# File 'lib/spiderfw/templates/template.rb', line 793

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:



773
774
775
776
# File 'lib/spiderfw/templates/template.rb', line 773

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.



650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
# File 'lib/spiderfw/templates/template.rb', line 650

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



778
779
780
781
# File 'lib/spiderfw/templates/template.rb', line 778

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.



832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
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
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
# File 'lib/spiderfw/templates/template.rb', line 832

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: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
        td = nil
        orig_td = nil
        if @extended_app
            td = @definer_class.respond_to?(:app) ? @definer_class.app.gettext_domain : nil
            orig_td = @extended_app.gettext_domain
        elsif @subtemplate_of
            td = @subtemplate_of.respond_to?(:app) ? @subtemplate_of.app.gettext_domain : nil
            orig_td = @definer_class.respond_to?(:app) ? @definer_class.app.gettext_domain : nil
        end
        if td && orig_td && td != orig_td
            override.innerHTML = '<tpl:pass tpl:text-domain="'+td+'">'+override.innerHTML+'</tpl:pass>'                
        end
        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
                    if orig_td
                        ovr = '<tpl:pass tpl:text-domain="'+orig_td+'">'+ovr+'</tpl:pass>'
                    end
                    o.swap(ovr)
                end
            elsif override.name == 'tpl:override' || override.name == 'tpl:content'
                if orig_td
                    f.set_attribute('tpl:text-domain', orig_td)
                end
                overridden = f.to_html
                parent = f.parent
                if f == el
                    f.innerHTML = override.innerHTML
                else
                    f.swap(override.innerHTML)
                end
                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'
                a = f.get_attribute(override.get_attribute("name")) || ''
                a += ' ' unless a.blank?
                a += override.get_attribute("value")
                f.set_attribute(override.get_attribute("name"), a)
            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



815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
# File 'lib/spiderfw/templates/template.rb', line 815

def apply_overrides(el)
    info_els = nil
    if el.children
        info_els = Hpricot::Elements[*(el.children_of_type('tpl:asset')+
            el.children_of_type('tpl:assets'))]
        info_els.remove
    end
    if @overrides
        @overrides.each{ |o| apply_override(el, o) }
    end
    if info_els
        el.innerHTML = info_els.to_s + el.innerHTML
    end
    el
end

#apply_widget_proc(widget, wp) ⇒ Object



936
937
938
939
940
941
942
# File 'lib/spiderfw/templates/template.rb', line 936

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.



243
244
245
246
# File 'lib/spiderfw/templates/template.rb', line 243

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

#compile(options = {}) ⇒ Object

Recompiles the template; returns a CompiledTemplate.



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
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# File 'lib/spiderfw/templates/template.rb', line 276

def compile(options={})
    compiled = CompiledTemplate.new
    compiled.source_path = @path
    doc = open(@path){ |f| Hpricot.XML(f) }
    root = get_el(doc)
    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|
        #se ho l'attributo runtime carico il file se il runtime coincide o non viene specificato
        @assets << Spider::Template.parse_asset_element(r) if (r.get_attribute("runmode") == Spider.runmode || r.get_attribute("runmode").nil?)
        r.set_attribute('class', 'to_delete')
    end
    new_assets = []
    @assets.each do |ass|
        a = parse_asset(ass[:type], ass[:src], ass)
        new_assets += a unless new_assets.include?(a) #non inserisco duplicati
    end
    @assets = new_assets
    root.search('.to_delete').remove
    root.search('tpl:assets').each do |ass|
        if wattr = ass.get_attribute('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]
        sub.subtemplate_of = options[:owner_class]
        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
    #
    #rendo univoco all'inizio l'array per non caricare piu' volte lo stesso asset
    assets_univoci = @assets.uniq!
    @assets = ( assets_univoci.nil? ? @assets : assets_univoci )
    @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 + assets).uniq sono univoci e assets == @assets
    return compiled
end

#do_widgets_beforeObject

Calls the before method of all widget instances.



690
691
692
693
694
695
# File 'lib/spiderfw/templates/template.rb', line 690

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.



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

def exec
    do_widgets_before
    run_widgets
end

#find_widget(path) ⇒ Object



669
670
671
# File 'lib/spiderfw/templates/template.rb', line 669

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.



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
557
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
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
# File 'lib/spiderfw/templates/template.rb', line 486

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
    our_domain = nil
    if @definer_class
        our_domain = @definer_class.respond_to?(:app) ? @definer_class.app.gettext_domain : 'spider'
    end
    @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
        @extended_app = ext_app
        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
        root = get_el(ext)
        if ext_app.gettext_domain != our_domain
            root.set_attribute('tpl:text-domain', ext_app.gettext_domain)
        end
        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
            raise "Template #{@path} didn't find included '#{incl.get_attribute('src')}'" unless src
            @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 != '/'
                    if resource.definer.is_a?(Spider::Home)
                        ass.set_attribute('home', 'true')
                    else
                    # ass.set_attribute('src', "/#{resource.definer.relative_path}/#{ass_src}")
                        res_rel_path = if resource.definer.respond_to?(:app)
                            resource.definer.app.relative_path
                        elsif resource.definer.respond_to?(:relative_path)
                            resource.definer.relative_path
                        else
                            nil
                        end
                        ass.set_attribute('app', res_rel_path) if res_rel_path
                    end
                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
            td = resource.definer.respond_to?(:app) ? resource.definer.app.gettext_domain : 'spider'
            if td != our_domain
                incl_el.set_attribute('tpl:text-domain', td)
            end
            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).



674
675
676
677
678
679
680
681
682
# File 'lib/spiderfw/templates/template.rb', line 674

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)


685
686
687
# File 'lib/spiderfw/templates/template.rb', line 685

def init_done?
    @init_done
end

#inspectObject



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

def inspect
    self.class.to_s
end

#load(path = nil) ⇒ Object

Loads the compiled template (from cache if available).



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/spiderfw/templates/template.rb', line 250

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
        begin
            compile(:mode => @mode)
        rescue Exception
            Spider.logger.error("Failed compilation of template #{@path}:")
            raise
        end
    end
end

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

:nodoc:



784
785
786
787
788
789
790
791
# File 'lib/spiderfw/templates/template.rb', line 784

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)


643
644
645
# File 'lib/spiderfw/templates/template.rb', line 643

def loaded?
    @compiled ? true : false
end

#override_tagsObject

Returns the class override_tags



222
223
224
# File 'lib/spiderfw/templates/template.rb', line 222

def override_tags
    @@overrides
end

#overrides_for(widget_id) ⇒ Object



811
812
813
# File 'lib/spiderfw/templates/template.rb', line 811

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.



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

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]
        asset_owner = attributes[:app]
        asset_owner = Spider.apps_by_path[asset_owner] unless asset_owner.is_a?(Module)
    elsif attributes[:home]
        asset_owner = Spider.home
    else
        asset_owner = (@owner ? @owner.class : @owner_class )
    end
    ass[:app] = asset_owner.app if asset_owner.respond_to?(:app)
    # FIXME! @definer_class is not correct for Spider::HomeController
    raise "Asset type not given for #{src}" unless type
    search_classes = [asset_owner]
    search_classes << @definer_class if @definer_class
    search_classes << Spider.home
    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)
    raise "Resource #{src} of type #{type} not found" unless res.path
    controller = nil
    if res && res.definer
        controller = res.definer.controller
        if res.definer.is_a?(Spider::Home)
            ass[:app] = :home
        else
            ass[:app] = res.definer
        end
    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 || 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[:no_compress] = attributes[:"no-compress"]
    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

    ass[:order] = attributes[:order]
    return [ass]
end

#process_tags(el) ⇒ Object



611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
# File 'lib/spiderfw/templates/template.rb', line 611

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.



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

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.



717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
# File 'lib/spiderfw/templates/template.rb', line 717

def render(scene=nil)
    prev_domain = nil
    if @definer_class
        td = @definer_class.respond_to?(:app) ? @definer_class.app.gettext_domain : 'spider'
        prev_domain = Spider::GetText.set_domain(td)
    end
    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
    Spider::GetText.restore_domain(prev_domain) if prev_domain
    # end
end

#runObject

Alias for #render.



764
765
766
# File 'lib/spiderfw/templates/template.rb', line 764

def run
    render(@scene)
end

#run_blockObject



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

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.



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

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

#with_widget(path, &proc) ⇒ Object



926
927
928
929
930
931
932
933
934
# File 'lib/spiderfw/templates/template.rb', line 926

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