# -*- encoding: utf-8 -*- require 'webgen/path_handler/base' require 'webgen/page' require 'webgen/error' module Webgen class PathHandler # This module should be used by path handlers that need to work with paths in Webgen Page Format. # # Note that this modules provides an implementation for the #parse_meta_info! method. If you # also include the Base module, make sure that you include it before this module! Also make sure # to override this method if you need custom behaviour! module PageUtils # Custom Node class that provides easy access to the blocks of the parsed page file and # methods for rendering a block. class Node < Webgen::PathHandler::Base::Node # Return the blocks (see PageUtils#parse_as_page!) for this node. def blocks node_info[:blocks] end # Render the block +name+ of this node using the provided Context object. # # Uses the content processors specified for the block via the +blocks+ meta information key if # the +pipeline+ parameter is not set. # # Returns the given context with the rendered content. def render_block(name, context, pipeline = nil) unless blocks.has_key?(name) raise Webgen::RenderError.new("No block named '#{name}' found", nil, context.dest_node.alcn, alcn) end content_processor = context.website.ext.content_processor context.website.ext.item_tracker.add(context.dest_node, :node_content, self) context.content = blocks[name].dup context[:block_name] = name pipeline ||= if (t = self['blocks']) && (t = t[name] || t['defaults']) && t.key?('pipeline') t['pipeline'] else [] end content_processor.normalize_pipeline(pipeline).each do |processor| content_processor.call(processor, context) end context[:block_name] = nil context end # Return the template chain for this node. # # When invoked directly, the +lang+ parameter should not be used. This parameter is necessary # for the recursive invocation of the method so that the correct templates are used. Consider # the following path hierarchy: # # /default.en.template # /default.de.template # /custom.template # /index.de.page template: custom.template # /index.en.page template: custom.template # # The template chains for index.en.page and index.de.page are therefore # # /default.en.template → /custom.template # /default.de.template → /custom.template # # This means that the /custom.template needs to reference different templates depending on the # language. def template_chain(lang = @lang) cached_template = (tree.website.cache.volatile[[alcn, :templates]] ||= {}) if cached_template.has_key?(lang) template_node = cached_template[lang] elsif self['template'].kind_of?(String) template_node = resolve(self['template'], lang, true) if template_node.nil? tree.website.logger.warn do ["Template '#{self['template']}' for <#{self}> not found, using default template!", 'Fix the value of the meta information \'template\' for <#{self}>'] end template_node = default_template(parent, lang) end cached_template[lang] = template_node elsif meta_info.has_key?('template') && self['template'].nil? template_node = cached_template[lang] = nil else tree.website.logger.debug { "Using default template in language '#{lang}' for <#{self}>" } template_node = default_template(parent, lang) if template_node == self && !parent.is_root? template_node = default_template(parent.parent, lang) end cached_template[lang] = template_node end if template_node.nil? [] else (template_node == self ? [] : template_node.template_chain(lang) + [template_node]) end end # Return the default template for the directory node +dir+ and language +lang+. # # If the template node is not found, the parent directories are searched. def default_template(dir, lang) default_template_name = tree.website.config['path_handler.default_template'] template = dir.resolve(default_template_name, lang) if template.nil? if dir.is_root? tree.website.logger.warn do ["Default template '#{default_template_name}' not found in root directory!", 'Provide a to fix this warning.'] end else template = default_template(dir.parent, lang) end end template end protected :default_template end def create_node(path) #:nodoc: path['node_class'] ||= Node.to_s super end # Calls #parse_as_page! to update the meta information hash of +path+. Returns the found # blocks which will be passed as second parameter to the #create_nodes method. def parse_meta_info!(path) parse_as_page!(path) end # Assume that the content of the given +path+ is in Webgen Page Format and parse it. Updates # 'path.meta_info' with the meta info from the page and returns the content blocks. def parse_as_page!(path) begin page = Webgen::Page.from_data(path.data) rescue Webgen::Page::FormatError => e raise Webgen::Error.new("Error reading source path: #{e.message}", nil, path) end blocks = page.meta_info.delete('blocks') || {} path.meta_info.merge!(page.meta_info) blocks.each {|key, val| ((path.meta_info['blocks'] ||= {})[key] ||= {}).merge!(val)} page.blocks end private :parse_as_page! # Set the blocks (see #parse_as_page!) for the node. def set_blocks(node, blocks) node.node_info[:blocks] = blocks end private :set_blocks end end end