gettalong-webgen 0.5.4.20080929
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +5 -0
- data/COPYING +10 -0
- data/GPL +340 -0
- data/Rakefile +324 -0
- data/THANKS +17 -0
- data/bin/webgen +10 -0
- data/data/webgen/resources.yaml +3 -0
- data/data/webgen/webgui/controller/main.rb +129 -0
- data/data/webgen/webgui/overrides/win32console.rb +0 -0
- data/data/webgen/webgui/public/css/jquery.autocomplete.css +50 -0
- data/data/webgen/webgui/public/css/ramaze_error.css +90 -0
- data/data/webgen/webgui/public/css/style.css +55 -0
- data/data/webgen/webgui/public/img/headerbg.jpg +0 -0
- data/data/webgen/webgui/public/img/webgen_logo.png +0 -0
- data/data/webgen/webgui/public/js/jquery.autocomplete.js +15 -0
- data/data/webgen/webgui/public/js/jquery.js +32 -0
- data/data/webgen/webgui/view/create_website.xhtml +22 -0
- data/data/webgen/webgui/view/error.xhtml +64 -0
- data/data/webgen/webgui/view/index.xhtml +22 -0
- data/data/webgen/webgui/view/manage_website.xhtml +18 -0
- data/data/webgen/webgui/view/page.xhtml +40 -0
- data/data/webgen/website_skeleton/README +10 -0
- data/data/webgen/website_skeleton/Rakefile +40 -0
- data/data/webgen/website_skeleton/config.yaml +17 -0
- data/data/webgen/website_skeleton/ext/init.rb +6 -0
- data/data/webgen/website_styles/1024px/README +13 -0
- data/data/webgen/website_styles/1024px/src/default.css +188 -0
- data/data/webgen/website_styles/1024px/src/default.template +60 -0
- data/data/webgen/website_styles/1024px/src/images/background.gif +0 -0
- data/data/webgen/website_styles/andreas00/README +13 -0
- data/data/webgen/website_styles/andreas00/src/default.css +290 -0
- data/data/webgen/website_styles/andreas00/src/default.template +60 -0
- data/data/webgen/website_styles/andreas00/src/images/bg.gif +0 -0
- data/data/webgen/website_styles/andreas00/src/images/front.jpg +0 -0
- data/data/webgen/website_styles/andreas00/src/images/menubg.gif +0 -0
- data/data/webgen/website_styles/andreas00/src/images/menubg2.gif +0 -0
- data/data/webgen/website_styles/andreas01/README +14 -0
- data/data/webgen/website_styles/andreas01/src/default.css +310 -0
- data/data/webgen/website_styles/andreas01/src/default.template +61 -0
- data/data/webgen/website_styles/andreas01/src/images/bg.gif +0 -0
- data/data/webgen/website_styles/andreas01/src/images/front.jpg +0 -0
- data/data/webgen/website_styles/andreas01/src/print.css +35 -0
- data/data/webgen/website_styles/andreas03/README +14 -0
- data/data/webgen/website_styles/andreas03/src/default.css +223 -0
- data/data/webgen/website_styles/andreas03/src/default.template +58 -0
- data/data/webgen/website_styles/andreas03/src/images/bodybg.png +0 -0
- data/data/webgen/website_styles/andreas03/src/images/contbg.png +0 -0
- data/data/webgen/website_styles/andreas03/src/images/footerbg.png +0 -0
- data/data/webgen/website_styles/andreas03/src/images/gradient1.png +0 -0
- data/data/webgen/website_styles/andreas03/src/images/gradient2.png +0 -0
- data/data/webgen/website_styles/andreas04/README +15 -0
- data/data/webgen/website_styles/andreas04/src/default.css +290 -0
- data/data/webgen/website_styles/andreas04/src/default.template +81 -0
- data/data/webgen/website_styles/andreas04/src/images/blinkarrow.gif +0 -0
- data/data/webgen/website_styles/andreas04/src/images/bodybg.png +0 -0
- data/data/webgen/website_styles/andreas04/src/images/contentbg.png +0 -0
- data/data/webgen/website_styles/andreas04/src/images/entrybg.png +0 -0
- data/data/webgen/website_styles/andreas04/src/images/flash.gif +0 -0
- data/data/webgen/website_styles/andreas04/src/images/flash2.gif +0 -0
- data/data/webgen/website_styles/andreas04/src/images/globe.gif +0 -0
- data/data/webgen/website_styles/andreas04/src/images/globebottom.gif +0 -0
- data/data/webgen/website_styles/andreas04/src/images/linkarrow.gif +0 -0
- data/data/webgen/website_styles/andreas04/src/images/menuhover.png +0 -0
- data/data/webgen/website_styles/andreas05/README +14 -0
- data/data/webgen/website_styles/andreas05/src/default.css +33 -0
- data/data/webgen/website_styles/andreas05/src/default.template +40 -0
- data/data/webgen/website_styles/andreas05/src/images/bodybg.gif +0 -0
- data/data/webgen/website_styles/andreas05/src/images/front.png +0 -0
- data/data/webgen/website_styles/andreas06/README +14 -0
- data/data/webgen/website_styles/andreas06/src/default.css +354 -0
- data/data/webgen/website_styles/andreas06/src/default.template +70 -0
- data/data/webgen/website_styles/andreas06/src/images/bodybg.gif +0 -0
- data/data/webgen/website_styles/andreas06/src/images/boxbg.gif +0 -0
- data/data/webgen/website_styles/andreas06/src/images/greypx.gif +0 -0
- data/data/webgen/website_styles/andreas06/src/images/header.jpg +0 -0
- data/data/webgen/website_styles/andreas06/src/images/innerbg.gif +0 -0
- data/data/webgen/website_styles/andreas06/src/images/leaves.jpg +0 -0
- data/data/webgen/website_styles/andreas06/src/images/tabs.gif +0 -0
- data/data/webgen/website_styles/andreas07/README +15 -0
- data/data/webgen/website_styles/andreas07/src/browserfix.css +7 -0
- data/data/webgen/website_styles/andreas07/src/default.css +92 -0
- data/data/webgen/website_styles/andreas07/src/default.template +42 -0
- data/data/webgen/website_styles/andreas07/src/images/bodybg.gif +0 -0
- data/data/webgen/website_styles/andreas07/src/images/sidebarbg.gif +0 -0
- data/data/webgen/website_styles/andreas08/README +14 -0
- data/data/webgen/website_styles/andreas08/src/default.css +224 -0
- data/data/webgen/website_styles/andreas08/src/default.template +51 -0
- data/data/webgen/website_styles/andreas09/README +14 -0
- data/data/webgen/website_styles/andreas09/src/default.css +308 -0
- data/data/webgen/website_styles/andreas09/src/default.template +68 -0
- data/data/webgen/website_styles/andreas09/src/images/bodybg-black.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/bodybg-green.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/bodybg-orange.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/bodybg-purple.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/bodybg-red.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/bodybg.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/footerbg.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/menuhover-black.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/menuhover-green.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/menuhover-orange.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/menuhover-purple.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/menuhover-red.jpg +0 -0
- data/data/webgen/website_styles/andreas09/src/images/menuhover.jpg +0 -0
- data/data/webgen/website_styles/simple/README +6 -0
- data/data/webgen/website_styles/simple/src/default.css +84 -0
- data/data/webgen/website_styles/simple/src/default.template +36 -0
- data/data/webgen/website_templates/default/README +6 -0
- data/data/webgen/website_templates/default/src/index.page +8 -0
- data/data/webgen/website_templates/project/README +5 -0
- data/data/webgen/website_templates/project/src/about.page +12 -0
- data/data/webgen/website_templates/project/src/download.page +15 -0
- data/data/webgen/website_templates/project/src/features.page +8 -0
- data/data/webgen/website_templates/project/src/index.page +9 -0
- data/data/webgen/website_templates/project/src/screenshots.page +18 -0
- data/doc/contentprocessor.template +11 -0
- data/doc/contentprocessor/blocks.page +66 -0
- data/doc/contentprocessor/builder.page +80 -0
- data/doc/contentprocessor/erb.page +56 -0
- data/doc/contentprocessor/erubis.page +46 -0
- data/doc/contentprocessor/haml.page +47 -0
- data/doc/contentprocessor/maruku.page +41 -0
- data/doc/contentprocessor/rdiscount.page +37 -0
- data/doc/contentprocessor/rdoc.page +36 -0
- data/doc/contentprocessor/redcloth.page +39 -0
- data/doc/contentprocessor/sass.page +31 -0
- data/doc/contentprocessor/tags.page +73 -0
- data/doc/extensions.metainfo +29 -0
- data/doc/extensions.page +16 -0
- data/doc/extensions.template +17 -0
- data/doc/faq.page +214 -0
- data/doc/getting_started.page +134 -0
- data/doc/index.page +65 -0
- data/doc/manual.page +532 -0
- data/doc/reference_configuration.page +646 -0
- data/doc/reference_metainfo.page +213 -0
- data/doc/sourcehandler.template +21 -0
- data/doc/sourcehandler/copy.page +19 -0
- data/doc/sourcehandler/directory.page +27 -0
- data/doc/sourcehandler/feed.page +82 -0
- data/doc/sourcehandler/metainfo.page +41 -0
- data/doc/sourcehandler/page.page +30 -0
- data/doc/sourcehandler/sitemap.page +46 -0
- data/doc/sourcehandler/template.page +45 -0
- data/doc/sourcehandler/virtual.page +49 -0
- data/doc/tag.template +25 -0
- data/doc/tag/breadcrumbtrail.page +40 -0
- data/doc/tag/coderay.page +49 -0
- data/doc/tag/date.page +31 -0
- data/doc/tag/executecommand.page +26 -0
- data/doc/tag/includefile.page +32 -0
- data/doc/tag/langbar.page +22 -0
- data/doc/tag/menu.page +92 -0
- data/doc/tag/metainfo.page +29 -0
- data/doc/tag/relocatable.page +38 -0
- data/doc/tag/sitemap.page +31 -0
- data/doc/upgrading.page +139 -0
- data/doc/webgen_page_format.page +128 -0
- data/lib/webgen/blackboard.rb +73 -0
- data/lib/webgen/cache.rb +85 -0
- data/lib/webgen/cli.rb +118 -0
- data/lib/webgen/cli/create_command.rb +64 -0
- data/lib/webgen/cli/run_command.rb +20 -0
- data/lib/webgen/cli/utils.rb +86 -0
- data/lib/webgen/cli/webgui_command.rb +49 -0
- data/lib/webgen/common.rb +10 -0
- data/lib/webgen/common/sitemap.rb +76 -0
- data/lib/webgen/configuration.rb +147 -0
- data/lib/webgen/contentprocessor.rb +96 -0
- data/lib/webgen/contentprocessor/blocks.rb +46 -0
- data/lib/webgen/contentprocessor/builder.rb +26 -0
- data/lib/webgen/contentprocessor/context.rb +90 -0
- data/lib/webgen/contentprocessor/erb.rb +24 -0
- data/lib/webgen/contentprocessor/erubis.rb +40 -0
- data/lib/webgen/contentprocessor/haml.rb +25 -0
- data/lib/webgen/contentprocessor/maruku.rb +18 -0
- data/lib/webgen/contentprocessor/rdiscount.rb +15 -0
- data/lib/webgen/contentprocessor/rdoc.rb +17 -0
- data/lib/webgen/contentprocessor/redcloth.rb +15 -0
- data/lib/webgen/contentprocessor/sass.rb +18 -0
- data/lib/webgen/contentprocessor/tags.rb +134 -0
- data/lib/webgen/coreext.rb +10 -0
- data/lib/webgen/default_config.rb +198 -0
- data/lib/webgen/languages.rb +578 -0
- data/lib/webgen/loggable.rb +23 -0
- data/lib/webgen/logger.rb +78 -0
- data/lib/webgen/node.rb +347 -0
- data/lib/webgen/output.rb +37 -0
- data/lib/webgen/output/filesystem.rb +67 -0
- data/lib/webgen/page.rb +133 -0
- data/lib/webgen/path.rb +182 -0
- data/lib/webgen/source.rb +24 -0
- data/lib/webgen/source/filesystem.rb +58 -0
- data/lib/webgen/source/resource.rb +42 -0
- data/lib/webgen/source/stacked.rb +53 -0
- data/lib/webgen/sourcehandler.rb +202 -0
- data/lib/webgen/sourcehandler/base.rb +211 -0
- data/lib/webgen/sourcehandler/copy.rb +41 -0
- data/lib/webgen/sourcehandler/directory.rb +31 -0
- data/lib/webgen/sourcehandler/feed.rb +121 -0
- data/lib/webgen/sourcehandler/fragment.rb +71 -0
- data/lib/webgen/sourcehandler/metainfo.rb +117 -0
- data/lib/webgen/sourcehandler/page.rb +77 -0
- data/lib/webgen/sourcehandler/sitemap.rb +60 -0
- data/lib/webgen/sourcehandler/template.rb +68 -0
- data/lib/webgen/sourcehandler/virtual.rb +75 -0
- data/lib/webgen/tag.rb +23 -0
- data/lib/webgen/tag/base.rb +162 -0
- data/lib/webgen/tag/breadcrumbtrail.rb +71 -0
- data/lib/webgen/tag/coderay.rb +32 -0
- data/lib/webgen/tag/date.rb +18 -0
- data/lib/webgen/tag/executecommand.rb +29 -0
- data/lib/webgen/tag/includefile.rb +42 -0
- data/lib/webgen/tag/langbar.rb +52 -0
- data/lib/webgen/tag/menu.rb +186 -0
- data/lib/webgen/tag/metainfo.rb +25 -0
- data/lib/webgen/tag/relocatable.rb +53 -0
- data/lib/webgen/tag/sitemap.rb +42 -0
- data/lib/webgen/tree.rb +80 -0
- data/lib/webgen/version.rb +6 -0
- data/lib/webgen/webgentask.rb +148 -0
- data/lib/webgen/website.rb +214 -0
- data/lib/webgen/websiteaccess.rb +29 -0
- data/lib/webgen/websitemanager.rb +125 -0
- data/man/man1/webgen.1 +67 -0
- data/misc/default.css +360 -0
- data/misc/default.template +75 -0
- data/misc/htmldoc.metainfo +25 -0
- data/misc/htmldoc.virtual +5 -0
- data/misc/images/arrow.gif +0 -0
- data/misc/images/error.gif +0 -0
- data/misc/images/exclamation.gif +0 -0
- data/misc/images/headerbg.jpg +0 -0
- data/misc/images/information.gif +0 -0
- data/misc/images/quote.gif +0 -0
- data/setup.rb +1585 -0
- data/test/helper.rb +41 -0
- data/test/test_blackboard.rb +58 -0
- data/test/test_cache.rb +57 -0
- data/test/test_common_sitemap.rb +56 -0
- data/test/test_configuration.rb +66 -0
- data/test/test_contentprocessor.rb +31 -0
- data/test/test_contentprocessor_blocks.rb +34 -0
- data/test/test_contentprocessor_builder.rb +19 -0
- data/test/test_contentprocessor_context.rb +38 -0
- data/test/test_contentprocessor_erb.rb +20 -0
- data/test/test_contentprocessor_erubis.rb +47 -0
- data/test/test_contentprocessor_haml.rb +20 -0
- data/test/test_contentprocessor_maruku.rb +27 -0
- data/test/test_contentprocessor_rdiscount.rb +15 -0
- data/test/test_contentprocessor_rdoc.rb +16 -0
- data/test/test_contentprocessor_redcloth.rb +12 -0
- data/test/test_contentprocessor_sass.rb +20 -0
- data/test/test_contentprocessor_tags.rb +97 -0
- data/test/test_languages.rb +53 -0
- data/test/test_loggable.rb +30 -0
- data/test/test_logger.rb +73 -0
- data/test/test_node.rb +339 -0
- data/test/test_output_filesystem.rb +58 -0
- data/test/test_page.rb +203 -0
- data/test/test_path.rb +131 -0
- data/test/test_source_filesystem.rb +59 -0
- data/test/test_source_resource.rb +26 -0
- data/test/test_source_stacked.rb +34 -0
- data/test/test_sourcehandler_base.rb +92 -0
- data/test/test_sourcehandler_copy.rb +45 -0
- data/test/test_sourcehandler_directory.rb +25 -0
- data/test/test_sourcehandler_feed.rb +74 -0
- data/test/test_sourcehandler_fragment.rb +67 -0
- data/test/test_sourcehandler_metainfo.rb +93 -0
- data/test/test_sourcehandler_page.rb +70 -0
- data/test/test_sourcehandler_sitemap.rb +47 -0
- data/test/test_sourcehandler_template.rb +63 -0
- data/test/test_sourcehandler_virtual.rb +56 -0
- data/test/test_tag_base.rb +82 -0
- data/test/test_tag_breadcrumbtrail.rb +89 -0
- data/test/test_tag_coderay.rb +30 -0
- data/test/test_tag_date.rb +16 -0
- data/test/test_tag_executecommand.rb +39 -0
- data/test/test_tag_includefile.rb +48 -0
- data/test/test_tag_langbar.rb +60 -0
- data/test/test_tag_menu.rb +195 -0
- data/test/test_tag_metainfo.rb +17 -0
- data/test/test_tag_relocatable.rb +57 -0
- data/test/test_tag_sitemap.rb +44 -0
- data/test/test_tree.rb +69 -0
- data/test/test_webgentask.rb +21 -0
- data/test/test_website.rb +96 -0
- data/test/test_websiteaccess.rb +23 -0
- data/test/test_websitemanager.rb +68 -0
- metadata +575 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
module Webgen::SourceHandler
|
2
|
+
|
3
|
+
# Simple source handler for copying files from the source tree, either verbatim or by applying a
|
4
|
+
# content processor.
|
5
|
+
class Copy
|
6
|
+
|
7
|
+
include Webgen::WebsiteAccess
|
8
|
+
include Base
|
9
|
+
|
10
|
+
# Create the node for +parent+ and +path+. If the +path+ has the name of a content processor in
|
11
|
+
# the extension, it is preprocessed.
|
12
|
+
def create_node(parent, path)
|
13
|
+
if path.ext.index('.')
|
14
|
+
processor, *rest = path.ext.split('.')
|
15
|
+
if website.blackboard.invoke(:content_processor_names).include?(processor)
|
16
|
+
path.ext = rest.join('.')
|
17
|
+
else
|
18
|
+
processor = nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
super(parent, path) do |node|
|
22
|
+
node.node_info[:preprocessor] = processor
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return either the preprocessed content of the +node+ or the IO object for the node's source
|
27
|
+
# path depending on the node type.
|
28
|
+
def content(node)
|
29
|
+
io = website.blackboard.invoke(:source_paths)[node.node_info[:src]].io
|
30
|
+
if node.node_info[:preprocessor]
|
31
|
+
context = Webgen::ContentProcessor::Context.new(:content => io.data, :chain => [node])
|
32
|
+
website.blackboard.invoke(:content_processor, node.node_info[:preprocessor]).call(context)
|
33
|
+
context.content
|
34
|
+
else
|
35
|
+
io
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'webgen/sourcehandler/base'
|
2
|
+
|
3
|
+
module Webgen::SourceHandler
|
4
|
+
|
5
|
+
# Handles directory source paths.
|
6
|
+
class Directory
|
7
|
+
|
8
|
+
include Base
|
9
|
+
|
10
|
+
# Creation of directory nodes is special because once they are created, they are only deleted
|
11
|
+
# when the source path gets deleted. Otherwise, only the meta information of the node gets
|
12
|
+
# updated.
|
13
|
+
def create_node(parent, path)
|
14
|
+
if node = node_exists?(parent, path)
|
15
|
+
node.meta_info.clear
|
16
|
+
node.meta_info.update(path.meta_info)
|
17
|
+
node.dirty = true
|
18
|
+
node
|
19
|
+
else
|
20
|
+
super(parent, path)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Return an empty string to signal that the directory should be written to the output.
|
25
|
+
def content(node)
|
26
|
+
''
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'webgen/websiteaccess'
|
2
|
+
require 'webgen/sourcehandler/base'
|
3
|
+
|
4
|
+
module Webgen::SourceHandler
|
5
|
+
|
6
|
+
# Source handler for creating atom and/or rss feeds.
|
7
|
+
class Feed
|
8
|
+
|
9
|
+
include Webgen::WebsiteAccess
|
10
|
+
include Base
|
11
|
+
|
12
|
+
# The mandatory keys that need to be set in a feed file.
|
13
|
+
MANDATORY_INFOS = %W[site_url author entries]
|
14
|
+
|
15
|
+
def initialize # :nodoc:
|
16
|
+
website.blackboard.add_listener(:node_changed?, method(:node_changed?))
|
17
|
+
end
|
18
|
+
|
19
|
+
# Create atom and/or rss feed files from +parent+ and +path+.
|
20
|
+
def create_node(parent, path)
|
21
|
+
page = page_from_path(path)
|
22
|
+
path.meta_info['link'] ||= parent.absolute_lcn
|
23
|
+
|
24
|
+
if MANDATORY_INFOS.any? {|t| path.meta_info[t].nil?}
|
25
|
+
raise "One of #{MANDATORY_INFOS.join('/')} information missing for feed <#{path}>"
|
26
|
+
end
|
27
|
+
|
28
|
+
create_feed_node = lambda do |type|
|
29
|
+
path.ext = type
|
30
|
+
super(parent, path) do |node|
|
31
|
+
node.node_info[:feed] = page
|
32
|
+
node.node_info[:feed_type] = type
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
nodes = []
|
37
|
+
nodes << create_feed_node['atom'] if path.meta_info['atom']
|
38
|
+
nodes << create_feed_node['rss'] if path.meta_info['rss']
|
39
|
+
|
40
|
+
nodes
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return the rendered feed represented by +node+.
|
44
|
+
def content(node)
|
45
|
+
website.cache[[:sourcehandler_feed, node.node_info[:src]]] = feed_entries(node).map {|n| n.absolute_lcn}
|
46
|
+
block_name = node.node_info[:feed_type] + '_template'
|
47
|
+
if node.node_info[:feed].blocks.has_key?(block_name)
|
48
|
+
node.node_info[:feed].blocks[block_name].
|
49
|
+
render(Webgen::ContentProcessor::Context.new(:chain => [node])).content
|
50
|
+
else
|
51
|
+
feed = (website.cache.volatile[:sourcehandler_feed] ||= {})[node.node_info[:src]] ||= build_feed_for(node)
|
52
|
+
feed.feed_type = node.node_info[:feed_type]
|
53
|
+
feed.build_xml
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Helper method for returning the entries for the feed node +node+.
|
58
|
+
def feed_entries(node)
|
59
|
+
nr_items = (node['number_of_entries'].to_i == 0 ? 10 : node['number_of_entries'].to_i)
|
60
|
+
patterns = [node['entries']].flatten.map {|pat| Pathname.new(pat =~ /^\// ? pat : File.join(node.parent.absolute_lcn, pat)).cleanpath.to_s}
|
61
|
+
|
62
|
+
node.tree.node_access[:alcn].values.
|
63
|
+
select {|node| patterns.any? {|pat| node =~ pat} && node.node_info[:page]}.
|
64
|
+
sort {|a,b| a['modified_at'] <=> b['modified_at']}.
|
65
|
+
reverse[0, nr_items]
|
66
|
+
end
|
67
|
+
|
68
|
+
#######
|
69
|
+
private
|
70
|
+
#######
|
71
|
+
|
72
|
+
# Return the populated FeedTools::Feed object for +node+.
|
73
|
+
def build_feed_for(node)
|
74
|
+
require 'feed_tools'
|
75
|
+
require 'time'
|
76
|
+
|
77
|
+
site_url = node['site_url']
|
78
|
+
|
79
|
+
feed = FeedTools::Feed.new
|
80
|
+
feed.title = node['title']
|
81
|
+
feed.description = node['description']
|
82
|
+
feed.author = node['author']
|
83
|
+
feed.author.url = node['author_url']
|
84
|
+
feed.base_uri = site_url
|
85
|
+
feed.link = File.join(site_url, node.tree[node['link']].path)
|
86
|
+
feed.id = feed.link
|
87
|
+
|
88
|
+
feed.published = (node['created_at'].kind_of?(Time) ? node['created_at'] : Time.now)
|
89
|
+
feed.updated = Time.now
|
90
|
+
feed.generator = 'webgen - Webgen::SourceHandler::Feed'
|
91
|
+
feed.icon = File.join(site_url, node.tree[node['icon']].path) if node['icon']
|
92
|
+
|
93
|
+
node.feed_entries.each do |entry|
|
94
|
+
item = FeedTools::FeedItem.new
|
95
|
+
item.title = entry['title']
|
96
|
+
item.link = File.join(site_url, entry.path)
|
97
|
+
item.content = entry.node_info[:page].blocks['content'].render(Webgen::ContentProcessor::Context.new(:chain => [entry])).content
|
98
|
+
item.updated = entry['modified_at']
|
99
|
+
item.published = entry['created_at'] if entry['created_at'].kind_of?(Time)
|
100
|
+
if entry['author']
|
101
|
+
item.author = entry['author']
|
102
|
+
item.author.url = entry['author_url']
|
103
|
+
end
|
104
|
+
item.id = item.link
|
105
|
+
feed << item
|
106
|
+
end
|
107
|
+
feed
|
108
|
+
end
|
109
|
+
|
110
|
+
# Check if the +node+ has meta information from any meta info node and if so, if the meta info
|
111
|
+
# node in question has changed.
|
112
|
+
def node_changed?(node)
|
113
|
+
return if node.node_info[:processor] != self.class.name
|
114
|
+
entries = node.feed_entries
|
115
|
+
node.dirty = true if entries.map {|n| n.absolute_lcn } != website.cache[[:sourcehandler_feed, node.node_info[:src]]] ||
|
116
|
+
entries.any? {|n| n.changed?}
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'webgen/sourcehandler/base'
|
2
|
+
require 'webgen/websiteaccess'
|
3
|
+
|
4
|
+
module Webgen::SourceHandler
|
5
|
+
|
6
|
+
# Handles page fragment nodes and provides utility methods for parsing HTML headers and generating
|
7
|
+
# fragment nodes from them.
|
8
|
+
class Fragment
|
9
|
+
|
10
|
+
include Base
|
11
|
+
include Webgen::WebsiteAccess
|
12
|
+
|
13
|
+
HTML_HEADER_REGEXP = /<h([123456])(?:>|\s([^>]*)>)(.*?)<\/h\1\s*>/i
|
14
|
+
HTML_ATTR_REGEXP = /\s*(\w+)\s*=\s*('|")([^\2]+)\2\s*/
|
15
|
+
|
16
|
+
# Parse the string +content+ for headers +h1+, ..., +h6+ and return the found, nested sections.
|
17
|
+
#
|
18
|
+
# Only those headers are used which have an +id+ attribute set. The method returns a list of
|
19
|
+
# arrays with entries <tt>level, id, title, sub sections</tt> where <tt>sub sections</tt> is
|
20
|
+
# such a list again.
|
21
|
+
def parse_html_headers(content)
|
22
|
+
sections = []
|
23
|
+
stack = []
|
24
|
+
content.scan(HTML_HEADER_REGEXP).each do |level,attrs,title|
|
25
|
+
next if attrs.nil?
|
26
|
+
id_attr = attrs.scan(HTML_ATTR_REGEXP).find {|name,sep,value| name == 'id'}
|
27
|
+
next if id_attr.nil?
|
28
|
+
id = id_attr[2]
|
29
|
+
|
30
|
+
section = [level.to_i, id, title, []]
|
31
|
+
success = false
|
32
|
+
while !success
|
33
|
+
if stack.empty?
|
34
|
+
sections << section
|
35
|
+
stack << section
|
36
|
+
success = true
|
37
|
+
elsif stack.last.first < section.first
|
38
|
+
stack.last.last << section
|
39
|
+
stack << section
|
40
|
+
success = true
|
41
|
+
else
|
42
|
+
stack.pop
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
sections
|
47
|
+
end
|
48
|
+
|
49
|
+
# Create nested fragment nodes under +parent+ from +sections+ (which can be created using
|
50
|
+
# +parse_html_headers+). +path+ is the source path that defines the fragments. The meta
|
51
|
+
# information +in_menu+ of the fragment nodes is set to the parameter +in_menu+ and the meta
|
52
|
+
# info +sort_info+ is calculated from the base +si+ value.
|
53
|
+
def create_fragment_nodes(sections, parent, path, in_menu, si = 1000 )
|
54
|
+
sections.each do |level, id, title, sub_sections|
|
55
|
+
node = website.blackboard.invoke(:create_nodes, parent.tree, parent.absolute_lcn,
|
56
|
+
path, self) do |cn_parent, cn_path|
|
57
|
+
ptemp = Webgen::Path.new('#' + id)
|
58
|
+
ptemp.meta_info = cn_path.meta_info.merge(ptemp.meta_info)
|
59
|
+
create_node(cn_parent, ptemp)
|
60
|
+
end.first
|
61
|
+
node['title'] = title
|
62
|
+
node['in_menu'] = in_menu
|
63
|
+
node['sort_info'] = si = si.succ
|
64
|
+
node.node_info[:src] = path.path
|
65
|
+
create_fragment_nodes(sub_sections, node, path, in_menu, si.succ)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'yaml'
|
3
|
+
require 'webgen/sourcehandler/base'
|
4
|
+
require 'webgen/websiteaccess'
|
5
|
+
|
6
|
+
module Webgen::SourceHandler
|
7
|
+
|
8
|
+
# Handles meta information files which provide meta information for other files.
|
9
|
+
class Metainfo
|
10
|
+
|
11
|
+
include Base
|
12
|
+
include Webgen::WebsiteAccess
|
13
|
+
|
14
|
+
CKEY = [:metainfo, :nodes]
|
15
|
+
|
16
|
+
# Upon creation the object registers itself as listener for some node hooks.
|
17
|
+
def initialize
|
18
|
+
website.blackboard.add_listener(:node_meta_info_changed?, method(:node_meta_info_changed?))
|
19
|
+
website.blackboard.add_listener(:before_node_created, method(:before_node_created))
|
20
|
+
website.blackboard.add_listener(:before_node_deleted, method(:before_node_deleted))
|
21
|
+
website.blackboard.add_listener(:after_node_created, method(:after_node_created))
|
22
|
+
self.nodes ||= Set.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# Create a meta info node from +parent+ and +path+.
|
26
|
+
def create_node(parent, path)
|
27
|
+
page = page_from_path(path)
|
28
|
+
super(parent, path) do |node|
|
29
|
+
[[:mi_paths, 'paths'], [:mi_alcn, 'alcn']].each do |mi_key, block_name|
|
30
|
+
node.node_info[mi_key] = {}
|
31
|
+
YAML::load(page.blocks[block_name].content).each do |key, value|
|
32
|
+
key = Pathname.new(key =~ /^\// ? key : File.join(parent.absolute_lcn, key)).cleanpath.to_s
|
33
|
+
key.chomp('/') unless key == '/'
|
34
|
+
node.node_info[mi_key][key] = value
|
35
|
+
end if page.blocks.has_key?(block_name)
|
36
|
+
end
|
37
|
+
website.cache[[:sh_metainfo_node_mi, node.absolute_lcn]] = {
|
38
|
+
:mi_paths => node.node_info[:mi_paths],
|
39
|
+
:mi_alcn => node.node_info[:mi_alcn]
|
40
|
+
}
|
41
|
+
|
42
|
+
mark_all_matched_dirty(node)
|
43
|
+
|
44
|
+
self.nodes << node
|
45
|
+
self.nodes = self.nodes.sort_by {|n| n.absolute_lcn}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def nodes #:nodoc:
|
50
|
+
website.cache.permanent[CKEY]
|
51
|
+
end
|
52
|
+
|
53
|
+
def nodes=(val) #:nodoc:
|
54
|
+
website.cache.permanent[CKEY] = val
|
55
|
+
end
|
56
|
+
|
57
|
+
#######
|
58
|
+
private
|
59
|
+
#######
|
60
|
+
|
61
|
+
# Return +true+ if any meta information for +node+ provided by +mi_node+ has changed.
|
62
|
+
def meta_info_changed?(mi_node, node, use_cache = true)
|
63
|
+
use_cache = false if !website.cache.old_data[[:sh_metainfo_node_mi, mi_node.absolute_lcn]]
|
64
|
+
cached = website.cache[[:sh_metainfo_node_mi, mi_node.absolute_lcn]]
|
65
|
+
path = website.blackboard.invoke(:source_paths)[node.node_info[:src]]
|
66
|
+
(mi_node.node_info[:mi_paths].any? {|pattern, mi| path =~ pattern && (!use_cache || mi != cached[:mi_paths][pattern])} ||
|
67
|
+
mi_node.node_info[:mi_alcn].any? {|pattern, mi| node =~ pattern && (!use_cache || mi != cached[:mi_alcn][pattern])})
|
68
|
+
end
|
69
|
+
|
70
|
+
# Mark all nodes that are matched by a path or an alcn specifcation in the meta info node +node+
|
71
|
+
# as dirty.
|
72
|
+
def mark_all_matched_dirty(node, use_cache = true)
|
73
|
+
node.tree.node_access[:alcn].each do |path, n|
|
74
|
+
n.dirty_meta_info = true if meta_info_changed?(node, n, use_cache)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Update the meta info of matched path before a node is created.
|
79
|
+
def before_node_created(parent, path)
|
80
|
+
self.nodes.each do |node|
|
81
|
+
node.node_info[:mi_paths].each do |pattern, mi|
|
82
|
+
path.meta_info.update(mi) if path =~ pattern
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Update the meta information of a matched alcn after the node has been created.
|
88
|
+
def after_node_created(node)
|
89
|
+
self.nodes.each do |n|
|
90
|
+
n.node_info[:mi_alcn].each do |pattern, mi|
|
91
|
+
node.meta_info.update(mi) if node =~ pattern
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Check if the +node+ has meta information from any meta info node and if so, if the meta info
|
97
|
+
# node in question has changed.
|
98
|
+
def node_meta_info_changed?(node)
|
99
|
+
return if self.nodes.include?(node)
|
100
|
+
self.nodes.each do |n|
|
101
|
+
if n.created && meta_info_changed?(n, node)
|
102
|
+
node.dirty_meta_info = true
|
103
|
+
return
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Delete the meta info node +node+ from the internal array.
|
109
|
+
def before_node_deleted(node)
|
110
|
+
return unless node.node_info[:processor] == self.class.name
|
111
|
+
mark_all_matched_dirty(node, false) if !website.blackboard.invoke(:source_paths).include?(node.node_info[:src])
|
112
|
+
self.nodes.delete(node)
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'webgen/websiteaccess'
|
2
|
+
require 'webgen/sourcehandler/base'
|
3
|
+
|
4
|
+
module Webgen::SourceHandler
|
5
|
+
|
6
|
+
# Source handler for handling content files in Webgen Page Format.
|
7
|
+
class Page
|
8
|
+
|
9
|
+
include Webgen::WebsiteAccess
|
10
|
+
include Base
|
11
|
+
|
12
|
+
def initialize #:nodoc:
|
13
|
+
website.blackboard.add_listener(:node_meta_info_changed?, method(:meta_info_changed?))
|
14
|
+
end
|
15
|
+
|
16
|
+
# Create a page file from +parent+ and +path+.
|
17
|
+
def create_node(parent, path)
|
18
|
+
page = page_from_path(path)
|
19
|
+
path.meta_info['lang'] ||= website.config['website.lang']
|
20
|
+
path.ext = 'html' if path.ext == 'page'
|
21
|
+
|
22
|
+
super(parent, path) do |node|
|
23
|
+
website.cache[[:sh_page_node_mi, node.absolute_lcn]] = node.meta_info.dup
|
24
|
+
|
25
|
+
node.node_info[:page] = page
|
26
|
+
tmp_logger = website.logger
|
27
|
+
website.logger = nil # disabling logging whiling creating fragment nodes
|
28
|
+
|
29
|
+
website.cache.permanent[:page_sections] ||= {}
|
30
|
+
sections = if path.changed? || !website.cache.permanent[:page_sections][node.absolute_lcn]
|
31
|
+
website.blackboard.invoke(:parse_html_headers, render_node(node, 'content', []))
|
32
|
+
else
|
33
|
+
website.cache.permanent[:page_sections][node.absolute_lcn]
|
34
|
+
end
|
35
|
+
website.cache.permanent[:page_sections][node.absolute_lcn] = sections
|
36
|
+
website.blackboard.invoke(:create_fragment_nodes,
|
37
|
+
sections,
|
38
|
+
node, website.blackboard.invoke(:source_paths)[path.path],
|
39
|
+
node.meta_info['fragments_in_menu'])
|
40
|
+
website.logger = tmp_logger
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Render the block called +block_name+ of the given +node+. The parameter +templates+ is set to
|
45
|
+
# the default template chain for the given +node+ but you can assign a custom template chain (an
|
46
|
+
# array of template nodes) if need arises. Return +nil+ if an error occurred.
|
47
|
+
def render_node(node, block_name = 'content', templates = website.blackboard.invoke(:templates_for_node, node))
|
48
|
+
chain = [templates, node].flatten
|
49
|
+
|
50
|
+
if chain.first.node_info[:page].blocks.has_key?(block_name)
|
51
|
+
node.node_info[:used_nodes] << chain.first.absolute_lcn
|
52
|
+
context = chain.first.node_info[:page].blocks[block_name].render(Webgen::ContentProcessor::Context.new(:chain => chain))
|
53
|
+
context.content
|
54
|
+
else
|
55
|
+
raise "Error rendering <#{node.absolute_lcn}>: no block named '#{block_name}' in <#{chain.first.absolute_lcn}>"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
alias_method :content, :render_node
|
59
|
+
|
60
|
+
#######
|
61
|
+
private
|
62
|
+
#######
|
63
|
+
|
64
|
+
# Checks if the meta information provided by the file in Webgen Page Format changed.
|
65
|
+
def meta_info_changed?(node)
|
66
|
+
return if !node.created || node.node_info[:processor] != self.class.name
|
67
|
+
ckey = [:sh_page_node_mi, node.absolute_lcn]
|
68
|
+
old_mi = website.cache.old_data[ckey]
|
69
|
+
old_mi.delete('modified_at') if old_mi
|
70
|
+
new_mi = website.cache.new_data[ckey]
|
71
|
+
new_mi.delete('modified_at')
|
72
|
+
node.dirty_meta_info = true if old_mi != new_mi
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|