blogical 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,31 @@
1
+ module Blogical
2
+ module Atom
3
+ def self.included(app)
4
+
5
+ app.get '/blog/atom.xml' do
6
+
7
+ feed = ::Atom::Feed.new do |f|
8
+ f.title = self.class.feed_title
9
+ f.links << ::Atom::Link.new(:href => self.class.url)
10
+ f.updated = options.repository.latest.posted.to_s(:iso8601)
11
+ f.authors << ::Atom::Person.new(:name => self.class.full_name)
12
+ f.id = 'tag:'+self.class.domain+',2010:blogical/blog'
13
+
14
+ options.repository.recent(15).each do |post|
15
+ entry = ::Atom::Entry.new do |e|
16
+ e.title = post.title
17
+ e.links << ::Atom::Link.new(:href => post.url)
18
+ e.id = UUIDTools::UUID.sha1_create(UUIDTools::UUID_URL_NAMESPACE, post.url).to_uri.to_s
19
+ e.updated = post.posted.to_s(:iso8601)
20
+ e.content = ::Atom::Content::Html.new(markup(File.read(post.content)))
21
+ end
22
+
23
+ f.entries << entry
24
+ end
25
+ end
26
+
27
+ feed.to_xml
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ module Blogical
2
+ module Blog
3
+ def self.included(app)
4
+
5
+ # GET /blog
6
+ app.get %r{^/blog/?(\?.*)?$} do
7
+ @posts = options.repository.paginated(Integer(params['page']))
8
+ @pages = options.repository.total_pages
9
+ erb :blog
10
+ end
11
+
12
+ # GET /blog/2009/05/12/comma-intro
13
+ app.get '/blog/:year/:month/:day/:title' do |year, month, day, title|
14
+ @post = options.repository.find_by_permalink(title)
15
+ raise Sinatra::NotFound, 'No such post' unless @post
16
+ @title = @post.title
17
+ erb :article
18
+ end
19
+
20
+ # GET /assets/2009/05/12/1-filename.pdf
21
+ app.get '/assets/:year/:month/:day/:attachment' do |year, month, day, attachment|
22
+ @attachment = options.repository.find_by_attachment(attachment)
23
+ raise Sinatra::NotFound, 'No such attachment' unless @attachment
24
+ send_file @attachment.content, :disposition => 'attachment'
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,146 @@
1
+ require 'find'
2
+
3
+ module Blogical
4
+ module Content
5
+
6
+ def self.included(app)
7
+ app.configure do |app|
8
+ app.set :repository, Repository.new(app.content)
9
+ end
10
+ end
11
+
12
+ class Repository
13
+ attr_accessor :articles, :path
14
+
15
+ def initialize(path)
16
+ @path, @index, @articles, @attachments = path, [], {}, {}
17
+ scan
18
+ end
19
+
20
+ def find_by_permalink(link)
21
+ @articles[link]
22
+ end
23
+
24
+ def find_by_attachment(attachment)
25
+ @attachments[attachment]
26
+ end
27
+
28
+ def recent(count = 3)
29
+ count = @index.size if count > @index.size
30
+ @index[0..(count - 1)]
31
+ end
32
+
33
+ def latest
34
+ @index[0]
35
+ end
36
+
37
+ def total_pages
38
+ @index.total_pages
39
+ end
40
+
41
+ def paginated(page_number = 1)
42
+ @index.page(page_number)
43
+ end
44
+
45
+ private
46
+
47
+ def page_size
48
+ @index.page_size
49
+ end
50
+
51
+ def article(meta)
52
+ article = Article.new(meta)
53
+ @index << article
54
+ @articles[article.permalink] = article
55
+ article.attachments.each { |a| @attachments[a.name] = a } if article.attachments
56
+ puts "Registered article #{article.permalink} (posted #{article.posted})"
57
+ end
58
+
59
+ def scan
60
+ metafiles = []
61
+ Find.find(@path) do |path|
62
+ next unless FileTest.directory?(path)
63
+ meta = "#{path}/meta.rb"
64
+ next unless File.exists?(meta)
65
+ metafiles << meta
66
+ Find.prune
67
+ end
68
+ metafiles.sort.reverse.each do |meta|
69
+ article(meta)
70
+ end
71
+ end
72
+
73
+ end
74
+
75
+ class Article
76
+ attr_accessor :permalink, :posted, :attachments, :tags, :content, :title
77
+
78
+ def initialize(meta)
79
+ @path, @content = meta, File.join(File.expand_path(File.dirname(meta)), 'content.markdown')
80
+ instance_eval File.read(meta)
81
+ end
82
+
83
+ def article(title, &block)
84
+ @title = title
85
+ instance_eval &block
86
+ end
87
+
88
+ def permalink(link = nil)
89
+ return @permalink unless link
90
+ @permalink = link
91
+ end
92
+
93
+ def posted(date = nil)
94
+ if date
95
+ @posted = date
96
+ else
97
+ return Chronic.parse(@posted)
98
+ end
99
+ end
100
+
101
+ # REVISIT: most recent content file git commit author
102
+ def nickname
103
+ Blogical::Application.nickname
104
+ end
105
+
106
+ def email
107
+ Blogical::Application.email
108
+ end
109
+
110
+ def url
111
+ "/blog/#{@posted}/#{@permalink}"
112
+ end
113
+
114
+ def attachments(*attachments)
115
+ return @attachments if attachments.empty?
116
+ @attachments = attachments.collect { |attachment| Attachment.new(self, attachment) }
117
+ end
118
+
119
+ def tags(*tags)
120
+ return @tags if tags.empty?
121
+ @tags = tags.collect { |tag| Tag.new(self, tag) }
122
+ end
123
+
124
+ end
125
+
126
+ class Attachment
127
+ attr_accessor :article, :name, :content
128
+
129
+ def initialize(article, name)
130
+ @article, @name = article, name
131
+ @content = File.join(File.expand_path(File.dirname(article.content)), name)
132
+ end
133
+
134
+ end
135
+
136
+ class Tag
137
+ attr_accessor :article, :name
138
+
139
+ def initialize(article, name)
140
+ @article, @name = article, name
141
+ end
142
+
143
+ end
144
+
145
+ end
146
+ end
@@ -0,0 +1,30 @@
1
+ class Time
2
+
3
+ FORMATS = {
4
+ :iso8601 => '%Y-%m-%dT%H:%MZ',
5
+ :posted => '%d %B %Y'
6
+ }
7
+
8
+ def to_s(requested = :iso8601)
9
+ self.strftime(FORMATS[requested])
10
+ end
11
+
12
+ end
13
+
14
+ class Array
15
+
16
+ def total_pages
17
+ (self.size.to_f / page_size.to_f).ceil
18
+ end
19
+
20
+ def page(page_number = 0)
21
+ page_number = 1 if page_number < 1
22
+ base = (page_number - 1) * page_size
23
+ self[base..(base + page_size - 1)]
24
+ end
25
+
26
+ def page_size
27
+ 3
28
+ end
29
+
30
+ end
@@ -0,0 +1,38 @@
1
+ require 'rdiscount'
2
+
3
+ module Blogical
4
+ module Helpers
5
+
6
+ def self.included(app)
7
+ app.helpers do
8
+ include Rack::Utils
9
+ alias_method :h, :escape_html
10
+
11
+ def markup(string)
12
+ RDiscount::new(string, :smart).to_html
13
+ end
14
+
15
+ def tags(post)
16
+ return '' unless post
17
+ tag_names = post.tags.collect { |tag| tag.name }
18
+ ", #{tag_names.join(', ')}"
19
+ end
20
+
21
+ def url(path)
22
+ request.script_name + path
23
+ end
24
+
25
+ def body_id
26
+ b_id = request.path_info.split('/')[1] || 'home'
27
+ b_id.to_i == 0 ? b_id : 'blog' # numerical paths are considered blog posts
28
+ end
29
+
30
+ def current_page?(page_number)
31
+ Integer(params['page']) == page_number
32
+ end
33
+ end
34
+
35
+ super
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,3 @@
1
+ Welcome, to my new blog!
2
+
3
+ My name is ..., and I'm ...
@@ -0,0 +1,5 @@
1
+ article 'Welcome!' do
2
+ permalink 'welcome'
3
+ posted '2010/6/16'
4
+ tags :blogical
5
+ end
@@ -0,0 +1,330 @@
1
+ @charset "utf-8";
2
+ /* CSS Document */
3
+
4
+ body, html {
5
+ margin: 0;
6
+ padding: 0;
7
+ }
8
+ body {
9
+ font: 81% "Trebuchet MS", Helvetica, Arial, sans-serif;
10
+ color: #bcbcbc;
11
+ background: #090e11;
12
+ text-align: center;
13
+ }
14
+ a:link {
15
+ color: #CCF;
16
+ text-decoration: none;
17
+ }
18
+ a:visited {
19
+ color: #af2d33;
20
+ text-decoration: none;
21
+ }
22
+ a:active {
23
+ color: #ffb43d;
24
+ }
25
+ a:hover {
26
+ color: #FFFFFF;
27
+ text-decoration: underline;
28
+ }
29
+ #header {
30
+ height: 144px;
31
+ background: #bbbbbb url(/images/ui/banner.jpg) center top repeat-x;
32
+ border-bottom: 1px solid #9fadb3;
33
+ }
34
+ body#home #header {
35
+ height: 289px;
36
+ }
37
+ span#dotmesh {
38
+ display: block;
39
+ position: absolute;
40
+ top: 0;
41
+ left: 0;
42
+ width: 100%;
43
+ height: 144px;
44
+ margin: 0;
45
+ background: url(/images/ui/dot-mesh.png);
46
+ }
47
+ body#home span#dotmesh {
48
+ height: 289px;
49
+ }
50
+ h1, h2, h3, h4 {
51
+ font-family: Arial, Helvetica, sans-serif;
52
+ color: #fff;
53
+ font-weight: normal;
54
+ margin-top: 0;
55
+ padding-top: 1em;
56
+ }
57
+ h2 {
58
+ font-size: 2.0em;
59
+ background: url(/images/ui/content-divider.png) center top no-repeat;
60
+ margin: 1em 0 1em;
61
+ padding: 1em 0 0;
62
+ color: #FFF;
63
+ }
64
+ h3 {
65
+ font-size: 1.6em;
66
+ }
67
+ h1#logo {
68
+ position: absolute;
69
+ margin: 0;
70
+ padding: 0;
71
+ top: 22px;
72
+ left: 15px;
73
+ }
74
+ body#home h1#logo {
75
+ top: 45px;
76
+ left: 15px;
77
+ }
78
+ h1#logo a {
79
+ display: block;
80
+ width: 237px;
81
+ height: 0;
82
+ padding: 102px 0 0;
83
+ overflow: hidden;
84
+ background: url(/images/ui/ra-logo-mid.png) no-repeat;
85
+ }
86
+ body#home h1#logo a {
87
+ width: 473px;
88
+ padding: 201px 0 0;
89
+ background: url(/images/ui/ra-logo-large.png) no-repeat;
90
+ }
91
+ h1#logo img {
92
+ display: none;
93
+ }
94
+ p#tagline {
95
+ position: absolute;
96
+ top: 109px;
97
+ left: 159px;
98
+ width: 339px;
99
+ height: 0;
100
+ margin: 0;
101
+ padding: 19px 0 0;
102
+ overflow: hidden;
103
+ background: url(/images/ui/ra-tagline-mid.png) no-repeat;
104
+ }
105
+ body#home p#tagline {
106
+ top: 226px;
107
+ left: auto;
108
+ right: 15px;
109
+ width: 448px;
110
+ padding: 25px 0 0;
111
+ background: url(/images/ui/ra-tagline.png) no-repeat;
112
+ }
113
+ #main-content p {
114
+ line-height: 1.5em;
115
+ }
116
+ ul#navbar {
117
+ position: absolute;
118
+ top: 0;
119
+ right: 0;
120
+ margin: 0;
121
+ padding: 0;
122
+ list-style: none;
123
+ }
124
+ ul#navbar li {
125
+ float: left;
126
+ }
127
+ ul#navbar li a {
128
+ display: block;
129
+ height: 0;
130
+ padding: 45px 0 0;
131
+ overflow: hidden;
132
+ background: url(/images/ui/navbar.png) no-repeat;
133
+ }
134
+ ul#navbar li#nav-home a:link, ul#navbar li#nav-home a:visited {
135
+ width: 88px;
136
+ background-position: 0 0;
137
+ }
138
+ ul#navbar li#nav-home a.selected:link, ul#navbar li#nav-home a.selected:visited, ul#navbar li#nav-home a:hover {
139
+ background-position: 0 -45px;
140
+ }
141
+ ul#navbar li#nav-ruby a:link, ul#navbar li#nav-ruby a:visited {
142
+ width: 81px;
143
+ background-position: -88px 0;
144
+ }
145
+ ul#navbar li#nav-ruby a.selected:link, ul#navbar li#nav-ruby a.selected:visited, ul#navbar li#nav-ruby a:hover {
146
+ background-position: -88px -45px;
147
+ }
148
+ ul#navbar li#nav-iphone a:link, ul#navbar li#nav-iphone a:visited {
149
+ width: 95px;
150
+ background-position: -169px 0;
151
+ }
152
+ ul#navbar li#nav-iphone a.selected:link, ul#navbar li#nav-iphone a.selected:visited, ul#navbar li#nav-iphone a:hover {
153
+ background-position: -169px -45px;
154
+ }
155
+ ul#navbar li#nav-blog a:link, ul#navbar li#nav-blog a:visited {
156
+ width: 76px;
157
+ background-position: -264px 0;
158
+ }
159
+ ul#navbar li#nav-blog a.selected:link, ul#navbar li#nav-blog a.selected:visited, ul#navbar li#nav-blog a:hover {
160
+ background-position: -264px -45px;
161
+ }
162
+ ul#navbar li#nav-about a:link, ul#navbar li#nav-about a:visited {
163
+ width: 89px;
164
+ background-position: -340px 0;
165
+ }
166
+ ul#navbar li#nav-about a.selected:link, ul#navbar li#nav-about a.selected:visited, ul#navbar li#nav-about a:hover {
167
+ background-position: -340px -45px;
168
+ }
169
+ ul#navbar li#nav-contact a:link, ul#navbar li#nav-contact a:visited {
170
+ width: 105px;
171
+ background-position: -429px 0;
172
+ }
173
+ ul#navbar li#nav-contact a.selected:link, ul#navbar li#nav-contact a.selected:visited, ul#navbar li#nav-contact a:hover {
174
+ background-position: -429px -45px;
175
+ }
176
+ div.main-container {
177
+ position: relative;
178
+ width: 960px;
179
+ text-align: left;
180
+ margin: 0 auto;
181
+ overflow: auto;
182
+ }
183
+ div#header div.main-container {
184
+ overflow: visible;
185
+ }
186
+ div#main-content {
187
+ background: url(/images/ui/content-glow-large.jpg) center top no-repeat;
188
+ clear: both;
189
+ }
190
+ body#home div#main-content {
191
+ background: url(/images/ui/content-glow-w-header.jpg) center top no-repeat;
192
+ }
193
+ .inset {
194
+ padding: 15px;
195
+ }
196
+ .col-1-2 {
197
+ float: left;
198
+ width: 450px;
199
+ padding: 15px;
200
+ }
201
+ .col-1-3 {
202
+ float: left;
203
+ width: 290px;
204
+ padding: 15px;
205
+ }
206
+ .col-1-5 {
207
+ float: left;
208
+ width: 162px;
209
+ padding: 15px;
210
+ }
211
+ .first-row {
212
+ padding-top: 0;
213
+ }
214
+ div#footer {
215
+ background: url(/images/ui/content-glow-small.jpg) center top no-repeat;
216
+ clear: both;
217
+ padding: 0 0 30px;
218
+ font-family: Arial, Helvetica, sans-serif;
219
+ font-size: .85em;
220
+ }
221
+ #footer dl {
222
+ margin: 15px 0 2em;
223
+ }
224
+ #footer dt {
225
+ font-weight: bold;
226
+ color: #3c484c;
227
+ margin: 0 0 1em;
228
+ }
229
+ #footer dd {
230
+ margin: 1em 0 1em 15px;
231
+ padding: 0;
232
+ color: #778f99;
233
+ }
234
+ #footer dd a {
235
+ color: #778f99;
236
+ }
237
+ div#footer p {
238
+ margin: 0;
239
+ }
240
+ div#footer p#mini-logo {
241
+ margin: 5px 0 .5em;
242
+ }
243
+ div#footer p#copyright {
244
+ margin: .5em 0;
245
+ color: #3c484c;
246
+ text-align: center;
247
+ }
248
+ div#footer p#mini-tagline {
249
+ margin: .5em 0;
250
+ font-weight: bold;
251
+ color: #3c484c;
252
+ text-align: center;
253
+ }
254
+
255
+ h2.title {
256
+ margin-top: 0;
257
+ margin-left: -15px;
258
+ margin-bottom: .5em;
259
+ padding: 25px 0 0;
260
+ background: none;
261
+ }
262
+ h2.title a {
263
+ display: block;
264
+ height: 0;
265
+ padding: 85px 0 0;
266
+ background-repeat: no-repeat;
267
+ overflow: hidden;
268
+ }
269
+
270
+ h3.title {
271
+ background: none;
272
+ padding: 0;
273
+ }
274
+ h3.title a {
275
+ display: block;
276
+ height: 0;
277
+ padding: 27px 0 0;
278
+ background-repeat: no-repeat;
279
+ overflow: hidden;
280
+ }
281
+
282
+ div.divider {
283
+ position: relative;
284
+ clear: both;
285
+ height: 0;
286
+ margin: 0;
287
+ padding: 3px 0 0;
288
+ overflow: hidden;
289
+ background: url(/images/ui/content-divider.png) center top no-repeat;
290
+ }
291
+ div.divider hr {
292
+ margin: 0;
293
+ display: none;
294
+ }
295
+ #blog pre {
296
+ position: relative;
297
+ width: 920px;
298
+ padding: 8px;
299
+ white-space: pre;
300
+ overflow: auto;
301
+ background: #223;
302
+ border: 1px solid #778;
303
+ color: #eec;
304
+ line-height: 1.5em;
305
+ }
306
+ #blog .vcard {
307
+ font-style: italic;
308
+ float: right;
309
+ position: relative;
310
+ top: -2em;
311
+ margin: -2em 0 0;
312
+ color: #fff;
313
+ }
314
+ #blog .pagination {
315
+ margin: 1em 0;
316
+ padding: 1em 0 .5em;
317
+ text-align: center;
318
+ background: url(/images/ui/content-divider.png) center top no-repeat;
319
+ }
320
+ #blog .pagination a {
321
+ display: inline-block;
322
+ padding: 5px 9px;
323
+ margin: 0 3px;
324
+ font-size: 1.2em;
325
+ font-weight: bold;
326
+ }
327
+
328
+ .stand-out {
329
+ font-size: 1.3em;
330
+ }
@@ -0,0 +1,137 @@
1
+ pre.twilight .DiffInserted {
2
+ background-color: #253B22;
3
+ color: #F8F8F8;
4
+ }
5
+ pre.twilight .DiffHeader {
6
+ background-color: #0E2231;
7
+ color: #F8F8F8;
8
+ font-style: italic;
9
+ }
10
+ pre.twilight .CssPropertyValue {
11
+ color: #F9EE98;
12
+ }
13
+ pre.twilight .CCCPreprocessorDirective {
14
+ color: #AFC4DB;
15
+ }
16
+ pre.twilight .Constant {
17
+ color: #CF6A4C;
18
+ }
19
+ pre.twilight .DiffChanged {
20
+ background-color: #4A410D;
21
+ color: #F8F8F8;
22
+ }
23
+ pre.twilight .EmbeddedSource {
24
+ background-color: #A3A6AD;
25
+ }
26
+ pre.twilight .Support {
27
+ color: #9B859D;
28
+ }
29
+ pre.twilight .MarkupList {
30
+ color: #F9EE98;
31
+ }
32
+ pre.twilight .CssConstructorArgument {
33
+ color: #8F9D6A;
34
+ }
35
+ pre.twilight .Storage {
36
+ color: #F9EE98;
37
+ }
38
+ pre.twilight .line-numbers {
39
+ background-color: #DDF0FF;
40
+ color: #000000;
41
+ }
42
+ pre.twilight .CssClass {
43
+ color: #9B703F;
44
+ }
45
+ pre.twilight .StringConstant {
46
+ color: #DDF2A4;
47
+ }
48
+ pre.twilight .CssAtRule {
49
+ color: #8693A5;
50
+ }
51
+ pre.twilight .MetaTagInline {
52
+ color: #E0C589;
53
+ }
54
+ pre.twilight .MarkupHeading {
55
+ color: #CF6A4C;
56
+ }
57
+ pre.twilight .CssTagName {
58
+ color: #CDA869;
59
+ }
60
+ pre.twilight .SupportConstant {
61
+ color: #CF6A4C;
62
+ }
63
+ pre.twilight .DiffDeleted {
64
+ background-color: #420E09;
65
+ color: #F8F8F8;
66
+ }
67
+ pre.twilight .CCCPreprocessorLine {
68
+ color: #8996A8;
69
+ }
70
+ pre.twilight .StringRegexpSpecial {
71
+ color: #CF7D34;
72
+ }
73
+ pre.twilight .EmbeddedSourceBright {
74
+ background-color: #9C9EA4;
75
+ }
76
+ pre.twilight .InvalidIllegal {
77
+ background-color: #241A24;
78
+ color: #F8F8F8;
79
+ }
80
+ pre.twilight .SupportFunction {
81
+ color: #DAD085;
82
+ }
83
+ pre.twilight .CssAdditionalConstants {
84
+ color: #CA7840;
85
+ }
86
+ pre.twilight .MetaTagAll {
87
+ color: #AC885B;
88
+ }
89
+ pre.twilight .StringRegexp {
90
+ color: #E9C062;
91
+ }
92
+ pre.twilight .StringEmbeddedSource {
93
+ color: #DAEFA3;
94
+ }
95
+ pre.twilight .EntityInheritedClass {
96
+ color: #9B5C2E;
97
+ font-style: italic;
98
+ }
99
+ pre.twilight .CssId {
100
+ color: #8B98AB;
101
+ }
102
+ pre.twilight .CssPseudoClass {
103
+ color: #8F9D6A;
104
+ }
105
+ pre.twilight .StringVariable {
106
+ color: #8A9A95;
107
+ }
108
+ pre.twilight .String {
109
+ color: #8F9D6A;
110
+ }
111
+ pre.twilight .Keyword {
112
+ color: #CDA869;
113
+ }
114
+ pre.twilight {
115
+ background-color: #141414;
116
+ color: #F8F8F8;
117
+ }
118
+ pre.twilight .CssPropertyName {
119
+ color: #C5AF75;
120
+ }
121
+ pre.twilight .DoctypeXmlProcessing {
122
+ color: #494949;
123
+ }
124
+ pre.twilight .InvalidDeprecated {
125
+ color: #D2A8A1;
126
+ font-style: italic;
127
+ }
128
+ pre.twilight .Variable {
129
+ color: #7587A6;
130
+ }
131
+ pre.twilight .Entity {
132
+ color: #9B703F;
133
+ }
134
+ pre.twilight .Comment {
135
+ color: #5F5A60;
136
+ font-style: italic;
137
+ }
@@ -0,0 +1,187 @@
1
+ <public:component>
2
+ <script type="text/javascript">
3
+
4
+ // IE5.5+ PNG Alpha Fix v2.0 Alpha
5
+ // (c) 2004-2008 Angus Turnbull http://www.twinhelix.com
6
+
7
+ // This is licensed under the GNU LGPL, version 2.1 or later.
8
+ // For details, see: http://creativecommons.org/licenses/LGPL/2.1/
9
+
10
+ var IEPNGFix = window.IEPNGFix || {};
11
+ IEPNGFix.data = IEPNGFix.data || {};
12
+
13
+
14
+ // This must be a path to a blank image, relative to the HTML document(s).
15
+ // In production use I suggest '/images/blank.gif' or similar. That's all!
16
+ IEPNGFix.blankImg = '/scripts/blank.gif';
17
+
18
+
19
+ IEPNGFix.fix = function(elm, src, t) {
20
+ // Applies an image 'src' to an element 'elm' using the DirectX filter.
21
+ // If 'src' is null, filter is disabled.
22
+ // Disables the 'hook' to prevent infinite recursion on setting BG/src.
23
+ // 't' = type, where background tile = 0, background = 1, IMG SRC = 2.
24
+
25
+ var h = this.hook.enabled;
26
+ this.hook.enabled = 0;
27
+
28
+ var f = 'DXImageTransform.Microsoft.AlphaImageLoader';
29
+ src = (src || '').replace(/\(/g, '%28').replace(/\)/g, '%29');
30
+
31
+ if (
32
+ src && !(/IMG|INPUT/.test(elm.nodeName) && (t != 2)) &&
33
+ elm.currentStyle.width == 'auto' && elm.currentStyle.height == 'auto'
34
+ ) {
35
+ elm.style.width = elm.offsetWidth + 'px';
36
+ elm.style.height = elm.clientHeight + 'px';
37
+ if (elm.currentStyle.display == 'inline') {
38
+ elm.style.display = 'inline-block';
39
+ }
40
+ }
41
+
42
+ if (t == 1) {
43
+ elm.style.backgroundImage = 'url("' + this.blankImg + '")';
44
+ }
45
+ if (t == 2) {
46
+ elm.src = this.blankImg;
47
+ }
48
+
49
+ if (elm.filters[f]) {
50
+ elm.filters[f].enabled = src ? true : false;
51
+ if (src) {
52
+ elm.filters[f].src = src;
53
+ }
54
+ } else if (src) {
55
+ elm.style.filter = 'progid:' + f + '(src="' + src +
56
+ '",sizingMethod="' + (t == 2 ? 'scale' : 'crop') + '")';
57
+ }
58
+
59
+ this.hook.enabled = h;
60
+ };
61
+
62
+
63
+ IEPNGFix.process = function(elm, init) {
64
+ // Checks the onpropertychange event (on first 'init' run, a fake event)
65
+ // and calls the filter-applying-functions.
66
+
67
+ if (
68
+ !/MSIE (5\.5|6)/.test(navigator.userAgent) ||
69
+ typeof elm.filters == 'unknown'
70
+ ) {
71
+ return;
72
+ }
73
+ if (!this.data[elm.uniqueID]) {
74
+ this.data[elm.uniqueID] = {
75
+ className: ''
76
+ };
77
+ }
78
+ var data = this.data[elm.uniqueID],
79
+ evt = init ? { propertyName: 'src,backgroundImage' } : event,
80
+ isSrc = /src/.test(evt.propertyName),
81
+ isBg = /backgroundImage/.test(evt.propertyName),
82
+ isPos = /width|height|background(Pos|Rep)/.test(evt.propertyName),
83
+ isClass = !init && ((elm.className != data.className) &&
84
+ (elm.className || data.className));
85
+ if (!(isSrc || isBg || isPos || isClass)) {
86
+ return;
87
+ }
88
+ data.className = elm.className;
89
+ var blank = this.blankImg.match(/([^\/]+)$/)[1],
90
+ eS = elm.style,
91
+ eCS = elm.currentStyle;
92
+
93
+ // Required for Whatever:hover - erase set BG if className changes.
94
+ if (
95
+ isClass && (eS.backgroundImage.indexOf('url(') == -1 ||
96
+ eS.backgroundImage.indexOf(blank) > -1)
97
+ ) {
98
+ return setTimeout(function() {
99
+ eS.backgroundImage = '';
100
+ }, 0);
101
+ }
102
+
103
+ // Foregrounds.
104
+ if (isSrc && elm.src && { IMG: 1, INPUT: 1 }[elm.nodeName]) {
105
+ if ((/\.png/i).test(elm.src)) {
106
+ this.fix(elm, elm.src, 2);
107
+ } else if (elm.src.indexOf(blank) == -1) {
108
+ this.fix(elm, '');
109
+ }
110
+ }
111
+
112
+ // Backgrounds.
113
+ var bgSrc = eCS.backgroundImage || eS.backgroundImage;
114
+ if ((bgSrc + elm.src).indexOf(blank) == -1) {
115
+ var bgPNG = bgSrc.match(/url[("']+(.*\.png[^\)"']*)[\)"']/i);
116
+ if (bgPNG) {
117
+ if (this.tileBG && !{ IMG: 1, INPUT: 1 }[elm.nodeName]) {
118
+ this.tileBG(elm, bgPNG[1]);
119
+ this.fix(elm, '', 1);
120
+ } else {
121
+ if (data.tiles && data.tiles.src) {
122
+ this.tileBG(elm, '');
123
+ }
124
+ this.fix(elm, bgPNG[1], 1);
125
+ this.childFix(elm);
126
+ }
127
+ } else {
128
+ if (data.tiles && data.tiles.src) {
129
+ this.tileBG(elm, '');
130
+ }
131
+ this.fix(elm, '');
132
+ }
133
+ } else if ((isPos || isClass) && data.tiles && data.tiles.src) {
134
+ this.tileBG(elm, data.tiles.src);
135
+ }
136
+
137
+ if (init) {
138
+ this.hook.enabled = 1;
139
+ elm.attachEvent('onpropertychange', this.hook);
140
+ }
141
+ };
142
+
143
+
144
+ IEPNGFix.childFix = function(elm) {
145
+ // "hasLayout" fix for unclickable children inside PNG backgrounds.
146
+ var tags = [
147
+ 'a',
148
+ 'input',
149
+ 'select',
150
+ 'textarea',
151
+ 'button',
152
+ 'iframe',
153
+ 'object'
154
+ ],
155
+ t = tags.length,
156
+ tFix = [];
157
+ while (t--) {
158
+ var pFix = elm.all.tags(tags[t]),
159
+ e = pFix.length;
160
+ while (e--) {
161
+ tFix.push(pFix[e]);
162
+ }
163
+ }
164
+ t = tFix.length;
165
+ if (t && (/relative|absolute/i).test(elm.currentStyle.position)) {
166
+ alert('IEPNGFix: Unclickable children of element:' +
167
+ '\n\n<' + elm.nodeName + (elm.id && ' id=' + elm.id) + '>');
168
+ }
169
+ while (t--) {
170
+ if (!(/relative|absolute/i).test(tFix[t].currentStyle.position)) {
171
+ tFix[t].style.position = 'relative';
172
+ }
173
+ }
174
+ };
175
+
176
+
177
+ IEPNGFix.hook = function() {
178
+ if (IEPNGFix.hook.enabled) {
179
+ IEPNGFix.process(element, 0);
180
+ }
181
+ };
182
+
183
+
184
+ IEPNGFix.process(element, 1);
185
+
186
+ </script>
187
+ </public:component>
@@ -0,0 +1,173 @@
1
+ // IE5.5+ PNG Alpha Fix v2.0 Alpha: Background Tiling Support
2
+ // (c) 2008 Angus Turnbull http://www.twinhelix.com
3
+
4
+ // This is licensed under the GNU LGPL, version 2.1 or later.
5
+ // For details, see: http://creativecommons.org/licenses/LGPL/2.1/
6
+
7
+ var IEPNGFix = window.IEPNGFix || {};
8
+
9
+ IEPNGFix.tileBG = function(elm, pngSrc, ready) {
10
+ // Params: A reference to a DOM element, the PNG src file pathname, and a
11
+ // hidden "ready-to-run" passed when called back after image preloading.
12
+
13
+ var data = this.data[elm.uniqueID],
14
+ elmW = Math.max(elm.clientWidth, elm.scrollWidth),
15
+ elmH = Math.max(elm.clientHeight, elm.scrollHeight),
16
+ bgX = elm.currentStyle.backgroundPositionX,
17
+ bgY = elm.currentStyle.backgroundPositionY,
18
+ bgR = elm.currentStyle.backgroundRepeat;
19
+
20
+ // Cache of DIVs created per element, and image preloader/data.
21
+ if (!data.tiles) {
22
+ data.tiles = {
23
+ elm: elm,
24
+ src: '',
25
+ cache: [],
26
+ img: new Image(),
27
+ old: {}
28
+ };
29
+ }
30
+ var tiles = data.tiles,
31
+ pngW = tiles.img.width,
32
+ pngH = tiles.img.height;
33
+
34
+ if (pngSrc) {
35
+ if (!ready && pngSrc != tiles.src) {
36
+ // New image? Preload it with a callback to detect dimensions.
37
+ tiles.img.onload = function() {
38
+ this.onload = null;
39
+ IEPNGFix.tileBG(elm, pngSrc, 1);
40
+ };
41
+ return tiles.img.src = pngSrc;
42
+ }
43
+ } else {
44
+ // No image?
45
+ if (tiles.src) ready = 1;
46
+ pngW = pngH = 0;
47
+ }
48
+ tiles.src = pngSrc;
49
+
50
+ if (!ready && elmW == tiles.old.w && elmH == tiles.old.h &&
51
+ bgX == tiles.old.x && bgY == tiles.old.y && bgR == tiles.old.r) {
52
+ return;
53
+ }
54
+
55
+ // Convert English and percentage positions to pixels.
56
+ var pos = {
57
+ top: '0%',
58
+ left: '0%',
59
+ center: '50%',
60
+ bottom: '100%',
61
+ right: '100%'
62
+ },
63
+ x,
64
+ y,
65
+ pc;
66
+ x = pos[bgX] || bgX;
67
+ y = pos[bgY] || bgY;
68
+ if (pc = x.match(/(\d+)%/)) {
69
+ x = Math.round((elmW - pngW) * (parseInt(pc[1]) / 100));
70
+ }
71
+ if (pc = y.match(/(\d+)%/)) {
72
+ y = Math.round((elmH - pngH) * (parseInt(pc[1]) / 100));
73
+ }
74
+ x = parseInt(x);
75
+ y = parseInt(y);
76
+
77
+ // Handle backgroundRepeat.
78
+ var repeatX = { 'repeat': 1, 'repeat-x': 1 }[bgR],
79
+ repeatY = { 'repeat': 1, 'repeat-y': 1 }[bgR];
80
+ if (repeatX) {
81
+ x %= pngW;
82
+ if (x > 0) x -= pngW;
83
+ }
84
+ if (repeatY) {
85
+ y %= pngH;
86
+ if (y > 0) y -= pngH;
87
+ }
88
+
89
+ // Go!
90
+ this.hook.enabled = 0;
91
+ if (!({ relative: 1, absolute: 1 }[elm.currentStyle.position])) {
92
+ elm.style.position = 'relative';
93
+ }
94
+ var count = 0,
95
+ xPos,
96
+ maxX = repeatX ? elmW : x + 0.1,
97
+ yPos,
98
+ maxY = repeatY ? elmH : y + 0.1,
99
+ d,
100
+ s,
101
+ isNew;
102
+ if (pngW && pngH) {
103
+ for (xPos = x; xPos < maxX; xPos += pngW) {
104
+ for (yPos = y; yPos < maxY; yPos += pngH) {
105
+ isNew = 0;
106
+ if (!tiles.cache[count]) {
107
+ tiles.cache[count] = document.createElement('div');
108
+ isNew = 1;
109
+ }
110
+ var clipR = (xPos + pngW > elmW ? elmW - xPos : pngW),
111
+ clipB = (yPos + pngH > elmH ? elmH - yPos : pngH);
112
+ d = tiles.cache[count];
113
+ s = d.style;
114
+ s.behavior = 'none';
115
+ s.left = xPos + 'px';
116
+ s.top = yPos + 'px';
117
+ s.width = clipR + 'px';
118
+ s.height = clipB + 'px';
119
+ s.clip = 'rect(' +
120
+ (yPos < 0 ? 0 - yPos : 0) + 'px,' +
121
+ clipR + 'px,' +
122
+ clipB + 'px,' +
123
+ (xPos < 0 ? 0 - xPos : 0) + 'px)';
124
+ s.display = 'block';
125
+ if (isNew) {
126
+ s.position = 'absolute';
127
+ s.zIndex = -999;
128
+ if (elm.firstChild) {
129
+ elm.insertBefore(d, elm.firstChild);
130
+ } else {
131
+ elm.appendChild(d);
132
+ }
133
+ }
134
+ this.fix(d, pngSrc, 0);
135
+ count++;
136
+ }
137
+ }
138
+ }
139
+ while (count < tiles.cache.length) {
140
+ this.fix(tiles.cache[count], '', 0);
141
+ tiles.cache[count++].style.display = 'none';
142
+ }
143
+
144
+ this.hook.enabled = 1;
145
+
146
+ // Cache so updates are infrequent.
147
+ tiles.old = {
148
+ w: elmW,
149
+ h: elmH,
150
+ x: bgX,
151
+ y: bgY,
152
+ r: bgR
153
+ };
154
+ };
155
+
156
+
157
+ IEPNGFix.update = function() {
158
+ // Update all PNG backgrounds.
159
+ for (var i in IEPNGFix.data) {
160
+ var t = IEPNGFix.data[i].tiles;
161
+ if (t && t.elm && t.src) {
162
+ IEPNGFix.tileBG(t.elm, t.src);
163
+ }
164
+ }
165
+ };
166
+ IEPNGFix.update.timer = 0;
167
+
168
+ if (window.attachEvent && !window.opera) {
169
+ window.attachEvent('onresize', function() {
170
+ clearTimeout(IEPNGFix.update.timer);
171
+ IEPNGFix.update.timer = setTimeout(IEPNGFix.update, 100);
172
+ });
173
+ }
@@ -0,0 +1,9 @@
1
+ <div class="content">
2
+ <div class="hentry">
3
+ <h2><%=h @post.title %></h2>
4
+ <div class="vcard">
5
+ posted by <a href="mailto:<%= @post.email %>"><%= @post.nickname %></a>, <span class="published"><%=h @post.posted.to_s(:posted) %></span>
6
+ </div>
7
+ <%= markup(File.read(@post.content)) %>
8
+ </div>
9
+ </div>
@@ -0,0 +1,17 @@
1
+ <div class="content">
2
+ <% @posts.each do |post| %>
3
+ <div class="hentry">
4
+ <h2><a href="<%= post.url %>"><%=h post.title %></a></h2>
5
+ <div class="vcard">
6
+ posted by <a href="mailto:<%= post.email %>"><%= post.nickname %></a>, <span class="published"><%= h post.posted.to_s(:posted) %></span>
7
+ </div>
8
+ <%= markup File.read(post.content) %>
9
+ </div>
10
+ <% end %>
11
+
12
+ <div class="pagination">
13
+ <% @pages.times do |i| %>
14
+ <a <%= 'id="selected"' if current_page?(i + 1) %> href="/blog?page=<%= i + 1 %>"><%= i + 1 %></a>
15
+ <% end %>
16
+ </div>
17
+ </div>
@@ -0,0 +1,42 @@
1
+ <DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="description" content="<%= Array(blog.description_tags)*', '%>" />
6
+ <meta name="keywords" content="<%= (Array(blog.keyword_tags) + Array(@post_tags))*', '%>" />
7
+ <!--[if IE]><script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
8
+ <style> article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } </style>
9
+
10
+ <% blog = Blogical::Application %>
11
+ <title><%= blog.title %></title>
12
+
13
+ <!-- Need HTML5 links here -->
14
+ <link type="text/css" rel="stylesheet" href="/css/screen.css" />
15
+ <link type="text/css" rel="stylesheet" href="/css/twilight.css" />
16
+ <link rel="icon" type="image/vnd.microsoft.icon" href="/favicon.ico" />
17
+ <link rel="icon" type="image/png" href="/favicon.png" />
18
+ <link href="/blog/atom.xml" rel="alternate" type="application/atom+xml" />
19
+ <!--[if lt IE 7]><script type="text/javascript" src="/scripts/iepngfix.tilebg.js"></script>
20
+ <style type="text/css">
21
+ img, div, a, p, h1, h2, li, span { behavior: url(/scripts/iepngfix.htc); }
22
+ </style><![endif]-->
23
+ </head>
24
+
25
+ <script src="http://www.google-analytics.com/urchin.js" type="text/javascript"/>
26
+ <script type="text/javascript">
27
+ _uacct = <%= blog.urchin_account_id %>;
28
+ urchinTracker();
29
+ </script>
30
+
31
+ <body id="<%= body_id %>">
32
+ <div id="header">
33
+ <!-- Put your header code here -->
34
+ </div>
35
+ <div class="main-container">
36
+ <%= yield %>
37
+ </div>
38
+ <div id="footer">
39
+ <!-- Put your footer code here -->
40
+ </div>
41
+ </body>
42
+ </html>
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blogical
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
9
+ - 2
10
+ version: 0.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Clifford Heath
@@ -33,10 +33,24 @@ files:
33
33
  - Gemfile
34
34
  - README.markdown
35
35
  - config.ru
36
+ - app/blogical/atom.rb
37
+ - app/blogical/blog.rb
38
+ - app/blogical/content.rb
39
+ - app/blogical/extensions.rb
40
+ - app/blogical/helpers.rb
36
41
  - app/blogical.rb
42
+ - content/01 Welcome/content.markdown
43
+ - content/01 Welcome/meta.rb
37
44
  - logs/access.log
38
45
  - logs/error.log
46
+ - public/css/screen.css
47
+ - public/css/twilight.css
48
+ - public/scripts/iepngfix.htc
49
+ - public/scripts/iepngfix.tilebg.js
39
50
  - tmp/restart.txt
51
+ - views/blogical/article.erb
52
+ - views/blogical/blog.erb
53
+ - views/blogical/layout.erb
40
54
  has_rdoc: true
41
55
  homepage: http://github.com/cjheath/blogical
42
56
  licenses: []