hobix 0.4 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. data/COPYING +18 -0
  2. data/README +18 -0
  3. data/Rakefile +96 -0
  4. data/bin/hobix +7 -3
  5. data/contrib/blosxom-to-hobix.rb +253 -0
  6. data/contrib/txp-to-hobix.rb +56 -0
  7. data/contrib/webrick-all-mine.rb +20 -0
  8. data/doc/CHANGELOG +285 -0
  9. data/doc/rdoc/classes/Hobix/API.html +382 -0
  10. data/doc/rdoc/classes/Hobix/Article.html +111 -0
  11. data/doc/rdoc/classes/Hobix/BaseContent.html +692 -0
  12. data/doc/rdoc/classes/Hobix/BaseEntry.html +218 -0
  13. data/doc/rdoc/classes/Hobix/BaseFacet.html +205 -0
  14. data/doc/rdoc/classes/Hobix/BaseOutput.html +122 -0
  15. data/doc/rdoc/classes/Hobix/BasePlugin.html +201 -0
  16. data/doc/rdoc/classes/Hobix/BaseProperties/ClassMethods.html +243 -0
  17. data/doc/rdoc/classes/Hobix/BaseProperties.html +218 -0
  18. data/doc/rdoc/classes/Hobix/BasePublish.html +157 -0
  19. data/doc/rdoc/classes/Hobix/BaseStorage.html +417 -0
  20. data/doc/rdoc/classes/Hobix/BixWik/Entry.html +196 -0
  21. data/doc/rdoc/classes/Hobix/BixWik/IndexEntry.html +170 -0
  22. data/doc/rdoc/classes/Hobix/BixWik/WikiRedCloth.html +111 -0
  23. data/doc/rdoc/classes/Hobix/BixWik.html +418 -0
  24. data/doc/rdoc/classes/Hobix/BixWikPlugin.html +158 -0
  25. data/doc/rdoc/classes/Hobix/CommandLine.html +1970 -0
  26. data/doc/rdoc/classes/Hobix/Comment.html +113 -0
  27. data/doc/rdoc/classes/Hobix/Config.html +212 -0
  28. data/doc/rdoc/classes/Hobix/DataMarsh.html +667 -0
  29. data/doc/rdoc/classes/Hobix/Entry.html +178 -0
  30. data/doc/rdoc/classes/Hobix/EntryEnum.html +162 -0
  31. data/doc/rdoc/classes/Hobix/Enumerable.html +170 -0
  32. data/doc/rdoc/classes/Hobix/Facets/WikiEdit.html +180 -0
  33. data/doc/rdoc/classes/Hobix/Facets.html +111 -0
  34. data/doc/rdoc/classes/Hobix/LinkList.html +182 -0
  35. data/doc/rdoc/classes/Hobix/Out/Quick.html +412 -0
  36. data/doc/rdoc/classes/Hobix/Out.html +119 -0
  37. data/doc/rdoc/classes/Hobix/Page.html +381 -0
  38. data/doc/rdoc/classes/Hobix/Trackback.html +113 -0
  39. data/doc/rdoc/classes/Hobix/UriStr.html +198 -0
  40. data/doc/rdoc/classes/Hobix/WebApp/QueryString.html +207 -0
  41. data/doc/rdoc/classes/Hobix/WebApp/QueryValidationFailure.html +111 -0
  42. data/doc/rdoc/classes/Hobix/WebApp.html +1383 -0
  43. data/doc/rdoc/classes/Hobix/Weblog/AuthorNotFound.html +111 -0
  44. data/doc/rdoc/classes/Hobix/Weblog.html +2082 -0
  45. data/doc/rdoc/classes/Hobix.html +399 -0
  46. data/doc/rdoc/classes/Kernel.html +139 -0
  47. data/doc/rdoc/classes/Regexp.html +154 -0
  48. data/doc/rdoc/classes/YAML/Omap.html +144 -0
  49. data/doc/rdoc/classes/YAML.html +111 -0
  50. data/doc/rdoc/created.rid +1 -0
  51. data/doc/rdoc/files/COPYING.html +129 -0
  52. data/doc/rdoc/files/README.html +131 -0
  53. data/doc/rdoc/files/doc/CHANGELOG.html +101 -0
  54. data/doc/rdoc/files/lib/hobix/api_rb.html +119 -0
  55. data/doc/rdoc/files/lib/hobix/article_rb.html +126 -0
  56. data/doc/rdoc/files/lib/hobix/base_rb.html +128 -0
  57. data/doc/rdoc/files/lib/hobix/bixwik_rb.html +126 -0
  58. data/doc/rdoc/files/lib/hobix/commandline_rb.html +140 -0
  59. data/doc/rdoc/files/lib/hobix/comments_rb.html +126 -0
  60. data/doc/rdoc/files/lib/hobix/config_rb.html +125 -0
  61. data/doc/rdoc/files/lib/hobix/datamarsh_rb.html +108 -0
  62. data/doc/rdoc/files/lib/hobix/entry_rb.html +118 -0
  63. data/doc/rdoc/files/lib/hobix/linklist_rb.html +127 -0
  64. data/doc/rdoc/files/lib/hobix/publisher_rb.html +126 -0
  65. data/doc/rdoc/files/lib/hobix/trackbacks_rb.html +128 -0
  66. data/doc/rdoc/files/lib/hobix/webapp_rb.html +127 -0
  67. data/doc/rdoc/files/lib/hobix/weblog_rb.html +135 -0
  68. data/doc/rdoc/files/lib/hobix_rb.html +127 -0
  69. data/doc/rdoc/fr_class_index.html +67 -0
  70. data/doc/rdoc/fr_file_index.html +44 -0
  71. data/doc/rdoc/fr_method_index.html +307 -0
  72. data/doc/rdoc/index.html +24 -0
  73. data/doc/rdoc/rdoc-style.css +208 -0
  74. data/git_hobix_update.php +13 -0
  75. data/lib/hobix/base.rb +6 -3
  76. data/lib/hobix/bixwik.rb +12 -12
  77. data/lib/hobix/commandline.rb +18 -2
  78. data/lib/hobix/comments.rb +4 -5
  79. data/lib/hobix/entry.rb +2 -1
  80. data/lib/hobix/facets/comments.rb +31 -6
  81. data/lib/hobix/linklist.rb +6 -1
  82. data/lib/hobix/out/atom.rb +29 -20
  83. data/lib/hobix/out/quick.rb +8 -6
  84. data/lib/hobix/out/rss.rb +16 -3
  85. data/lib/hobix/plugin/akismet.rb +196 -0
  86. data/lib/hobix/plugin/calendar.rb +6 -14
  87. data/lib/hobix/plugin/recent_comments.rb +4 -2
  88. data/lib/hobix/plugin/tags.rb +1 -1
  89. data/lib/hobix/storage/filesys.rb +41 -31
  90. data/lib/hobix/trackbacks.rb +1 -2
  91. data/lib/hobix/weblog.rb +73 -40
  92. data/lib/hobix.rb +9 -2
  93. data/share/default-blog/hobix.yaml +16 -0
  94. data/share/default-blog/htdocs/site.css +174 -0
  95. data/share/default-blog/skel/entry.html.quick +0 -0
  96. data/share/default-blog/skel/index.atom.atom +0 -0
  97. data/share/default-blog/skel/index.html.quick-summary +0 -0
  98. data/share/default-blog/skel/index.xml.rss +0 -0
  99. data/share/default-blog/skel/index.yaml.okaynews +0 -0
  100. data/share/default-blog/skel/monthly.html.quick-archive +0 -0
  101. data/share/default-blog/skel/section.html.quick-archive +0 -0
  102. data/share/default-blog/skel/yearly.html.quick-archive +0 -0
  103. data/share/default-blog-modes.yaml +7 -0
  104. data/share/default-blog.apache-cgi.patch +8 -0
  105. data/share/default-blog.apache-ssi.patch +38 -0
  106. data/share/default-blog.apache2-ssi.patch +3 -0
  107. data/share/default-blog.cgi.patch +8 -0
  108. data/share/default-blog.comments.patch +5 -0
  109. data/share/default-blog.prototype.patch +766 -0
  110. data/share/default-blog.publisher.patch +5 -0
  111. data/share/default-blog.wiki.patch +29 -0
  112. data/share/publisher/css/control.css +90 -0
  113. data/share/publisher/css/form.css +238 -0
  114. data/share/publisher/css/form.import.css +72 -0
  115. data/share/publisher/css/main-menu.css +134 -0
  116. data/share/publisher/i/hobix-emblazen-1.png +0 -0
  117. data/share/publisher/i/hobix-emblazen-2.png +0 -0
  118. data/share/publisher/i/hobix-emblazen-3.png +0 -0
  119. data/share/publisher/i/hobix-emblazen-4.png +0 -0
  120. data/share/publisher/i/hobix-emblazen-5.png +0 -0
  121. data/share/publisher/i/hobix-emblazen-6.png +0 -0
  122. data/share/publisher/i/hobix-emblazen-7.png +0 -0
  123. data/share/publisher/index.erb +66 -0
  124. data/share/publisher/js/controls.js +261 -0
  125. data/share/publisher/js/dragdrop.js +476 -0
  126. data/share/publisher/js/effects.js +570 -0
  127. data/share/publisher/js/prototype.js +1011 -0
  128. metadata +196 -53
  129. 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.text =
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. &rarr;
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
- page = Page.new SidebarCalendarPlugin.dir_to(month_start, false)
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/#%Y%m%d")
166
+ d.strftime("/%Y/#day%Y%m%d")
171
167
  when :monthly:
