hobix 0.4 → 0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +18 -0
- data/README +18 -0
- data/Rakefile +96 -0
- data/bin/hobix +7 -3
- data/contrib/blosxom-to-hobix.rb +253 -0
- data/contrib/txp-to-hobix.rb +56 -0
- data/contrib/webrick-all-mine.rb +20 -0
- data/doc/CHANGELOG +285 -0
- data/doc/rdoc/classes/Hobix/API.html +382 -0
- data/doc/rdoc/classes/Hobix/Article.html +111 -0
- data/doc/rdoc/classes/Hobix/BaseContent.html +692 -0
- data/doc/rdoc/classes/Hobix/BaseEntry.html +218 -0
- data/doc/rdoc/classes/Hobix/BaseFacet.html +205 -0
- data/doc/rdoc/classes/Hobix/BaseOutput.html +122 -0
- data/doc/rdoc/classes/Hobix/BasePlugin.html +201 -0
- data/doc/rdoc/classes/Hobix/BaseProperties/ClassMethods.html +243 -0
- data/doc/rdoc/classes/Hobix/BaseProperties.html +218 -0
- data/doc/rdoc/classes/Hobix/BasePublish.html +157 -0
- data/doc/rdoc/classes/Hobix/BaseStorage.html +417 -0
- data/doc/rdoc/classes/Hobix/BixWik/Entry.html +196 -0
- data/doc/rdoc/classes/Hobix/BixWik/IndexEntry.html +170 -0
- data/doc/rdoc/classes/Hobix/BixWik/WikiRedCloth.html +111 -0
- data/doc/rdoc/classes/Hobix/BixWik.html +418 -0
- data/doc/rdoc/classes/Hobix/BixWikPlugin.html +158 -0
- data/doc/rdoc/classes/Hobix/CommandLine.html +1970 -0
- data/doc/rdoc/classes/Hobix/Comment.html +113 -0
- data/doc/rdoc/classes/Hobix/Config.html +212 -0
- data/doc/rdoc/classes/Hobix/DataMarsh.html +667 -0
- data/doc/rdoc/classes/Hobix/Entry.html +178 -0
- data/doc/rdoc/classes/Hobix/EntryEnum.html +162 -0
- data/doc/rdoc/classes/Hobix/Enumerable.html +170 -0
- data/doc/rdoc/classes/Hobix/Facets/WikiEdit.html +180 -0
- data/doc/rdoc/classes/Hobix/Facets.html +111 -0
- data/doc/rdoc/classes/Hobix/LinkList.html +182 -0
- data/doc/rdoc/classes/Hobix/Out/Quick.html +412 -0
- data/doc/rdoc/classes/Hobix/Out.html +119 -0
- data/doc/rdoc/classes/Hobix/Page.html +381 -0
- data/doc/rdoc/classes/Hobix/Trackback.html +113 -0
- data/doc/rdoc/classes/Hobix/UriStr.html +198 -0
- data/doc/rdoc/classes/Hobix/WebApp/QueryString.html +207 -0
- data/doc/rdoc/classes/Hobix/WebApp/QueryValidationFailure.html +111 -0
- data/doc/rdoc/classes/Hobix/WebApp.html +1383 -0
- data/doc/rdoc/classes/Hobix/Weblog/AuthorNotFound.html +111 -0
- data/doc/rdoc/classes/Hobix/Weblog.html +2082 -0
- data/doc/rdoc/classes/Hobix.html +399 -0
- data/doc/rdoc/classes/Kernel.html +139 -0
- data/doc/rdoc/classes/Regexp.html +154 -0
- data/doc/rdoc/classes/YAML/Omap.html +144 -0
- data/doc/rdoc/classes/YAML.html +111 -0
- data/doc/rdoc/created.rid +1 -0
- data/doc/rdoc/files/COPYING.html +129 -0
- data/doc/rdoc/files/README.html +131 -0
- data/doc/rdoc/files/doc/CHANGELOG.html +101 -0
- data/doc/rdoc/files/lib/hobix/api_rb.html +119 -0
- data/doc/rdoc/files/lib/hobix/article_rb.html +126 -0
- data/doc/rdoc/files/lib/hobix/base_rb.html +128 -0
- data/doc/rdoc/files/lib/hobix/bixwik_rb.html +126 -0
- data/doc/rdoc/files/lib/hobix/commandline_rb.html +140 -0
- data/doc/rdoc/files/lib/hobix/comments_rb.html +126 -0
- data/doc/rdoc/files/lib/hobix/config_rb.html +125 -0
- data/doc/rdoc/files/lib/hobix/datamarsh_rb.html +108 -0
- data/doc/rdoc/files/lib/hobix/entry_rb.html +118 -0
- data/doc/rdoc/files/lib/hobix/linklist_rb.html +127 -0
- data/doc/rdoc/files/lib/hobix/publisher_rb.html +126 -0
- data/doc/rdoc/files/lib/hobix/trackbacks_rb.html +128 -0
- data/doc/rdoc/files/lib/hobix/webapp_rb.html +127 -0
- data/doc/rdoc/files/lib/hobix/weblog_rb.html +135 -0
- data/doc/rdoc/files/lib/hobix_rb.html +127 -0
- data/doc/rdoc/fr_class_index.html +67 -0
- data/doc/rdoc/fr_file_index.html +44 -0
- data/doc/rdoc/fr_method_index.html +307 -0
- data/doc/rdoc/index.html +24 -0
- data/doc/rdoc/rdoc-style.css +208 -0
- data/git_hobix_update.php +13 -0
- data/lib/hobix/base.rb +6 -3
- data/lib/hobix/bixwik.rb +12 -12
- data/lib/hobix/commandline.rb +18 -2
- data/lib/hobix/comments.rb +4 -5
- data/lib/hobix/entry.rb +2 -1
- data/lib/hobix/facets/comments.rb +31 -6
- data/lib/hobix/linklist.rb +6 -1
- data/lib/hobix/out/atom.rb +29 -20
- data/lib/hobix/out/quick.rb +8 -6
- data/lib/hobix/out/rss.rb +16 -3
- data/lib/hobix/plugin/akismet.rb +196 -0
- data/lib/hobix/plugin/calendar.rb +6 -14
- data/lib/hobix/plugin/recent_comments.rb +4 -2
- data/lib/hobix/plugin/tags.rb +1 -1
- data/lib/hobix/storage/filesys.rb +41 -31
- data/lib/hobix/trackbacks.rb +1 -2
- data/lib/hobix/weblog.rb +73 -40
- data/lib/hobix.rb +9 -2
- data/share/default-blog/hobix.yaml +16 -0
- data/share/default-blog/htdocs/site.css +174 -0
- data/share/default-blog/skel/entry.html.quick +0 -0
- data/share/default-blog/skel/index.atom.atom +0 -0
- data/share/default-blog/skel/index.html.quick-summary +0 -0
- data/share/default-blog/skel/index.xml.rss +0 -0
- data/share/default-blog/skel/index.yaml.okaynews +0 -0
- data/share/default-blog/skel/monthly.html.quick-archive +0 -0
- data/share/default-blog/skel/section.html.quick-archive +0 -0
- data/share/default-blog/skel/yearly.html.quick-archive +0 -0
- data/share/default-blog-modes.yaml +7 -0
- data/share/default-blog.apache-cgi.patch +8 -0
- data/share/default-blog.apache-ssi.patch +38 -0
- data/share/default-blog.apache2-ssi.patch +3 -0
- data/share/default-blog.cgi.patch +8 -0
- data/share/default-blog.comments.patch +5 -0
- data/share/default-blog.prototype.patch +766 -0
- data/share/default-blog.publisher.patch +5 -0
- data/share/default-blog.wiki.patch +29 -0
- data/share/publisher/css/control.css +90 -0
- data/share/publisher/css/form.css +238 -0
- data/share/publisher/css/form.import.css +72 -0
- data/share/publisher/css/main-menu.css +134 -0
- data/share/publisher/i/hobix-emblazen-1.png +0 -0
- data/share/publisher/i/hobix-emblazen-2.png +0 -0
- data/share/publisher/i/hobix-emblazen-3.png +0 -0
- data/share/publisher/i/hobix-emblazen-4.png +0 -0
- data/share/publisher/i/hobix-emblazen-5.png +0 -0
- data/share/publisher/i/hobix-emblazen-6.png +0 -0
- data/share/publisher/i/hobix-emblazen-7.png +0 -0
- data/share/publisher/index.erb +66 -0
- data/share/publisher/js/controls.js +261 -0
- data/share/publisher/js/dragdrop.js +476 -0
- data/share/publisher/js/effects.js +570 -0
- data/share/publisher/js/prototype.js +1011 -0
- metadata +196 -53
- checksums.yaml +0 -7
data/lib/hobix/out/rss.rb
CHANGED
@@ -15,6 +15,7 @@
|
|
15
15
|
#++
|
16
16
|
require 'hobix/base'
|
17
17
|
require 'rexml/document'
|
18
|
+
require 'erb'
|
18
19
|
|
19
20
|
module Hobix
|
20
21
|
module Out
|
@@ -52,7 +53,7 @@ class RSS < Hobix::BaseOutput
|
|
52
53
|
</rss>
|
53
54
|
EOXML
|
54
55
|
rssdoc << REXML::XMLDecl.new
|
55
|
-
rssdoc.elements['/rss/channel/title'].text = vars[:weblog].title
|
56
|
+
rssdoc.elements['/rss/channel/title'].text = rss_mangle( vars[:weblog].title )
|
56
57
|
rssdoc.elements['/rss/channel/link'].text = vars[:weblog].link.to_s
|
57
58
|
rssdoc.elements['/rss/channel/description'].text = vars[:weblog].tagline
|
58
59
|
rssdoc.elements['/rss/channel/dc:date'].text = Time.now.utc.strftime( "%Y-%m-%dT%H:%M:%S+00:00" )
|
@@ -69,7 +70,7 @@ EOXML
|
|
69
70
|
( vars[:entries] || [vars[:entry]] ).each do |e|
|
70
71
|
ele = REXML::Element.new 'item'
|
71
72
|
ele_title = REXML::Element.new 'title'
|
72
|
-
ele_title.text = e.title
|
73
|
+
ele_title.text = rss_mangle( e.title )
|
73
74
|
ele << ele_title
|
74
75
|
ele_link = REXML::Element.new 'link'
|
75
76
|
link = e.link.gsub(/'/,"%27")
|
@@ -99,17 +100,29 @@ EOXML
|
|
99
100
|
ele_pubDate.text = ( e.modified || e.created ).dup.utc.strftime( "%Y-%m-%dT%H:%M:%S+00:00" )
|
100
101
|
ele << ele_pubDate
|
101
102
|
ele_desc = REXML::Element.new 'description'
|
102
|
-
ele_desc.
|
103
|
+
ele_desc.attributes['xml:space'] = "preserve"
|
104
|
+
text =
|
103
105
|
if @summaries && e.summary
|
104
106
|
e.summary.to_html + (@more_link ? %{<p><a href="#{e.link}">#@more_link</a></p>} : "")
|
105
107
|
else
|
106
108
|
e.content.to_html
|
107
109
|
end.gsub( /(src|href)="\//, "\\1=\"#{ vars[:weblog].link.rooturi }/" )
|
110
|
+
# Quote the text ourselves rather than letting REXML do it,
|
111
|
+
# due to REXML bug where it fails to quote e.g. →
|
112
|
+
REXML::Text.new ::ERB::Util.h( text ), true, ele_desc, true
|
108
113
|
ele << ele_desc
|
109
114
|
rssdoc.elements['/rss/channel'].add ele
|
110
115
|
end
|
111
116
|
rssdoc.to_s
|
112
117
|
end
|
118
|
+
|
119
|
+
private
|
120
|
+
def rss_mangle( string )
|
121
|
+
string = string.gsub( /&/, '[and]' )
|
122
|
+
string.gsub!( /</, '[less-than]' )
|
123
|
+
string.gsub!( />/, '[greater-than]' )
|
124
|
+
string
|
125
|
+
end
|
113
126
|
end
|
114
127
|
end
|
115
128
|
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
## akismet.rb -- Hobix akismet plugin
|
2
|
+
##
|
3
|
+
## Adds spam comment blocking to Hobix comments support. It does this
|
4
|
+
## using David Czarnecki's Ruby API (included in the plugin) for Akismet
|
5
|
+
## (http://akismet.com/personal/). When loaded comments that get submitted
|
6
|
+
## are fed to Akismet on-line and rejected if they are considered to be
|
7
|
+
## spam comments.
|
8
|
+
##
|
9
|
+
## Note that this plugin needs a network connection to verify the comments
|
10
|
+
## and it needs an Akismet API key to function. For personal use, Akismet
|
11
|
+
## API keys are free and will be sent to you on signing up at WordPress.
|
12
|
+
## See also: http://wordpress.com/signup/.
|
13
|
+
##
|
14
|
+
## USAGE:
|
15
|
+
##
|
16
|
+
## 1) In hobix.yaml (e.g. by running 'hobix edit <blogname>'), simply
|
17
|
+
## add 'hobix/plugin/akismet' to the 'required' block.
|
18
|
+
##
|
19
|
+
## required:
|
20
|
+
## [...]
|
21
|
+
## - hobix/plugin/akismet
|
22
|
+
##
|
23
|
+
## 2) Specify the API key you received/already had as parameter for the
|
24
|
+
## plugin.
|
25
|
+
##
|
26
|
+
## required:
|
27
|
+
## [...]
|
28
|
+
## - hobix/plugin/akismet:
|
29
|
+
## api-key: 123456789abc
|
30
|
+
##
|
31
|
+
## And that's it!
|
32
|
+
##
|
33
|
+
## NOTES:
|
34
|
+
##
|
35
|
+
## 1) This plugin is not useful when the Hobix comments support is not loaded,
|
36
|
+
## i.e. 'hobix/comments' is not required.
|
37
|
+
|
38
|
+
module Hobix
|
39
|
+
|
40
|
+
class AkismetKey < BasePlugin
|
41
|
+
|
42
|
+
def initialize(weblog, params = {})
|
43
|
+
raise %{The Akismet plugin is not configured, the API key is missing. See hobix/plugin/akismet.rb for details} unless params.member?("api-key")
|
44
|
+
@@key = params["api-key"]
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.key; @@key; end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
# Akismet
|
54
|
+
#
|
55
|
+
# Author:: David Czarnecki
|
56
|
+
# Copyright:: Copyright (c) 2005 - David Czarnecki
|
57
|
+
# License:: BSD
|
58
|
+
# Modified by Dieter Komendera, Sparkling Studios:
|
59
|
+
# append blog= to data string (Akismet said it is required)
|
60
|
+
# changed require 'net/HTTP' to require 'net/http' (to work for me unter GNU/Linux)
|
61
|
+
|
62
|
+
class Akismet
|
63
|
+
|
64
|
+
require 'net/http'
|
65
|
+
require 'uri'
|
66
|
+
|
67
|
+
STANDARD_HEADERS = {
|
68
|
+
'User-Agent' => 'Akismet Ruby API/1.0',
|
69
|
+
'Content-Type' => 'application/x-www-form-urlencoded'
|
70
|
+
}
|
71
|
+
|
72
|
+
# Instance variables
|
73
|
+
@apiKey
|
74
|
+
@blog
|
75
|
+
@verifiedKey
|
76
|
+
@proxyPort = nil
|
77
|
+
@proxyHost = nil
|
78
|
+
|
79
|
+
# Create a new instance of the Akismet class
|
80
|
+
#
|
81
|
+
# apiKey
|
82
|
+
# Your Akismet API key
|
83
|
+
# blog
|
84
|
+
# The blog associated with your api key
|
85
|
+
|
86
|
+
def initialize(blog, apiKey)
|
87
|
+
@apiKey = apiKey
|
88
|
+
@blog = blog
|
89
|
+
@verifiedKey = false
|
90
|
+
end
|
91
|
+
|
92
|
+
# Set proxy information
|
93
|
+
#
|
94
|
+
# proxyHost
|
95
|
+
# Hostname for the proxy to use
|
96
|
+
# proxyPort
|
97
|
+
# Port for the proxy
|
98
|
+
def setProxy(proxyHost, proxyPort)
|
99
|
+
@proxyPort = proxyPort
|
100
|
+
@proxyHost = proxyHost
|
101
|
+
end
|
102
|
+
|
103
|
+
# Call to check and verify your API key. You may then call the #hasVerifiedKey method to see if your key has been validated.
|
104
|
+
def verifyAPIKey()
|
105
|
+
http = Net::HTTP.new('rest.akismet.com', 80, @proxyHost, @proxyPort)
|
106
|
+
path = '/1.1/verify-key'
|
107
|
+
|
108
|
+
data="key=#{@apiKey}&blog=#{@blog}"
|
109
|
+
|
110
|
+
resp, data = http.post(path, data, STANDARD_HEADERS)
|
111
|
+
@verifiedKey = (data == "valid")
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns <tt>true</tt> if the API key has been verified, <tt>false</tt> otherwise
|
115
|
+
def hasVerifiedKey()
|
116
|
+
return @verifiedKey
|
117
|
+
end
|
118
|
+
|
119
|
+
# Internal call to Akismet. Prepares the data for posting to the Akismet service.
|
120
|
+
#
|
121
|
+
# akismet_function
|
122
|
+
# The Akismet function that should be called
|
123
|
+
# user_ip (required)
|
124
|
+
# IP address of the comment submitter.
|
125
|
+
# user_agent (required)
|
126
|
+
# User agent information.
|
127
|
+
# referrer (note spelling)
|
128
|
+
# The content of the HTTP_REFERER header should be sent here.
|
129
|
+
# permalink
|
130
|
+
# The permanent location of the entry the comment was submitted to.
|
131
|
+
# comment_type
|
132
|
+
# May be blank, comment, trackback, pingback, or a made up value like "registration".
|
133
|
+
# comment_author
|
134
|
+
# Submitted name with the comment
|
135
|
+
# comment_author_email
|
136
|
+
# Submitted email address
|
137
|
+
# comment_author_url
|
138
|
+
# Commenter URL.
|
139
|
+
# comment_content
|
140
|
+
# The content that was submitted.
|
141
|
+
# Other server enviroment variables
|
142
|
+
# In PHP there is an array of enviroment variables called $_SERVER which contains information about the web server itself as well as a key/value for every HTTP header sent with the request. This data is highly useful to Akismet as how the submited content interacts with the server can be very telling, so please include as much information as possible.
|
143
|
+
def callAkismet(akismet_function, user_ip, user_agent, referrer, permalink, comment_type, comment_author, comment_author_email, comment_author_url, comment_content, other)
|
144
|
+
http = Net::HTTP.new("#{@apiKey}.rest.akismet.com", 80, @proxyHost, @proxyPort)
|
145
|
+
path = "/1.1/#{akismet_function}"
|
146
|
+
|
147
|
+
data = "blog=#{@blog}&user_ip=#{user_ip}&user_agent=#{user_agent}&referrer=#{referrer}&permalink=#{permalink}&comment_type=#{comment_type}&comment_author=#{comment_author}&comment_author_email=#{comment_author_email}&comment_author_url=#{comment_author_url}&comment_content=#{comment_content}"
|
148
|
+
if (other != nil)
|
149
|
+
other.each_pair {|key, value| data.concat("&#{key}=#{value}")}
|
150
|
+
end
|
151
|
+
|
152
|
+
resp, data = http.post(path, data, STANDARD_HEADERS)
|
153
|
+
|
154
|
+
return (data != "false")
|
155
|
+
end
|
156
|
+
|
157
|
+
protected :callAkismet
|
158
|
+
|
159
|
+
# This is basically the core of everything. This call takes a number of arguments and characteristics about the submitted content and then returns a thumbs up or thumbs down. Almost everything is optional, but performance can drop dramatically if you exclude certain elements.
|
160
|
+
#
|
161
|
+
# user_ip (required)
|
162
|
+
# IP address of the comment submitter.
|
163
|
+
# user_agent (required)
|
164
|
+
# User agent information.
|
165
|
+
# referrer (note spelling)
|
166
|
+
# The content of the HTTP_REFERER header should be sent here.
|
167
|
+
# permalink
|
168
|
+
# The permanent location of the entry the comment was submitted to.
|
169
|
+
# comment_type
|
170
|
+
# May be blank, comment, trackback, pingback, or a made up value like "registration".
|
171
|
+
# comment_author
|
172
|
+
# Submitted name with the comment
|
173
|
+
# comment_author_email
|
174
|
+
# Submitted email address
|
175
|
+
# comment_author_url
|
176
|
+
# Commenter URL.
|
177
|
+
# comment_content
|
178
|
+
# The content that was submitted.
|
179
|
+
# Other server enviroment variables
|
180
|
+
# In PHP there is an array of enviroment variables called $_SERVER which contains information about the web server itself as well as a key/value for every HTTP header sent with the request. This data is highly useful to Akismet as how the submited content interacts with the server can be very telling, so please include as much information as possible.
|
181
|
+
def commentCheck(user_ip, user_agent, referrer, permalink, comment_type, comment_author, comment_author_email, comment_author_url, comment_content, other)
|
182
|
+
return callAkismet('comment-check', user_ip, user_agent, referrer, permalink, comment_type, comment_author, comment_author_email, comment_author_url, comment_content, other)
|
183
|
+
end
|
184
|
+
|
185
|
+
# This call is for submitting comments that weren't marked as spam but should have been. It takes identical arguments as comment check.
|
186
|
+
# The call parameters are the same as for the #commentCheck method.
|
187
|
+
def submitSpam(user_ip, user_agent, referrer, permalink, comment_type, comment_author, comment_author_email, comment_author_url, comment_content, other)
|
188
|
+
callAkismet('submit-spam', user_ip, user_agent, referrer, permalink, comment_type, comment_author, comment_author_email, comment_author_url, comment_content, other)
|
189
|
+
end
|
190
|
+
|
191
|
+
# This call is intended for the marking of false positives, things that were incorrectly marked as spam. It takes identical arguments as comment check and submit spam.
|
192
|
+
# The call parameters are the same as for the #commentCheck method.
|
193
|
+
def submitHam(user_ip, user_agent, referrer, permalink, comment_type, comment_author, comment_author_email, comment_author_url, comment_content, other)
|
194
|
+
callAkismet('submit-ham', user_ip, user_agent, referrer, permalink, comment_type, comment_author, comment_author_email, comment_author_url, comment_content, other)
|
195
|
+
end
|
196
|
+
end
|
@@ -88,16 +88,11 @@ class Out::Quick
|
|
88
88
|
def sidebar_erb
|
89
89
|
sidebar_calendar_ssi
|
90
90
|
end
|
91
|
-
|
92
|
-
## overwrite the default day header so that we can jump to the
|
93
|
-
## corresponding day in the main body of the monthly/yearly index
|
94
|
-
## files
|
95
|
-
def day_header_erb; %{ <h2 class="dayHeader"><a name="<%= day.strftime( "%Y%m%d" ) %>"><%= day.strftime( "%A, %B %d, %Y" ) %></a></h2> }; end
|
96
91
|
end
|
97
92
|
|
98
93
|
class Weblog
|
99
94
|
## generate all the sidebar calendar files
|
100
|
-
def skel_sidebar(path_storage)
|
95
|
+
def skel_sidebar( path_storage, section_path )
|
101
96
|
months = path_storage.get_months(storage.find)
|
102
97
|
|
103
98
|
months.extend Hobix::Enumerable
|
@@ -105,7 +100,8 @@ class Weblog
|
|
105
100
|
month_start, month_end, month_id = cur
|
106
101
|
|
107
102
|
entries = path_storage.within(month_start, month_end)
|
108
|
-
|
103
|
+
entry_path = SidebarCalendarPlugin.dir_to(month_start, false)
|
104
|
+
page = Page.new( entry_path, section_path )
|
109
105
|
page.timestamp = month_start
|
110
106
|
page.updated = Time.now #path_storage.last_modified(entries)
|
111
107
|
page.prev = prev[0].strftime("/%Y/%m/") if prev
|
@@ -167,11 +163,11 @@ class Out::Quick
|
|
167
163
|
title = d.strftime("%A, %B %e: " + (days[d] == 1 ? "one entry" : "#{days[d]} entries"))
|
168
164
|
link = case index
|
169
165
|
when :yearly:
|
170
|
-
d.strftime("/%Y
|
166
|
+
d.strftime("/%Y/#day%Y%m%d")
|
171
167
|
when :monthly:
|
172
|
-
d.strftime("/%Y/%m
|
168
|
+
d.strftime("/%Y/%m/#day%Y%m%d")
|
173
169
|
else
|
174
|
-
d.strftime("/%Y/%m/%d.html
|
170
|
+
d.strftime("/%Y/%m/%d.html#day%Y%m%d")
|
175
171
|
end
|
176
172
|
%>
|
177
173
|
<td class="sidebarCalendarLinkDay"><a title="<%= title %>" href="<%= weblog.expand_path link %>"><%= d.strftime("%e") %></a></td>
|
@@ -180,10 +176,6 @@ class Out::Quick
|
|
180
176
|
<% end %>
|
181
177
|
<% end %>
|
182
178
|
|
183
|
-
<% (7 - offset).times do %>
|
184
|
-
<td class="sidebarCalendarFiller"> </td>
|
185
|
-
<% end %>
|
186
|
-
|
187
179
|
</tr>
|
188
180
|
}
|
189
181
|
end
|
@@ -60,9 +60,11 @@ class Hobix::Out::Quick
|
|
60
60
|
<div class="sidebarBox">
|
61
61
|
<h2 class="sidebarTitle">Recent Comments</h2>
|
62
62
|
<ul>
|
63
|
-
<% recent_comments( weblog, weblog.storage.find, RecentCommentsPlugin.num )
|
64
|
-
|
63
|
+
<% reccomm = recent_comments( weblog, weblog.storage.find, RecentCommentsPlugin.num ) %>
|
64
|
+
<% reccomm.each do |link, title, auth, created| %>
|
65
|
+
<li><a href="<%= link %>"><%= title %></a> by <%= auth %> on <nobr><%= created.strftime "%d %b at %H:%M" %></nobr></li>
|
65
66
|
<% end %>
|
67
|
+
<%= "<li>No comments (yet)!</li>" if reccomm.empty? %>
|
66
68
|
</ul>
|
67
69
|
</div>
|
68
70
|
}
|
data/lib/hobix/plugin/tags.rb
CHANGED
@@ -38,7 +38,7 @@ class Hobix::Out::Quick
|
|
38
38
|
<ul>
|
39
39
|
<% tags_list(weblog.storage.find).sort.each do |name, count| %>
|
40
40
|
<li>
|
41
|
-
<a href="<%= weblog.
|
41
|
+
<a href="<%= weblog.expand_path "tags/#{ name }/" %>"><%= name
|
42
42
|
%></a>: <%=count%>
|
43
43
|
</li>
|
44
44
|
<% end %>
|
@@ -51,7 +51,7 @@ class FileSys < Hobix::BaseStorage
|
|
51
51
|
# Start the storage plugin for the +weblog+ passed in.
|
52
52
|
def initialize( weblog )
|
53
53
|
super( weblog )
|
54
|
-
@
|
54
|
+
@updated = {}
|
55
55
|
@basepath = weblog.entry_path
|
56
56
|
@default_author = weblog.authors.keys.first
|
57
57
|
@weblog = weblog
|
@@ -75,10 +75,10 @@ class FileSys < Hobix::BaseStorage
|
|
75
75
|
File.join( @basepath, id.split( '/' ) ) + "." + ext
|
76
76
|
end
|
77
77
|
|
78
|
-
# Brings an entry's
|
78
|
+
# Brings an entry's updated time current.
|
79
79
|
def touch_entry( id )
|
80
80
|
check_id( id )
|
81
|
-
@
|
81
|
+
@updated[id] = Time.now
|
82
82
|
FileUtils.touch entry_path( id )
|
83
83
|
end
|
84
84
|
|
@@ -90,24 +90,22 @@ class FileSys < Hobix::BaseStorage
|
|
90
90
|
e.created ||= (@index.has_key?( id ) ? @index[id].created : now)
|
91
91
|
path = entry_path( id )
|
92
92
|
|
93
|
-
|
94
|
-
File.open( path, 'w' ) { |f| YAML::dump( e, f ) }
|
95
|
-
rescue Errno::ENOENT
|
96
|
-
raise unless create_category and File.exists? @basepath
|
93
|
+
unless create_category and File.exists? @basepath
|
97
94
|
FileUtils.makedirs File.dirname( path )
|
98
|
-
retry
|
99
95
|
end
|
96
|
+
|
97
|
+
File.open( path, 'w' ) { |f| YAML::dump( e, f ) }
|
100
98
|
|
101
99
|
@entry_cache ||= {}
|
102
100
|
e.id = id
|
103
101
|
e.link = e.class.url_link e, @link, @weblog.central_ext
|
104
|
-
e.modified = now
|
102
|
+
e.updated = e.modified = now
|
105
103
|
@entry_cache[id] = e
|
106
104
|
|
107
105
|
@index[id] = @weblog.index_class.new( e ) do |i|
|
108
|
-
i.
|
106
|
+
i.updated = e.updated
|
109
107
|
end
|
110
|
-
@
|
108
|
+
@updated[id] = e.updated
|
111
109
|
# catalog_search_entry( e )
|
112
110
|
sort_index( true )
|
113
111
|
e
|
@@ -124,9 +122,10 @@ class FileSys < Hobix::BaseStorage
|
|
124
122
|
e = Hobix::Entry::load( entry_file )
|
125
123
|
e.id = id
|
126
124
|
e.link = e.class.url_link e, @link, @weblog.central_ext
|
127
|
-
e.
|
125
|
+
e.updated = updated( id )
|
128
126
|
unless e.created
|
129
127
|
e.created = @index[id].created
|
128
|
+
e.modified = @index[id].modified
|
130
129
|
File.open( entry_file, 'w' ) { |f| YAML::dump( e, f ) }
|
131
130
|
end
|
132
131
|
@entry_cache[id] = e
|
@@ -175,28 +174,30 @@ class FileSys < Hobix::BaseStorage
|
|
175
174
|
entry_paths = File.split( $` )
|
176
175
|
entry_paths.shift if entry_paths.first == '.'
|
177
176
|
entry_id = entry_paths.join( '/' )
|
178
|
-
@
|
177
|
+
@updated[entry_id] = File.mtime( path )
|
179
178
|
|
180
179
|
index_entry = nil
|
181
180
|
if ( index.has_key? entry_id ) and !( index[entry_id].is_a? ::Time ) # pre-0.4 index format
|
182
181
|
index_entry = index[entry_id]
|
183
182
|
end
|
184
183
|
## we will (re)load the entry if:
|
185
|
-
if not index_entry.respond_to?( :
|
186
|
-
( index_entry.
|
187
|
-
index_fields.detect { |f| index_entry.send( f ).nil? } # index fields have been added
|
184
|
+
if not index_entry.respond_to?( :updated ) or # it's new
|
185
|
+
( index_entry.updated != @updated[entry_id] ) # it's changed
|
186
|
+
# or index_fields.detect { |f| index_entry.send( f ).nil? } # index fields have been added
|
188
187
|
# or search_needs_update? index_entry # entry is old or not available in search db
|
189
188
|
|
189
|
+
puts "++ Reloaded #{ entry_id }"
|
190
190
|
efile = entry_path( entry_id )
|
191
191
|
e = Hobix::Entry::load( efile )
|
192
192
|
e.id = entry_id
|
193
193
|
index_entry = @weblog.index_class.new( e, index_fields ) do |i|
|
194
|
-
i.
|
194
|
+
i.updated = @updated[entry_id]
|
195
195
|
end
|
196
196
|
# catalog_search_entry( e )
|
197
197
|
modified = true
|
198
198
|
end
|
199
|
-
|
199
|
+
index_entry.id = entry_id
|
200
|
+
@index[entry_id] = index_entry
|
200
201
|
end
|
201
202
|
end
|
202
203
|
sort_index( modified )
|
@@ -210,7 +211,7 @@ class FileSys < Hobix::BaseStorage
|
|
210
211
|
@index.sort! { |x,y| y[1].created <=> x[1].created }
|
211
212
|
if modified
|
212
213
|
File.open( index_path, 'w' ) do |f|
|
213
|
-
|
214
|
+
YAML::dump( @index, f )
|
214
215
|
end
|
215
216
|
# @search_index.dump
|
216
217
|
end
|
@@ -225,7 +226,7 @@ class FileSys < Hobix::BaseStorage
|
|
225
226
|
path_storage.instance_eval do
|
226
227
|
@index = @index.dup.delete_if do |id, entry|
|
227
228
|
if id.index( p ) != 0
|
228
|
-
@
|
229
|
+
@updated.delete( p )
|
229
230
|
true
|
230
231
|
end
|
231
232
|
end
|
@@ -259,7 +260,7 @@ class FileSys < Hobix::BaseStorage
|
|
259
260
|
_index = @index
|
260
261
|
if _index.empty?
|
261
262
|
e = default_entry( @default_author )
|
262
|
-
@
|
263
|
+
@updated[e.id] = e.updated
|
263
264
|
_index = {e.id => @weblog.index_class.new(e)}
|
264
265
|
end
|
265
266
|
# if search[:search]
|
@@ -300,11 +301,19 @@ class FileSys < Hobix::BaseStorage
|
|
300
301
|
entries
|
301
302
|
end
|
302
303
|
|
304
|
+
# Returns a Time object for the latest updated time for a group of
|
305
|
+
# +entries+ (pass in an Array of IndexEntry objects).
|
306
|
+
def last_updated( entries )
|
307
|
+
entries.collect do |entry|
|
308
|
+
updated( entry.id )
|
309
|
+
end.max
|
310
|
+
end
|
311
|
+
|
303
312
|
# Returns a Time object for the latest modified time for a group of
|
304
313
|
# +entries+ (pass in an Array of IndexEntry objects).
|
305
314
|
def last_modified( entries )
|
306
315
|
entries.collect do |entry|
|
307
|
-
|
316
|
+
entry.modified
|
308
317
|
end.max
|
309
318
|
end
|
310
319
|
|
@@ -316,10 +325,11 @@ class FileSys < Hobix::BaseStorage
|
|
316
325
|
end.max
|
317
326
|
end
|
318
327
|
|
319
|
-
# Returns a Time object representing the +
|
320
|
-
# entry identified by +entry_id+.
|
321
|
-
|
322
|
-
|
328
|
+
# Returns a Time object representing the +updated+ time for the
|
329
|
+
# entry identified by +entry_id+. Takes into account attachments
|
330
|
+
# which have been updated.
|
331
|
+
def updated( entry_id )
|
332
|
+
find_attached( entry_id ).inject( @updated[entry_id] ) do |max, ext|
|
323
333
|
mtime = File.mtime( entry_path( entry_id, ext ) )
|
324
334
|
mtime > max ? mtime : max
|
325
335
|
end
|
@@ -343,7 +353,7 @@ class FileSys < Hobix::BaseStorage
|
|
343
353
|
next_month %= 12
|
344
354
|
end
|
345
355
|
month_end = Time.mktime( next_year, next_month, 1 ) - 1
|
346
|
-
months << [ start, month_end, start.strftime( "/%Y/%m/" ) ]
|
356
|
+
months << [ start, month_end, start.strftime( "/%Y/%m/" ) ] unless find( :after => start, :before => month_end).empty?
|
347
357
|
start = month_end + 1
|
348
358
|
end
|
349
359
|
months
|
@@ -378,7 +388,7 @@ class FileSys < Hobix::BaseStorage
|
|
378
388
|
def save_attached( id, ext, e )
|
379
389
|
check_id( id )
|
380
390
|
File.open( entry_path( id, ext ), 'w' ) do |f|
|
381
|
-
|
391
|
+
YAML::dump( e, f )
|
382
392
|
end
|
383
393
|
|
384
394
|
@attach_cache ||= {}
|
@@ -389,9 +399,9 @@ class FileSys < Hobix::BaseStorage
|
|
389
399
|
# then saves the modified attachment. If an attachment of the given type
|
390
400
|
# does not exist, it will be created.
|
391
401
|
def append_to_attachment( entry_id, attachment_type, *items )
|
392
|
-
|
393
|
-
|
394
|
-
|
402
|
+
attachment = load_attached( entry_id, attachment_type ) rescue []
|
403
|
+
attachment += items
|
404
|
+
save_attached( entry_id, attachment_type, attachment )
|
395
405
|
end
|
396
406
|
end
|
397
407
|
end
|
data/lib/hobix/trackbacks.rb
CHANGED
@@ -36,7 +36,6 @@ class Quick
|
|
36
36
|
}
|
37
37
|
|
38
38
|
def entry_trackback_erb; %{
|
39
|
-
<a name="trackbacks"></a>
|
40
39
|
<div id="trackbacks">
|
41
40
|
<% entry_id = entry.id %>
|
42
41
|
<% trackbacks = weblog.storage.load_attached( entry_id, "trackbacks") rescue [] %>
|
@@ -44,7 +43,7 @@ class Quick
|
|
44
43
|
<div class="entry">
|
45
44
|
<div class="entryAttrib">
|
46
45
|
<div class="entryAuthor"><h3><%= trackback.blog_name %></h3></div>
|
47
|
-
<div class="entryTime">tracked back on <%= trackback.created.strftime("<nobr>%d %b %Y</nobr> at <nobr>%
|
46
|
+
<div class="entryTime">tracked back on <%= trackback.created.strftime("<nobr>%d %b %Y</nobr> at <nobr>%H:%M</nobr>" ) %></div>
|
48
47
|
</div>
|
49
48
|
<div class="entryContentOuter"><div class="entryContent">
|
50
49
|
<h3><a href="<%= trackback.url %>"><%= trackback.title %></a></h3>
|