blogical 0.0.1 → 0.0.2

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.
@@ -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: []