172
- d.strftime("/%Y/%m/#%Y%m%d")
168
+ d.strftime("/%Y/%m/#day%Y%m%d")
173
169
  else
174
- d.strftime("/%Y/%m/%d.html#%Y%m%d")
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"> &nbsp; </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 ).each do |link, title, auth, created| %>
64
- <li><a href="<%= link %>"><%= title %></a> by <%= auth %> on <nobr><%= created.strftime "%m/%d at %I:%M %P" %></nobr></li>
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
  }
@@ -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.link %>/tags/<%=name%>/index.html"><%= name
41
+ <a href="<%= weblog.expand_path "tags/#{ name }/" %>"><%= name
42
42
  %></a>:&nbsp;<%=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
- @modified = {}
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 modified time current.
78
+ # Brings an entry's updated time current.
79
79
  def touch_entry( id )
80
80
  check_id( id )
81
- @modified[id] = Time.now
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
- begin
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.modified = e.modified
106
+ i.updated = e.updated
109
107
  end
110
- @modified[id] = e.modified
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.modified = modified( id )
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
- @modified[entry_id] = File.mtime( path )
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?( :modified ) or # it's new
186
- ( index_entry.modified != @modified[entry_id] ) or # it's changed
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.modified = @modified[entry_id]
194
+ i.updated = @updated[entry_id]
195
195
  end
196
196
  # catalog_search_entry( e )
197
197
  modified = true
198
198
  end
199
- @index[index_entry.id] = index_entry
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
- YAML::dump( @index, f )
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
- @modified.delete( p )
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
- @modified[e.id] = e.modified
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
- modified( entry.id )
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 +modified+ time for the
320
- # entry identified by +entry_id+.
321
- def modified( entry_id )
322
- find_attached( entry_id ).inject( @modified[entry_id] ) do |max, ext|
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
- YAML::dump( e, f )
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
- attachment = load_attached( entry_id, attachment_type ) rescue []
393
- attachment += items
394
- save_attached( entry_id, attachment_type, attachment )
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
@@ -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>%I:%M %p</nobr>" ) %></div>
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>