From 2e49f2c9e7c603572e24ffac0cbf96260c305407 Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Wed, 7 Jul 2010 00:29:51 -0700 Subject: [PATCH 01/17] Minimal working frontend. --- gollum.gemspec | 3 + lib/gollum/frontend/app.rb | 62 ++++++++++++ lib/gollum/frontend/public/css/global.css | 93 ++++++++++++++++++ lib/gollum/frontend/templates/layout.mustache | 15 +++ lib/gollum/frontend/templates/page.mustache | 1 + lib/gollum/frontend/views/layout.rb | 12 +++ lib/gollum/frontend/views/page.rb | 11 +++ lib/gollum/markup.rb | 12 +-- templates/formatting.html | 92 +++++++++++++++++ .../01/676dc56d35c1999c6fe9043fe8b78d52a0e797 | Bin 0 -> 195 bytes .../07/9a5887755dc6fbacfdb672abc168b0cce698fa | Bin 0 -> 747 bytes .../11/5bbf9fe8004aa6a06274b44ab93a84a06e3204 | Bin 0 -> 196 bytes .../14/78ebf7ad4dc6a06c76cdb4aca0eba7f78796aa | Bin 0 -> 195 bytes .../1e/716a3178a76fe39ee7b88f0cf2dc4a447566f6 | Bin 0 -> 164 bytes .../28/bb2f40d2e4c82a4ae62ef619a80a4b555e23ee | Bin 0 -> 171 bytes .../2c/b9156ad383914561a8502fc70f5a1d887e48ad | Bin 0 -> 399 bytes .../37/fcc52509fb09142cafccaada0252f3de81873c | Bin 0 -> 195 bytes .../4c/770a352f1e86071b680f879a89874bf59008fa | Bin 0 -> 195 bytes .../4f/de706c7c8d3b30b6caec8c82ff4c01261350f2 | 3 + .../71/4323c104239440a5c66ab12a67ed07a83c404f | Bin 0 -> 9596 bytes .../79/8f6564abb42d7ed34621d53595cbbe84638949 | 1 + .../7c/7251d713278633fbe506e1b74aba6c91ddd562 | Bin 0 -> 125 bytes .../93/633112529b0d0bdf25c2206682e59e9f5572e5 | Bin 0 -> 759 bytes .../a3/46f056d6d8e89f034489e403b3924fbc95f201 | Bin 0 -> 195 bytes .../af/e2034d400ba21e13361f38f74900c51dbc7fde | 2 + .../b0/d108328459e44fff4a76cd19b10ddc34adce4b | Bin 0 -> 167 bytes .../b3/14b19c56ee272a7c9dc379996d9a32f5c463d7 | Bin 0 -> 194 bytes .../bc/d5c99495011915971b2c9e38da8e5aacfe875d | 2 + .../d9/e379fdea55b6ff3b71c110b3d2d7b55bbfd5ee | Bin 0 -> 124 bytes .../e3/415337d9ae2c0b4b00054a93727f4a7d3c3ca5 | Bin 0 -> 124 bytes .../f2/5eccd98e9b667f9e22946f3e2f945378b8a72d | 2 + .../f4/46205ac9df5b6a40c00785f06827f4a4dbd727 | 1 + .../fa/e7ef5344202bba4129abdc13060d9297d99465 | 3 + test/examples/lotr.git/refs/heads/master | 2 +- test/test_markup.rb | 10 +- test/test_page.rb | 2 +- test/test_wiki.rb | 16 +-- 37 files changed, 325 insertions(+), 20 deletions(-) create mode 100644 lib/gollum/frontend/app.rb create mode 100644 lib/gollum/frontend/public/css/global.css create mode 100644 lib/gollum/frontend/templates/layout.mustache create mode 100644 lib/gollum/frontend/templates/page.mustache create mode 100644 lib/gollum/frontend/views/layout.rb create mode 100644 lib/gollum/frontend/views/page.rb create mode 100644 templates/formatting.html create mode 100644 test/examples/lotr.git/objects/01/676dc56d35c1999c6fe9043fe8b78d52a0e797 create mode 100644 test/examples/lotr.git/objects/07/9a5887755dc6fbacfdb672abc168b0cce698fa create mode 100644 test/examples/lotr.git/objects/11/5bbf9fe8004aa6a06274b44ab93a84a06e3204 create mode 100644 test/examples/lotr.git/objects/14/78ebf7ad4dc6a06c76cdb4aca0eba7f78796aa create mode 100644 test/examples/lotr.git/objects/1e/716a3178a76fe39ee7b88f0cf2dc4a447566f6 create mode 100644 test/examples/lotr.git/objects/28/bb2f40d2e4c82a4ae62ef619a80a4b555e23ee create mode 100644 test/examples/lotr.git/objects/2c/b9156ad383914561a8502fc70f5a1d887e48ad create mode 100644 test/examples/lotr.git/objects/37/fcc52509fb09142cafccaada0252f3de81873c create mode 100644 test/examples/lotr.git/objects/4c/770a352f1e86071b680f879a89874bf59008fa create mode 100644 test/examples/lotr.git/objects/4f/de706c7c8d3b30b6caec8c82ff4c01261350f2 create mode 100644 test/examples/lotr.git/objects/71/4323c104239440a5c66ab12a67ed07a83c404f create mode 100644 test/examples/lotr.git/objects/79/8f6564abb42d7ed34621d53595cbbe84638949 create mode 100644 test/examples/lotr.git/objects/7c/7251d713278633fbe506e1b74aba6c91ddd562 create mode 100644 test/examples/lotr.git/objects/93/633112529b0d0bdf25c2206682e59e9f5572e5 create mode 100644 test/examples/lotr.git/objects/a3/46f056d6d8e89f034489e403b3924fbc95f201 create mode 100644 test/examples/lotr.git/objects/af/e2034d400ba21e13361f38f74900c51dbc7fde create mode 100644 test/examples/lotr.git/objects/b0/d108328459e44fff4a76cd19b10ddc34adce4b create mode 100644 test/examples/lotr.git/objects/b3/14b19c56ee272a7c9dc379996d9a32f5c463d7 create mode 100644 test/examples/lotr.git/objects/bc/d5c99495011915971b2c9e38da8e5aacfe875d create mode 100644 test/examples/lotr.git/objects/d9/e379fdea55b6ff3b71c110b3d2d7b55bbfd5ee create mode 100644 test/examples/lotr.git/objects/e3/415337d9ae2c0b4b00054a93727f4a7d3c3ca5 create mode 100644 test/examples/lotr.git/objects/f2/5eccd98e9b667f9e22946f3e2f945378b8a72d create mode 100644 test/examples/lotr.git/objects/f4/46205ac9df5b6a40c00785f06827f4a4dbd727 create mode 100644 test/examples/lotr.git/objects/fa/e7ef5344202bba4129abdc13060d9297d99465 diff --git a/gollum.gemspec b/gollum.gemspec index 62c84760..2071a8fa 100644 --- a/gollum.gemspec +++ b/gollum.gemspec @@ -24,7 +24,10 @@ Gem::Specification.new do |s| s.extra_rdoc_files = %w[README.md LICENSE] s.add_dependency('grit', [">= 2.0.0", "< 3.0.0"]) + s.add_dependency('github-markup', [">= 0.4.0", "< 1.0.0"]) s.add_dependency('albino', "~> 1.0.0") + s.add_dependency('sinatra', "~> 1.0.0") + s.add_dependency('mustache', [">= 0.11.2", "< 1.0.0"]) s.add_development_dependency('shoulda') s.add_development_dependency('mocha') diff --git a/lib/gollum/frontend/app.rb b/lib/gollum/frontend/app.rb new file mode 100644 index 00000000..e7044548 --- /dev/null +++ b/lib/gollum/frontend/app.rb @@ -0,0 +1,62 @@ +require 'rubygems' + +require 'sinatra' +require 'gollum' +require 'mustache/sinatra' + +require 'gollum/frontend/views/layout' + +$path = "~/dev/mojombo/gollum/test/examples/lotr.git" + +module Precious + class App < Sinatra::Base + register Mustache::Sinatra + + dir = File.dirname(File.expand_path(__FILE__)) + + # We want to serve public assets for now + set :public, "#{dir}/public" + set :static, true + + set :mustache, { + # Tell mustache where the Views constant lives + :namespace => Precious, + + # Mustache templates live here + :templates => "#{dir}/templates", + + # Tell mustache where the views are + :views => "#{dir}/views" + } + + # Sinatra error handling + configure :development, :staging do + set :raise_errors, false + set :show_exceptions, true + set :dump_errors, true + set :clean_trace, false + end + + get '/' do + show_page_or_file('Home') + end + + get '/*' do + show_page_or_file(params[:splat].first) + end + + def show_page_or_file(name) + wiki = Gollum::Wiki.new($path) + if page = wiki.page(name) + @content = page.formatted_data + mustache :page + elsif file = wiki.file(name) + file.raw_data + else + halt 404 + end + end + end +end + +Precious::App.run! diff --git a/lib/gollum/frontend/public/css/global.css b/lib/gollum/frontend/public/css/global.css new file mode 100644 index 00000000..f9e98c50 --- /dev/null +++ b/lib/gollum/frontend/public/css/global.css @@ -0,0 +1,93 @@ +h1, h2, h3, h4, h5, h6 { + color: #f90; + font-weight: bold; + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +h1 { + font-size: 36pt; +} + +h2 { + font-size: 32pt; +} + +h3 { + font-size: 28pt; +} + +h4 { + font-size: 24pt; +} + +h5 { + font-size: 20pt; +} + +h6 { + font-size: 16pt; +} + +p { + font-family: Georgia, serif; + font-size: 14pt; + line-height: 22pt; +} + +#content { + width: 60em; + margin: 0 auto; + color: #666; +} + +/***********************/ + +.frame { + margin: 1em 0; + display: inline-block; +} + +.frame img { + display: block; +} + +.frame > span { + display: block; + border: 1px solid #aaa; + padding: 4px; +} + +.frame span span { + display: block; + font-size: 10pt; + margin: 0; + padding: 4px 0 2px 0; + text-align: center; + line-height: 10pt; + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +.float-left { + float: left; + padding: .5em 1em .25em 0; +} + +.float-right { + float: right; + padding: .5em 0 .25em 1em; +} + +.align-left { + display: block; + text-align: left; +} + +.align-center { + display: block; + text-align: center; +} + +.align-right { + display: block; + text-align: right; +} \ No newline at end of file diff --git a/lib/gollum/frontend/templates/layout.mustache b/lib/gollum/frontend/templates/layout.mustache new file mode 100644 index 00000000..5d3ad456 --- /dev/null +++ b/lib/gollum/frontend/templates/layout.mustache @@ -0,0 +1,15 @@ + + + + + + Gollum - {{title}} + + + + +
+ {{{yield}}} +
+ + diff --git a/lib/gollum/frontend/templates/page.mustache b/lib/gollum/frontend/templates/page.mustache new file mode 100644 index 00000000..86ee4641 --- /dev/null +++ b/lib/gollum/frontend/templates/page.mustache @@ -0,0 +1 @@ +{{{content}}} \ No newline at end of file diff --git a/lib/gollum/frontend/views/layout.rb b/lib/gollum/frontend/views/layout.rb new file mode 100644 index 00000000..ae53aa24 --- /dev/null +++ b/lib/gollum/frontend/views/layout.rb @@ -0,0 +1,12 @@ +module Precious + module Views + class Layout < Mustache + include Rack::Utils + alias_method :h, :escape_html + + def title + "Home" + end + end + end +end diff --git a/lib/gollum/frontend/views/page.rb b/lib/gollum/frontend/views/page.rb new file mode 100644 index 00000000..a1aa9b0d --- /dev/null +++ b/lib/gollum/frontend/views/page.rb @@ -0,0 +1,11 @@ +module Precious + module Views + class Page < Layout + attr_reader :content + + def title + "A Page" + end + end + end +end diff --git a/lib/gollum/markup.rb b/lib/gollum/markup.rb index c7ad7bd9..d1a7010b 100644 --- a/lib/gollum/markup.rb +++ b/lib/gollum/markup.rb @@ -100,7 +100,7 @@ module Gollum containered = true align ||= 'left' if %w{left right}.include?(align) - classes << "float-#{align};" + classes << "float-#{align}" end elsif %w{top texttop middle absmiddle bottom absbottom baseline}.include?(align) attrs << %{align="#{align}"} @@ -136,12 +136,12 @@ module Gollum if opts['frame'] || containered classes << 'frame' if opts['frame'] - %{
} + - %{
} + + %{} + + %{} + %{} + - (alt ? %{

#{alt}

} : '') + - %{
} + - %{
} + (alt ? %{#{alt}} : '') + + %{} + + %{} else %{} end diff --git a/templates/formatting.html b/templates/formatting.html new file mode 100644 index 00000000..dd0b3df5 --- /dev/null +++ b/templates/formatting.html @@ -0,0 +1,92 @@ + + +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas hendrerit eros felis. Nunc non enim at dolor malesuada pellentesque a quis nibh. Aliquam sit amet pretium ante. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas hendrerit eros felis. Nunc non enim at dolor malesuada pellentesque a quis nibh. Aliquam sit amet pretium ante. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas hendrerit eros felis. Nunc non enim at dolor malesuada pellentesque a quis nibh. Aliquam sit amet pretium ante. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas hendrerit eros felis. Nunc non enim at dolor malesuada pellentesque a quis nibh. Aliquam sit amet pretium ante. + +

+
+ +

Google

+
+
+ +Fusce ullamcorper orci enim. Duis lectus elit, convallis ac convallis sit amet, euismod imperdiet dolor. Nunc egestas nisi quis magna feugiat vitae fringilla elit fermentum. + +
+
+ +

Google

+
+
+ +Vivamus sollicitudin dolor sit amet elit mollis ultricies. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas hendrerit eros felis. Nunc non enim at dolor malesuada pellentesque a quis nibh. Aliquam sit amet pretium ante. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas hendrerit eros felis. Nunc non enim at dolor malesuada pellentesque a quis nibh. Aliquam sit amet pretium ante. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas hendrerit eros felis. Nunc non enim at dolor malesuada pellentesque a quis nibh. Aliquam sit amet pretium ante.

+ +

+
+ +

Google

+
+
+ +

Phasellus porta dignissim leo vel hendrerit. Nulla pellentesque nisi ac nunc malesuada aliquam. Nullam et cursus augue. Sed rhoncus pharetra odio, vel dictum diam facilisis et. Etiam molestie justo ut purus elementum rhoncus. Fusce nec augue lectus. Proin a nisl ac lectus facilisis tempus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent blandit tempus libero, in interdum odio dignissim quis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec quis arcu a metus tincidunt scelerisque eget sed mauris. Nullam pellentesque faucibus sodales. Integer ullamcorper enim id nibh tempor ultricies.

+ +
+
+ +

Google

+
+
+ +

Phasellus porta dignissim leo vel hendrerit. Nulla pellentesque nisi ac nunc malesuada aliquam. Nullam et cursus augue. Sed rhoncus pharetra odio, vel dictum diam facilisis et. Etiam molestie justo ut purus elementum rhoncus. Fusce nec augue lectus. Proin a nisl ac lectus facilisis tempus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent blandit tempus libero, in interdum odio dignissim quis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec quis arcu a metus tincidunt scelerisque eget sed mauris. Nullam pellentesque faucibus sodales. Integer ullamcorper enim id nibh tempor ultricies.

+ +

+

+
+ +
+
+

+ +

Phasellus porta dignissim leo vel hendrerit. Nulla pellentesque nisi ac nunc malesuada aliquam. Nullam et cursus augue. Sed rhoncus pharetra odio, vel dictum diam facilisis et. Etiam molestie justo ut purus elementum rhoncus. Fusce nec augue lectus. Proin a nisl ac lectus facilisis tempus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent blandit tempus libero, in interdum odio dignissim quis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec quis arcu a metus tincidunt scelerisque eget sed mauris. Nullam pellentesque faucibus sodales. Integer ullamcorper enim id nibh tempor ultricies.

+
+ +
+
Phasellus porta dignissim leo vel hendrerit. Nulla pellentesque nisi ac nunc malesuada aliquam. Nullam et cursus augue. Sed rhoncus pharetra odio, vel dictum diam facilisis et. Etiam molestie justo ut purus elementum rhoncus. Fusce nec augue lectus. Proin a nisl ac lectus facilisis tempus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Praesent blandit tempus libero, in interdum odio dignissim quis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec quis arcu a metus tincidunt scelerisque eget sed mauris. Nullam pellentesque faucibus sodales. Integer ullamcorper enim id nibh tempor ultricies.

\ No newline at end of file diff --git a/test/examples/lotr.git/objects/01/676dc56d35c1999c6fe9043fe8b78d52a0e797 b/test/examples/lotr.git/objects/01/676dc56d35c1999c6fe9043fe8b78d52a0e797 new file mode 100644 index 0000000000000000000000000000000000000000..6ff4cb8945f10a355c02f3be731498ae185ee399 GIT binary patch literal 195 zcmV;!06hPA0V^p=O;s?oG-NO|FfcPQQEYF!db67`ac%NP!Cv765^Et{jSigD5tv+XNdLiAXnYCQ6DQ}s$x zD@rnRQW<_de;@3kpuNjcbM+lzHr`3oZ%#=yF#rMu-~6JK{33>$qQL9I>TSlqpRzsN x?zJmt;@zuBP=n&#^7Bhli$G3#bIXWz-$Pf0Ra=+uHYlFN<~_Nu833dfOJ4;%Up@c; literal 0 HcmV?d00001 diff --git a/test/examples/lotr.git/objects/07/9a5887755dc6fbacfdb672abc168b0cce698fa b/test/examples/lotr.git/objects/07/9a5887755dc6fbacfdb672abc168b0cce698fa new file mode 100644 index 0000000000000000000000000000000000000000..682d63571cb575aa8afd49d4edb73edde1170578 GIT binary patch literal 747 zcmV_ZVyq&{jMRQ*uo$kLVhSVMS}z09&h$oOd;CI4DB+P7)aC-*_jcplXX_2lBz_ zf^3;utZ0Y1X+l+#fc!nxPHwWyI^1MNsG)EB!563m4`j?3GXxr;0f-8{ccuU}v<|${ zmNCaP=>fenz(v5Cep{5g&U%Iu!Ev!kVSmY{!P^2wfEoKXJ80~&r3qrY&Lb8h#IrqsNlOzH@# zzk)5a;6eg)&as}9*_&mO=u7aBZ(xj)85~7kE6f>pf+ITmn9BtO8)60a_Jpzxeag;& zUzqC`%M{jr~r5M<0!Vy}Q_C)6xljp1+=%_MMML-Ki-is@(5EEKg0p5}4u9WaG^ zmeC6v~CYy??jY)IWI{JgoeGz4BFcfosj;|LcdgsXzKI dFh$Ouo}P|B%e%l*(96AV4|8ZK`304fh3Y?;ai#zO literal 0 HcmV?d00001 diff --git a/test/examples/lotr.git/objects/11/5bbf9fe8004aa6a06274b44ab93a84a06e3204 b/test/examples/lotr.git/objects/11/5bbf9fe8004aa6a06274b44ab93a84a06e3204 new file mode 100644 index 0000000000000000000000000000000000000000..25024714322cbf9ee362ebfa10770a6c59f90924 GIT binary patch literal 196 zcmV;#06YJ90V^p=O;s?oG-NO|FfcPQQEYF!db67`ac%NP!Cv765^Et{jSigD5tv+XNdLiAXnYCQ6DQ}s$x zD@rnRQW<_de;@3kpuNjcbM+lzHr`3oZ%#=yF#rMu-~6JK{33>%k1PMa3f=bKy6~XD y=1bSNM(@A+4r)-mTYi2?Y7xjuZ*Cc}?tAE}uxjh_-3G;z*t{qAH3I-Wq)t>#6JP%T literal 0 HcmV?d00001 diff --git a/test/examples/lotr.git/objects/14/78ebf7ad4dc6a06c76cdb4aca0eba7f78796aa b/test/examples/lotr.git/objects/14/78ebf7ad4dc6a06c76cdb4aca0eba7f78796aa new file mode 100644 index 0000000000000000000000000000000000000000..e9ffb99969c7339af742b2b627e418a65e9d924c GIT binary patch literal 195 zcmV;!06hPA0V^p=O;s?oG-NO|FfcPQQEUNfH&w4B zwW1_5CzavX^Y_6n3fj9IHCNveX5*bS{pOTZ69XVn@Xaqu$uDBydnH*t+4^R4v7m3{ x@h8(YN~Avjgc=m@mY-jeS_E>^n_EV#`yRR~tlGMKw?XkFHt)%O%>YcLOWk&|VRrxk literal 0 HcmV?d00001 diff --git a/test/examples/lotr.git/objects/1e/716a3178a76fe39ee7b88f0cf2dc4a447566f6 b/test/examples/lotr.git/objects/1e/716a3178a76fe39ee7b88f0cf2dc4a447566f6 new file mode 100644 index 0000000000000000000000000000000000000000..42fc78435f6f21a83129dfdcd6ec9100daa691b7 GIT binary patch literal 164 zcmV;V09*ff0iBLZ3IZ_@1zqP9eF3HO?F2+Tf(yZQCh7QrOiPUSch2DUQANEXy+0=y zYj$%m1L{Db79XnhMW>WXXq?d5#&Mxoy~)UwNWJsmbwX}z(7Ngnmuxg^YlCh!HgXBE zcwLu5t+LAB`H%ru>2MkRnX>M0JXRiXoYK!-UeXsi6zM0>hN2^FeS|#{qT1H&<=o)^ SeD&=4&M>#`NBsc5%t`zSeN<8a literal 0 HcmV?d00001 diff --git a/test/examples/lotr.git/objects/28/bb2f40d2e4c82a4ae62ef619a80a4b555e23ee b/test/examples/lotr.git/objects/28/bb2f40d2e4c82a4ae62ef619a80a4b555e23ee new file mode 100644 index 0000000000000000000000000000000000000000..3669331255811f4b3c9ba7223db33d50a5ea67a0 GIT binary patch literal 171 zcmV;c095~Y0iBLPYQr!P0DIOe_5%)*z1GSQLZ8q>A?KB}B1t1}kmdi^`9iM43{28m z?;XZz`RYvs98!>2h%@Ho+4@92<%pcvN@OY&Xz|SE#ZA@@(Pn4EGzOd(K`f;pzYDiS zXLC*ya!!KL@ZN9Q;8!dBG}*eY!&TZU4bENbch!g1sHdd$0&b*$-qY-0uw<<{=yBN( Z`Lo_U@9Q7zFW9sSY<(}q`~yOVPEXogSjqqZ literal 0 HcmV?d00001 diff --git a/test/examples/lotr.git/objects/2c/b9156ad383914561a8502fc70f5a1d887e48ad b/test/examples/lotr.git/objects/2c/b9156ad383914561a8502fc70f5a1d887e48ad new file mode 100644 index 0000000000000000000000000000000000000000..9d786ae31c1c1864fd91f1fa423f8c2493e2dcfd GIT binary patch literal 399 zcmV;A0dW3!0gaL|i`+mAg;V=i2(H)!_Pmhdij*4?av>?Q*^t7RL$+mGcsw$i@tOVi z(Rgh_x`3OJ-#mSKn#xH9PfzdPJiwVBV;{2YpCfR9*b_`D5j*i5B1j8YD;32T zsVa_T3FsR@7X(HeC;&oBONP@#sOW2}uwSoy6K&G<KW4fI@JXo>HA(i%w`{TW)W8)Tg*?liZQ47n zv3gX+)vp%Ig5xn6FFn`2p}4ihK1YK8&Q0U!(V~kcP|6NUrn?;=TA0C^mw1aHkte*C zjn-;&fLC$zNP7YoBRY!=>HOQUN7TAMZtLCFigWC33{#|yZkeTR?!Es0{K?K7*g0!& tGk#9}i$2Eb!|6mmUwGh&8pd3-JEhZUeMm3cyDH!QzxG|8{Q;Bt>+DyY%WMDu literal 0 HcmV?d00001 diff --git a/test/examples/lotr.git/objects/37/fcc52509fb09142cafccaada0252f3de81873c b/test/examples/lotr.git/objects/37/fcc52509fb09142cafccaada0252f3de81873c new file mode 100644 index 0000000000000000000000000000000000000000..88edefe55b7fe458e8beabcf79bfc13320112fc4 GIT binary patch literal 195 zcmV;!06hPA0V^p=O;s?oG-NO|FfcPQQEe>(?DaW5-R-VmJwJwPziF(P!WekV6*v;pdmd(*u#W?AS+4dDJA$qJ(H6Ho7sd^=; z6(yNDsSLlKzYlg%(B9>!x%!SU8}Fp)H>aeU7yyBSZ+=lqeh~xTE6M7~);F7r1$`rr xKbfvkBK7$v)S!5`{QQ#CB9N2b+%jU__s~^g)z;;^4T>kRc~9YF!db67`ac%NP!Cv765^Et{jSigD5tv+XNdLiAXnYCQ6DQ}s$x zD@rnRQW<_de;@3kpuNjcbM+lzHr`3oZ%#=yF#rMu-~6JK{2~UvSCZ9}t#39L3;ISL xe==R8MC$WTs6p{=`S~TOMIa}=xn;z<@1d*0s;$d+8x&7s^Pb$-3;=sLN{2e$TtWZ< literal 0 HcmV?d00001 diff --git a/test/examples/lotr.git/objects/4f/de706c7c8d3b30b6caec8c82ff4c01261350f2 b/test/examples/lotr.git/objects/4f/de706c7c8d3b30b6caec8c82ff4c01261350f2 new file mode 100644 index 00000000..78a9ea4e --- /dev/null +++ b/test/examples/lotr.git/objects/4f/de706c7c8d3b30b6caec8c82ff4c01261350f2 @@ -0,0 +1,3 @@ +xK +1]}ɯ{":iy +^̐vIِCɖBXBRy4Fim`,uՔs+p!tqӐvi䘥AZ9Yt9v^յ3F}ɆJ \ No newline at end of file diff --git a/test/examples/lotr.git/objects/71/4323c104239440a5c66ab12a67ed07a83c404f b/test/examples/lotr.git/objects/71/4323c104239440a5c66ab12a67ed07a83c404f new file mode 100644 index 0000000000000000000000000000000000000000..b003ac7ff853cb9f457515ce9f101ccebffbe17a GIT binary patch literal 9596 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 literal 0 HcmV?d00001 diff --git a/test/examples/lotr.git/objects/79/8f6564abb42d7ed34621d53595cbbe84638949 b/test/examples/lotr.git/objects/79/8f6564abb42d7ed34621d53595cbbe84638949 new file mode 100644 index 00000000..df9cf90a --- /dev/null +++ b/test/examples/lotr.git/objects/79/8f6564abb42d7ed34621d53595cbbe84638949 @@ -0,0 +1 @@ +xA@ 9ϯMO ı 8P8TrObe27G-WU}FfcPQQE;tH)%8!)4NfdA%FolwO<`c4713TAd+hg` zzuSsdAI#Wr=Gly2P_?O*sd`xj=?sO=$_H7Lr#LJ+VOOQhz*e z?Kp`<$`OIoL!#8PGxOfOH(M{QU(&PZFJC-*LT9%^pIW-)9K5TlcM^mcpXfWGUQNnD zBKelmT86{;IUasoRqu05L!e*#RbE+LIkM8;*BRk?373}T@H&wZmn0nR#HHMPJaCW^ zO5Pt5hIl#u!3XI``Q*FH(~K@y(3K-;!PX#s zQvxKJt|5S@kW(m6H8F&fu9rYLIHul*lr;G;qf2RUU?U+gEp;ib)Jf`$Hrb)c>l}Eg zr9X;Or>N7A(`fN`OuEb#=iwVv)L2@x8Nz_)!&0dY0Ib&XA^sLPVX4p^`; zxr^*(bPi%GfVSeP8xGghaF4E$7*@1a4X`!p$az=OhJzx6-z0&7{*8BH3aX|!wj&>m zPRJ(KVnti9<9>Ypv&Wx3}}#^Dk$#`&uk8{NkS?%T$IsZwp2N87$&xt$vO5 zO;8z+>Yc@4r7inD2Y{8}fjDjX%n0@e?QR$+ZM@B?FLN!fX<&PeQQ_Ume?zBXf_=6d zbzGzyD7T!=Ae$ijE5?WxT&4p9FhT@{%wmtmWRBmoXgPVmF^-S~f>t72~8QX4_Y^gy^wC)p+FRrs|cX zR+MDsq%!<^{yx}6L3@{@=IT4bY`l}E-<*!o$L)y`dG(~!U zOt9!qb1(yjR*JV?r?3|Q1bgZBwdFDGU+7*ldY*`(@Qj5==( z1L9U|GtD|hulXwjzNEwF;J+#R`J2bi1Flp0N0+DcESDnv2F8Zyw#|kFXC1Uwi>}ML VYF!db67`ac%NP!Cv765^Et{jSigD5tv+XNdLiAXnYCQ6DQ}s$x zD@rnRQW<_de;@3kpuNjcbM+lzHr`3oZ%#=yF#rMu-~6JK{33?Oj=|K]0f Gʀp SNh[~-nN}ނ-rL 0&YRiN_+8/%L|d0+,Vl=YGhu-G)A$ЩLrבR2ILaH?.R-+u+#FU_<3&Tկ۶/7u=GmWg.P +%]7`K{ O/7ppXߎ=6v+ŋ /n>O1x? fݎR3h+n}Dnoml \ No newline at end of file diff --git a/test/examples/lotr.git/objects/d9/e379fdea55b6ff3b71c110b3d2d7b55bbfd5ee b/test/examples/lotr.git/objects/d9/e379fdea55b6ff3b71c110b3d2d7b55bbfd5ee new file mode 100644 index 0000000000000000000000000000000000000000..721127b6e8e556175d4a3e413aa06033f79d2455 GIT binary patch literal 124 zcmV-?0E7Q{0V^p=O;s>7G-WU}FfcPQQE;tH)%8!)4NfdA%FolwO<~}BwM{G1fGuqc zr_HDH3#T3YcbBgasy4MURWGX`ouSZK`5=q(6o;k9vNmd^zhz%xMmanH literal 0 HcmV?d00001 diff --git a/test/examples/lotr.git/objects/e3/415337d9ae2c0b4b00054a93727f4a7d3c3ca5 b/test/examples/lotr.git/objects/e3/415337d9ae2c0b4b00054a93727f4a7d3c3ca5 new file mode 100644 index 0000000000000000000000000000000000000000..5f5e49e09c62f9c8836c3a26e38abb02700b022d GIT binary patch literal 124 zcmV-?0E7Q{0V^p=O;s>7G-WU}FfcPQQE;tH)%8!)4NfdA%FolwO<|avY$y~oo0t2( z>LG=+rl<4fhZa4Bs!gp-)ypbKXDD=5KFFdx#bN2Otc_afZ`oJaIQT=Al;o%6>y=cL eFmTA96a>^ literal 0 HcmV?d00001 diff --git a/test/examples/lotr.git/objects/f2/5eccd98e9b667f9e22946f3e2f945378b8a72d b/test/examples/lotr.git/objects/f2/5eccd98e9b667f9e22946f3e2f945378b8a72d new file mode 100644 index 00000000..8b7776d1 --- /dev/null +++ b/test/examples/lotr.git/objects/f2/5eccd98e9b667f9e22946f3e2f945378b8a72d @@ -0,0 +1,2 @@ +xKj0@))#{$@hd&,k|CiuK͞q#EDn<ҐmBjׅE!jQ +TZJl1uU;|٧n/ x?hZ]Y`@4'=/)zsmp<`.ϣ5,L \ No newline at end of file diff --git a/test/examples/lotr.git/objects/f4/46205ac9df5b6a40c00785f06827f4a4dbd727 b/test/examples/lotr.git/objects/f4/46205ac9df5b6a40c00785f06827f4a4dbd727 new file mode 100644 index 00000000..15bedfdd --- /dev/null +++ b/test/examples/lotr.git/objects/f4/46205ac9df5b6a40c00785f06827f4a4dbd727 @@ -0,0 +1 @@ +xKj0@))#i,KPJEk}fhd&8^`).9&AO#)5-КGM(,F"-E"By T,V=VW9x]xl
b

\n" + output = "

a b

\n" relative_image(content, output) end end test "image with float" do content = "a\n\n[[alpha.jpg|float]]\n\nb" - output = "

a

\n\n

\n\n

b

\n" + output = "

a

\n\n

\n\n

b

\n" relative_image(content, output) end test "image with float and align" do %w{left right}.each do |align| content = "a\n\n[[alpha.jpg|float|align=#{align}]]\n\nb" - output = "

a

\n\n

\n\n

b

\n" + output = "

a

\n\n

\n\n

b

\n" relative_image(content, output) end end test "image with frame" do content = "a\n\n[[alpha.jpg|frame]]\n\nb" - output = "

a

\n\n

\n\n

b

\n" + output = "

a

\n\n

\n\n

b

\n" relative_image(content, output) end test "image with frame and alt" do content = "a\n\n[[alpha.jpg|frame|alt=Alpha]]\n\nb" - output = "

a

\n\n

\"Alpha\"

Alpha

\n\n

b

\n" + output = "

a

\n\n

\"Alpha\"Alpha

\n\n

b

\n" relative_image(content, output) end diff --git a/test/test_page.rb b/test/test_page.rb index 45b19b91..b5dac678 100644 --- a/test/test_page.rb +++ b/test/test_page.rb @@ -28,7 +28,7 @@ context "Page" do test "page versions" do page = @wiki.page('Bilbo Baggins') - assert_equal ['5bc1aaec6149e854078f1d0f8b71933bbc6c2e43'], + assert_equal ["f25eccd98e9b667f9e22946f3e2f945378b8a72d", "5bc1aaec6149e854078f1d0f8b71933bbc6c2e43"], page.versions.map { |v| v.id } end diff --git a/test/test_wiki.rb b/test/test_wiki.rb index 8d3ceded..2bb913de 100644 --- a/test/test_wiki.rb +++ b/test/test_wiki.rb @@ -17,25 +17,27 @@ context "Wiki" do test "shows paginated log with no page" do Gollum::Wiki.per_page = 3 assert_equal %w( - f01428b3138994aab19d5f880b6f37336ddf1f24 - fbabba862dfa7ac35b39042dd4ad780c9f67b8cb - df26e61e707116f81ebc6b935ec6d1676b7e96c4), + 4fde706c7c8d3b30b6caec8c82ff4c01261350f2 + 1e716a3178a76fe39ee7b88f0cf2dc4a447566f6 + afe2034d400ba21e13361f38f74900c51dbc7fde), @wiki.log.map { |c| c.id } end test "shows paginated log with 1st page" do Gollum::Wiki.per_page = 3 assert_equal %w( - f01428b3138994aab19d5f880b6f37336ddf1f24 - fbabba862dfa7ac35b39042dd4ad780c9f67b8cb - df26e61e707116f81ebc6b935ec6d1676b7e96c4), + 4fde706c7c8d3b30b6caec8c82ff4c01261350f2 + 1e716a3178a76fe39ee7b88f0cf2dc4a447566f6 + afe2034d400ba21e13361f38f74900c51dbc7fde), @wiki.log(:page => 1).map { |c| c.id } end test "shows paginated log with next page" do Gollum::Wiki.per_page = 3 assert_equal %w( - 5bc1aaec6149e854078f1d0f8b71933bbc6c2e43), + f25eccd98e9b667f9e22946f3e2f945378b8a72d + b0d108328459e44fff4a76cd19b10ddc34adce4b + f01428b3138994aab19d5f880b6f37336ddf1f24), @wiki.log(:page => 2).map { |c| c.id } end end From 0485c67b3d460b33264db4c25c23efe7d484d9b2 Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Wed, 7 Jul 2010 13:49:55 -0700 Subject: [PATCH 02/17] Distinguish between present and absent page links. --- lib/gollum/frontend/public/css/global.css | 6 +++++- lib/gollum/markup.rb | 8 ++++++-- test/test_markup.rb | 10 +++++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/gollum/frontend/public/css/global.css b/lib/gollum/frontend/public/css/global.css index f9e98c50..9a4b256a 100644 --- a/lib/gollum/frontend/public/css/global.css +++ b/lib/gollum/frontend/public/css/global.css @@ -40,7 +40,11 @@ p { color: #666; } -/***********************/ +a.absent { + color: #a00; +} + +/* Images */ .frame { margin: 1em 0; diff --git a/lib/gollum/markup.rb b/lib/gollum/markup.rb index d1a7010b..316c3112 100644 --- a/lib/gollum/markup.rb +++ b/lib/gollum/markup.rb @@ -41,7 +41,7 @@ module Gollum # # Returns the placeholder'd String data. def extract_tags(data) - data.gsub(/\[\[(.+?)\]\]/) do + data.gsub(/\[\[(.+?)\]\]/m) do id = Digest::SHA1.hexdigest($1) @tagmap[id] = $1 id @@ -192,7 +192,11 @@ module Gollum parts = tag.split('|') name = parts[0].strip cname = Page.cname((parts[1] || parts[0]).strip) - %{#{name}} + if @wiki.page(cname) + %{#{name}} + else + %{#{name}} + end end # Find the given file in the repo. diff --git a/test/test_markup.rb b/test/test_markup.rb index 1f0d595c..c0ea7323 100644 --- a/test/test_markup.rb +++ b/test/test_markup.rb @@ -21,7 +21,15 @@ context "Markup" do page = @wiki.page("Bilbo Baggins") output = Gollum::Markup.new(page).render - assert_equal %{

a Bilbo Baggins b

\n}, output + assert_equal %{

a Bilbo Baggins b

\n}, output + end + + test "absent page link" do + @wiki.write_page("Tolkien", :markdown, "a [[J. R. R. Tolkien]]'s b", @commit) + + page = @wiki.page("Tolkien") + output = Gollum::Markup.new(page).render + assert_equal %{

a J. R. R. Tolkien's b

\n}, output end test "image with absolute path" do From 6c7fcf89c38a0baf2ec0b17af92fd292f6de72c1 Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Wed, 7 Jul 2010 16:02:26 -0700 Subject: [PATCH 03/17] Add create/edit powers to frontend. Support external image URLs. --- lib/gollum/frontend/app.rb | 38 ++++++++++++++++++- lib/gollum/frontend/public/css/global.css | 13 +++++++ lib/gollum/frontend/templates/create.mustache | 13 +++++++ lib/gollum/frontend/templates/edit.mustache | 10 +++++ lib/gollum/frontend/templates/layout.mustache | 3 ++ lib/gollum/frontend/views/create.rb | 11 ++++++ lib/gollum/frontend/views/edit.rb | 11 ++++++ lib/gollum/frontend/views/layout.rb | 2 + lib/gollum/markup.rb | 9 ++++- test/test_markup.rb | 10 +++++ 10 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 lib/gollum/frontend/templates/create.mustache create mode 100644 lib/gollum/frontend/templates/edit.mustache create mode 100644 lib/gollum/frontend/views/create.rb create mode 100644 lib/gollum/frontend/views/edit.rb diff --git a/lib/gollum/frontend/app.rb b/lib/gollum/frontend/app.rb index e7044548..3757a470 100644 --- a/lib/gollum/frontend/app.rb +++ b/lib/gollum/frontend/app.rb @@ -6,7 +6,7 @@ require 'mustache/sinatra' require 'gollum/frontend/views/layout' -$path = "~/dev/mojombo/gollum/test/examples/lotr.git" +$path = "~/dev/sandbox/lotr2" module Precious class App < Sinatra::Base @@ -41,6 +41,38 @@ module Precious show_page_or_file('Home') end + get '/edit/:name' do + @name = params[:name] + wiki = Gollum::Wiki.new($path) + if page = wiki.page(@name) + @content = page.raw_data + mustache :edit + else + mustache :create + end + end + + post '/edit/:name' do + name = params[:name] + wiki = Gollum::Wiki.new($path) + page = wiki.page(name) + commit = { :message => 'commit message', + :name => 'Tom Preston-Werner', + :email => 'tom@github.com' } + wiki.update_page(page, params[:content], commit) + redirect "/#{name}" + end + + post '/create/:page' do + page = params[:page] + wiki = Gollum::Wiki.new($path) + commit = { :message => 'commit message', + :name => 'Tom Preston-Werner', + :email => 'tom@github.com' } + wiki.write_page(page, :markdown, params[:content], commit) + redirect "/#{page}" + end + get '/*' do show_page_or_file(params[:splat].first) end @@ -48,12 +80,14 @@ module Precious def show_page_or_file(name) wiki = Gollum::Wiki.new($path) if page = wiki.page(name) + @name = name @content = page.formatted_data mustache :page elsif file = wiki.file(name) file.raw_data else - halt 404 + @name = name + mustache :create end end end diff --git a/lib/gollum/frontend/public/css/global.css b/lib/gollum/frontend/public/css/global.css index 9a4b256a..54706a1d 100644 --- a/lib/gollum/frontend/public/css/global.css +++ b/lib/gollum/frontend/public/css/global.css @@ -34,6 +34,12 @@ p { line-height: 22pt; } +#nav { + width: 60em; + margin: 0 auto; + color: #666; +} + #content { width: 60em; margin: 0 auto; @@ -44,6 +50,13 @@ a.absent { color: #a00; } +/* Forms */ + +textarea { + width: 100%; + height: 20em; +} + /* Images */ .frame { diff --git a/lib/gollum/frontend/templates/create.mustache b/lib/gollum/frontend/templates/create.mustache new file mode 100644 index 00000000..1678ccff --- /dev/null +++ b/lib/gollum/frontend/templates/create.mustache @@ -0,0 +1,13 @@ +

Create a new page

+ +
+
+ +
+
+ +
+
+ +
+
\ No newline at end of file diff --git a/lib/gollum/frontend/templates/edit.mustache b/lib/gollum/frontend/templates/edit.mustache new file mode 100644 index 00000000..d3f942ea --- /dev/null +++ b/lib/gollum/frontend/templates/edit.mustache @@ -0,0 +1,10 @@ +

Editing {{name}}

+ +
+
+ +
+
+ +
+
\ No newline at end of file diff --git a/lib/gollum/frontend/templates/layout.mustache b/lib/gollum/frontend/templates/layout.mustache index 5d3ad456..2c4b82ba 100644 --- a/lib/gollum/frontend/templates/layout.mustache +++ b/lib/gollum/frontend/templates/layout.mustache @@ -8,6 +8,9 @@ +
{{{yield}}}
diff --git a/lib/gollum/frontend/views/create.rb b/lib/gollum/frontend/views/create.rb new file mode 100644 index 00000000..30417379 --- /dev/null +++ b/lib/gollum/frontend/views/create.rb @@ -0,0 +1,11 @@ +module Precious + module Views + class Create < Layout + attr_reader :page + + def title + "Create a new page" + end + end + end +end diff --git a/lib/gollum/frontend/views/edit.rb b/lib/gollum/frontend/views/edit.rb new file mode 100644 index 00000000..01153767 --- /dev/null +++ b/lib/gollum/frontend/views/edit.rb @@ -0,0 +1,11 @@ +module Precious + module Views + class Edit < Layout + attr_reader :page, :content + + def title + "Edit" + end + end + end +end diff --git a/lib/gollum/frontend/views/layout.rb b/lib/gollum/frontend/views/layout.rb index ae53aa24..4fba39c3 100644 --- a/lib/gollum/frontend/views/layout.rb +++ b/lib/gollum/frontend/views/layout.rb @@ -4,6 +4,8 @@ module Precious include Rack::Utils alias_method :h, :escape_html + attr_reader :name + def title "Home" end diff --git a/lib/gollum/markup.rb b/lib/gollum/markup.rb index 316c3112..e8802a70 100644 --- a/lib/gollum/markup.rb +++ b/lib/gollum/markup.rb @@ -85,8 +85,15 @@ module Gollum def process_image_tag(tag) parts = tag.split('|') name = parts[0].strip + path = nil if file = find_file(name) + path = "/#{file.path}" + elsif name =~ /^https?:\/\/.+(jpg|png|gif|svg|bmp)$/ + path = name + end + + if path opts = parse_image_tag_options(tag) containered = false @@ -143,7 +150,7 @@ module Gollum %{} + %{} else - %{} + %{} end end end diff --git a/test/test_markup.rb b/test/test_markup.rb index c0ea7323..e7c023e3 100644 --- a/test/test_markup.rb +++ b/test/test_markup.rb @@ -32,6 +32,16 @@ context "Markup" do assert_equal %{

a J. R. R. Tolkien's b

\n}, output end + test "image with http url" do + ['http', 'https'].each do |scheme| + @wiki.write_page("Bilbo Baggins", :markdown, "a [[#{scheme}://example.com/bilbo.jpg]] b", @commit) + + page = @wiki.page("Bilbo Baggins") + output = Gollum::Markup.new(page).render + assert_equal %{

a b

\n}, output + end + end + test "image with absolute path" do index = @wiki.repo.index index.add("alpha.jpg", "hi") From f3cbbb865239b39769c531b5667a3d58e6579cde Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Wed, 7 Jul 2010 17:33:04 -0700 Subject: [PATCH 04/17] Handle stupid 0x0D bytes because browsers are stupid. --- lib/gollum/markup.rb | 2 +- lib/gollum/wiki.rb | 13 +++++++++++-- test/test_markup.rb | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/gollum/markup.rb b/lib/gollum/markup.rb index e8802a70..ba2f73d8 100644 --- a/lib/gollum/markup.rb +++ b/lib/gollum/markup.rb @@ -232,7 +232,7 @@ module Gollum # # Returns the placeholder'd String data. def extract_code(data) - data.gsub(/^``` ?(.+)\n(.+)\n```$/m) do + data.gsub(/^``` ?(.+?)\r?\n(.+?)\r?\n```\r?$/m) do id = Digest::SHA1.hexdigest($2) @codemap[id] = { :lang => $1, :code => $2 } id diff --git a/lib/gollum/wiki.rb b/lib/gollum/wiki.rb index 4423e189..2eb893e1 100644 --- a/lib/gollum/wiki.rb +++ b/lib/gollum/wiki.rb @@ -67,7 +67,7 @@ module Gollum if pcommit = @repo.commit('master') map = tree_map(pcommit.tree) end - map[path] = data + map[path] = normalize(data) index = tree_map_to_index(map) parents = pcommit ? [pcommit] : [] @@ -90,7 +90,7 @@ module Gollum pcommit = @repo.commit('master') map = tree_map(pcommit.tree) index = tree_map_to_index(map) - index.add(page.path, data) + index.add(page.path, normalize(data)) actor = Grit::Actor.new(commit[:name], commit[:email]) index.commit(commit[:message], [pcommit], actor) @@ -160,6 +160,15 @@ module Gollum # Returns the String path. attr_reader :path + # Normalize the data. + # + # data - The String data to be normalized. + # + # Returns the normalized data String. + def normalize(data) + data.gsub(/\r/, '') + end + # Fill an array with a list of pages. # # tree - The Grit::Tree to start with. diff --git a/test/test_markup.rb b/test/test_markup.rb index e7c023e3..41b00e30 100644 --- a/test/test_markup.rb +++ b/test/test_markup.rb @@ -167,6 +167,21 @@ context "Markup" do assert_equal output, rendered end + test "code blocks with carriage returns" do + content = "a\r\n\r\n```ruby\r\nx = 1\r\n```\r\n\r\nb" + output = "

a

\n\n

" +
+             "x = " +
+             "1\n
\n

\n\n

b

\n" + + index = @wiki.repo.index + index.add("Bilbo-Baggins.md", content) + index.commit("Add alpha.jpg") + + page = @wiki.page("Bilbo Baggins") + rendered = Gollum::Markup.new(page).render + assert_equal output, rendered + end + def relative_image(content, output) index = @wiki.repo.index index.add("greek/alpha.jpg", "hi") From 3ceae59524d01b9673079c2fba54d170893a00fd Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Thu, 8 Jul 2010 13:55:43 -0700 Subject: [PATCH 05/17] Better code styling for frontend. --- lib/gollum/frontend/public/css/global.css | 13 ++++ lib/gollum/frontend/public/css/syntax.css | 60 +++++++++++++++++++ lib/gollum/frontend/templates/layout.mustache | 1 + 3 files changed, 74 insertions(+) create mode 100644 lib/gollum/frontend/public/css/syntax.css diff --git a/lib/gollum/frontend/public/css/global.css b/lib/gollum/frontend/public/css/global.css index 54706a1d..ad11ea44 100644 --- a/lib/gollum/frontend/public/css/global.css +++ b/lib/gollum/frontend/public/css/global.css @@ -34,6 +34,19 @@ p { line-height: 22pt; } +.highlight { + border: 1px solid #eee; + padding: 0; + margin: 0; + font-size: 12pt; +} + +.highlight pre { + background-color: #f8f8ff; + margin: 0; + padding: .5em; +} + #nav { width: 60em; margin: 0 auto; diff --git a/lib/gollum/frontend/public/css/syntax.css b/lib/gollum/frontend/public/css/syntax.css new file mode 100644 index 00000000..2774b764 --- /dev/null +++ b/lib/gollum/frontend/public/css/syntax.css @@ -0,0 +1,60 @@ +.highlight { background: #ffffff; } +.highlight .c { color: #999988; font-style: italic } /* Comment */ +.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.highlight .k { font-weight: bold } /* Keyword */ +.highlight .o { font-weight: bold } /* Operator */ +.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ +.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ +.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #aa0000 } /* Generic.Error */ +.highlight .gh { color: #999999 } /* Generic.Heading */ +.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ +.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #555555 } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #aaaaaa } /* Generic.Subheading */ +.highlight .gt { color: #aa0000 } /* Generic.Traceback */ +.highlight .kc { font-weight: bold } /* Keyword.Constant */ +.highlight .kd { font-weight: bold } /* Keyword.Declaration */ +.highlight .kp { font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #009999 } /* Literal.Number */ +.highlight .s { color: #d14 } /* Literal.String */ +.highlight .na { color: #008080 } /* Name.Attribute */ +.highlight .nb { color: #0086B3 } /* Name.Builtin */ +.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ +.highlight .no { color: #008080 } /* Name.Constant */ +.highlight .ni { color: #800080 } /* Name.Entity */ +.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ +.highlight .nn { color: #555555 } /* Name.Namespace */ +.highlight .nt { color: #000080 } /* Name.Tag */ +.highlight .nv { color: #008080 } /* Name.Variable */ +.highlight .ow { font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #009999 } /* Literal.Number.Float */ +.highlight .mh { color: #009999 } /* Literal.Number.Hex */ +.highlight .mi { color: #009999 } /* Literal.Number.Integer */ +.highlight .mo { color: #009999 } /* Literal.Number.Oct */ +.highlight .sb { color: #d14 } /* Literal.String.Backtick */ +.highlight .sc { color: #d14 } /* Literal.String.Char */ +.highlight .sd { color: #d14 } /* Literal.String.Doc */ +.highlight .s2 { color: #d14 } /* Literal.String.Double */ +.highlight .se { color: #d14 } /* Literal.String.Escape */ +.highlight .sh { color: #d14 } /* Literal.String.Heredoc */ +.highlight .si { color: #d14 } /* Literal.String.Interpol */ +.highlight .sx { color: #d14 } /* Literal.String.Other */ +.highlight .sr { color: #009926 } /* Literal.String.Regex */ +.highlight .s1 { color: #d14 } /* Literal.String.Single */ +.highlight .ss { color: #990073 } /* Literal.String.Symbol */ +.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #008080 } /* Name.Variable.Class */ +.highlight .vg { color: #008080 } /* Name.Variable.Global */ +.highlight .vi { color: #008080 } /* Name.Variable.Instance */ +.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ diff --git a/lib/gollum/frontend/templates/layout.mustache b/lib/gollum/frontend/templates/layout.mustache index 2c4b82ba..59ae7b3a 100644 --- a/lib/gollum/frontend/templates/layout.mustache +++ b/lib/gollum/frontend/templates/layout.mustache @@ -5,6 +5,7 @@ Gollum - {{title}} + From 5f7685d5fde79a76b86514da4f3646b957eb4bf2 Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Thu, 8 Jul 2010 18:05:20 -0700 Subject: [PATCH 06/17] Sanitize HTML output. --- gollum.gemspec | 1 + lib/gollum.rb | 42 +++++++++++++++++++++++++++++++++++++++++- lib/gollum/markup.rb | 17 +++++++---------- test/test_markup.rb | 40 ++++++++++++++++++++-------------------- 4 files changed, 69 insertions(+), 31 deletions(-) diff --git a/gollum.gemspec b/gollum.gemspec index 2071a8fa..08022da7 100644 --- a/gollum.gemspec +++ b/gollum.gemspec @@ -28,6 +28,7 @@ Gem::Specification.new do |s| s.add_dependency('albino', "~> 1.0.0") s.add_dependency('sinatra', "~> 1.0.0") s.add_dependency('mustache', [">= 0.11.2", "< 1.0.0"]) + s.add_dependency('sanitize', "~> 1.0.0") s.add_development_dependency('shoulda') s.add_development_dependency('mocha') diff --git a/lib/gollum.rb b/lib/gollum.rb index 77064832..390b778e 100644 --- a/lib/gollum.rb +++ b/lib/gollum.rb @@ -1,6 +1,7 @@ # external require 'grit' require 'github/markup' +require 'sanitize' # internal require 'gollum/pagination' @@ -12,4 +13,43 @@ require 'gollum/albino' module Gollum VERSION = '0.0.1' -end \ No newline at end of file + + SANITIZATION_OPTIONS = { + :elements => [ + 'a', 'abbr', 'acronym', 'address', 'area', 'b', 'big', + 'blockquote', 'br', 'button', 'caption', 'center', 'cite', + 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir', + 'div', 'dl', 'dt', 'em', 'fieldset', 'font', 'form', 'h1', + 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'input', + 'ins', 'kbd', 'label', 'legend', 'li', 'map', 'menu', + 'ol', 'optgroup', 'option', 'p', 'pre', 'q', 's', 'samp', + 'select', 'small', 'span', 'strike', 'strong', 'sub', + 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', + 'thead', 'tr', 'tt', 'u', 'ul', 'var' + ], + :attributes => { + :all => ['abbr', 'accept', 'accept-charset', + 'accesskey', 'action', 'align', 'alt', 'axis', + 'border', 'cellpadding', 'cellspacing', 'char', + 'charoff', 'charset', 'checked', 'cite', + 'class', 'clear', 'cols', 'colspan', 'color', + 'compact', 'coords', 'datetime', 'dir', + 'disabled', 'enctype', 'for', 'frame', + 'headers', 'height', 'href', 'hreflang', + 'hspace', 'id', 'ismap', 'label', 'lang', + 'longdesc', 'maxlength', 'media', 'method', + 'multiple', 'name', 'nohref', 'noshade', + 'nowrap', 'prompt', 'readonly', 'rel', 'rev', + 'rows', 'rowspan', 'rules', 'scope', + 'selected', 'shape', 'size', 'span', 'src', + 'start', 'summary', 'tabindex', 'target', + 'title', 'type', 'usemap', 'valign', 'value', + 'vspace', 'width'] + }, + :protocols => { + 'a' => {'href' => ['http', 'https', 'mailto', :relative]}, + 'img' => {'href' => ['http', 'https', :relative]} + } + } +end + diff --git a/lib/gollum/markup.rb b/lib/gollum/markup.rb index ba2f73d8..d258c8c5 100644 --- a/lib/gollum/markup.rb +++ b/lib/gollum/markup.rb @@ -27,6 +27,9 @@ module Gollum data = GitHub::Markup.render(@name, data) rescue '' data = process_tags(data) data = process_code(data) + data = Sanitize.clean(data, SANITIZATION_OPTIONS) + data = data.gsub(/

<\/p>/, '') + data end ######################################################################### @@ -100,7 +103,6 @@ module Gollum classes = [] # applied to whatever the outermost container is attrs = [] # applied to the image - styles = [] # applied to the image align = opts['align'] if opts['float'] @@ -120,13 +122,13 @@ module Gollum if width = opts['width'] if width =~ /^\d+(\.\d+)?(em|px)$/ - styles << "max-width: #{width};" + attrs << %{width="#{width}"} end end if height = opts['height'] if height =~ /^\d+(\.\d+)?(em|px)$/ - styles << "max-height: #{height};" + attrs << %{height="#{height}"} end end @@ -136,21 +138,16 @@ module Gollum attr_string = attrs.size > 0 ? attrs.join(' ') + ' ' : '' - style_string = '' - unless styles.empty? - style_string = %{ style="#{styles.join(' ')}"} - end - if opts['frame'] || containered classes << 'frame' if opts['frame'] %{} + %{} + - %{} + + %{} + (alt ? %{#{alt}} : '') + %{} + %{} else - %{} + %{} end end end diff --git a/test/test_markup.rb b/test/test_markup.rb index 41b00e30..316668c4 100644 --- a/test/test_markup.rb +++ b/test/test_markup.rb @@ -21,7 +21,7 @@ context "Markup" do page = @wiki.page("Bilbo Baggins") output = Gollum::Markup.new(page).render - assert_equal %{

a Bilbo Baggins b

\n}, output + assert_equal %{

a Bilbo Baggins b

}, output end test "absent page link" do @@ -29,7 +29,7 @@ context "Markup" do page = @wiki.page("Tolkien") output = Gollum::Markup.new(page).render - assert_equal %{

a J. R. R. Tolkien's b

\n}, output + assert_equal %{

a J. R. R. Tolkien's b

}, output end test "image with http url" do @@ -38,7 +38,7 @@ context "Markup" do page = @wiki.page("Bilbo Baggins") output = Gollum::Markup.new(page).render - assert_equal %{

a b

\n}, output + assert_equal %{

a b

}, output end end @@ -50,7 +50,7 @@ context "Markup" do page = @wiki.page("Bilbo Baggins") output = Gollum::Markup.new(page).render - assert_equal %{

a b

\n}, output + assert_equal %{

a b

}, output end test "image with relative path" do @@ -61,12 +61,12 @@ context "Markup" do page = @wiki.page("Bilbo Baggins") output = Gollum::Markup.new(page).render - assert_equal %{

a b

\n}, output + assert_equal %{

a b

}, output end test "image with alt" do content = "a [[alpha.jpg|alt=Alpha Dog]] b" - output = %{

a Alpha Dog b

\n} + output = %{

a Alpha Dog b

} relative_image(content, output) end @@ -74,7 +74,7 @@ context "Markup" do %w{em px}.each do |unit| %w{width height}.each do |dim| content = "a [[alpha.jpg|#{dim}=100#{unit}]] b" - output = "

a b

\n" + output = "

a b

" relative_image(content, output) end end @@ -83,7 +83,7 @@ context "Markup" do test "image with bogus dimension" do %w{width height}.each do |dim| content = "a [[alpha.jpg|#{dim}=100]] b" - output = "

a b

\n" + output = "

a b

" relative_image(content, output) end end @@ -91,7 +91,7 @@ context "Markup" do test "image with vertical align" do %w{top texttop middle absmiddle bottom absbottom baseline}.each do |align| content = "a [[alpha.jpg|align=#{align}]] b" - output = "

a b

\n" + output = "

a b

" relative_image(content, output) end end @@ -99,34 +99,34 @@ context "Markup" do test "image with horizontal align" do %w{left center right}.each do |align| content = "a [[alpha.jpg|align=#{align}]] b" - output = "

a b

\n" + output = "

a b

" relative_image(content, output) end end test "image with float" do content = "a\n\n[[alpha.jpg|float]]\n\nb" - output = "

a

\n\n

\n\n

b

\n" + output = "

a

\n\n

\n\n

b

" relative_image(content, output) end test "image with float and align" do %w{left right}.each do |align| content = "a\n\n[[alpha.jpg|float|align=#{align}]]\n\nb" - output = "

a

\n\n

\n\n

b

\n" + output = "

a

\n\n

\n\n

b

" relative_image(content, output) end end test "image with frame" do content = "a\n\n[[alpha.jpg|frame]]\n\nb" - output = "

a

\n\n

\n\n

b

\n" + output = "

a

\n\n

\n\n

b

" relative_image(content, output) end test "image with frame and alt" do content = "a\n\n[[alpha.jpg|frame|alt=Alpha]]\n\nb" - output = "

a

\n\n

\"Alpha\"Alpha

\n\n

b

\n" + output = "

a

\n\n

\"Alpha\"Alpha

\n\n

b

" relative_image(content, output) end @@ -138,7 +138,7 @@ context "Markup" do page = @wiki.page("Bilbo Baggins") output = Gollum::Markup.new(page).render - assert_equal %{

a Alpha b

\n}, output + assert_equal %{

a Alpha b

}, output end test "file link with relative path" do @@ -149,14 +149,14 @@ context "Markup" do page = @wiki.page("Bilbo Baggins") output = Gollum::Markup.new(page).render - assert_equal %{

a Alpha b

\n}, output + assert_equal %{

a Alpha b

}, output end test "code blocks" do content = "a\n\n```ruby\nx = 1\n```\n\nb" - output = "

a

\n\n

" +
+    output = "

a

\n\n
" +
              "x = " +
-             "1\n
\n

\n\n

b

\n" + "1\n
\n
\n\n

b

" index = @wiki.repo.index index.add("Bilbo-Baggins.md", content) @@ -169,9 +169,9 @@ context "Markup" do test "code blocks with carriage returns" do content = "a\r\n\r\n```ruby\r\nx = 1\r\n```\r\n\r\nb" - output = "

a

\n\n

" +
+    output = "

a

\n\n
" +
              "x = " +
-             "1\n
\n

\n\n

b

\n" + "1\n
\n
\n\n

b

" index = @wiki.repo.index index.add("Bilbo-Baggins.md", content) From 9e3a307aa8ded6683d71626626d7735d6965ddb8 Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Thu, 8 Jul 2010 18:22:41 -0700 Subject: [PATCH 07/17] Small Readme clarification. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0c53eb79..fa89535e 100644 --- a/README.md +++ b/README.md @@ -69,10 +69,10 @@ or JavaScript. These tags will be stripped from the converted HTML. To link to another Gollum wiki page, use the Gollum Page Link Tag. - [[Frodo]] + [[Frodo Baggins]] The above tag will create a link to the corresponding page file named -`Frodo.ext` where `ext` may be any of the allowed extension types. The +`Frodo-Baggins.ext` where `ext` may be any of the allowed extension types. The conversion is as follows: 1. Replace any spaces (U+0020) with dashes (U+002D) From 2c2bf68a3bb628b85756f2f1d0336e92a5330d22 Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Thu, 8 Jul 2010 19:04:36 -0700 Subject: [PATCH 08/17] Escape lisp-quoted wiki links. --- lib/gollum/markup.rb | 12 ++++++++---- test/test_markup.rb | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/lib/gollum/markup.rb b/lib/gollum/markup.rb index d258c8c5..72eccfb4 100644 --- a/lib/gollum/markup.rb +++ b/lib/gollum/markup.rb @@ -44,10 +44,14 @@ module Gollum # # Returns the placeholder'd String data. def extract_tags(data) - data.gsub(/\[\[(.+?)\]\]/m) do - id = Digest::SHA1.hexdigest($1) - @tagmap[id] = $1 - id + data.gsub(/(.?)\[\[(.+?)\]\](.?)/m) do + if $1 == "'" && $3 != "'" + "[[#{$2}]]#{$3}" + else + id = Digest::SHA1.hexdigest($2) + @tagmap[id] = $2 + "#{$1}#{id}#{$3}" + end end end diff --git a/test/test_markup.rb b/test/test_markup.rb index 316668c4..d14a5d9a 100644 --- a/test/test_markup.rb +++ b/test/test_markup.rb @@ -182,6 +182,28 @@ context "Markup" do assert_equal output, rendered end + test "escaped wiki link" do + content = "a '[[Foo]], b" + output = "

a [[Foo]], b

" + compare(content, output) + end + + test "quoted wiki link" do + content = "a '[[Foo]]', b" + output = "

a 'Foo', b

" + compare(content, output) + end + + def compare(content, output) + index = @wiki.repo.index + index.add("Bilbo-Baggins.md", content) + index.commit("Add alpha.jpg") + + page = @wiki.page("Bilbo Baggins") + rendered = Gollum::Markup.new(page).render + assert_equal output, rendered + end + def relative_image(content, output) index = @wiki.repo.index index.add("greek/alpha.jpg", "hi") From 752a544f394ca29b124b727aa4b6b8bfb5be7794 Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Thu, 8 Jul 2010 19:25:35 -0700 Subject: [PATCH 09/17] Extract code before tags. --- lib/gollum/markup.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gollum/markup.rb b/lib/gollum/markup.rb index 72eccfb4..63529de5 100644 --- a/lib/gollum/markup.rb +++ b/lib/gollum/markup.rb @@ -22,8 +22,8 @@ module Gollum # # Returns the formatted String content. def render - data = extract_tags(@data) - data = extract_code(data) + data = extract_code(@data) + data = extract_tags(data) data = GitHub::Markup.render(@name, data) rescue '' data = process_tags(data) data = process_code(data) From 9b98a81f2a06cef249e43af12615e747a7e4f994 Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Fri, 9 Jul 2010 15:01:34 -0700 Subject: [PATCH 10/17] Switch to GitHub styles. --- lib/gollum/frontend/public/css/gollum.css | 55 +++ lib/gollum/frontend/public/css/screen.css | 345 ++++++++++++++++++ lib/gollum/frontend/templates/create.mustache | 29 +- lib/gollum/frontend/templates/edit.mustache | 22 +- lib/gollum/frontend/templates/layout.mustache | 14 +- lib/gollum/frontend/templates/page.mustache | 11 +- 6 files changed, 448 insertions(+), 28 deletions(-) create mode 100644 lib/gollum/frontend/public/css/gollum.css create mode 100644 lib/gollum/frontend/public/css/screen.css diff --git a/lib/gollum/frontend/public/css/gollum.css b/lib/gollum/frontend/public/css/gollum.css new file mode 100644 index 00000000..e594530e --- /dev/null +++ b/lib/gollum/frontend/public/css/gollum.css @@ -0,0 +1,55 @@ +a.absent { + color: #a00; +} + +/* Images */ + +.frame { + margin: 0; + display: inline-block; +} + +.frame img { + display: block; +} + +.frame > span { + display: block; + border: 1px solid #aaa; + padding: 4px; +} + +.frame span span { + display: block; + font-size: 10pt; + margin: 0; + padding: 4px 0 2px 0; + text-align: center; + line-height: 10pt; + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +.float-left { + float: left; + padding: .5em 1em .25em 0; +} + +.float-right { + float: right; + padding: .5em 0 .25em 1em; +} + +.align-left { + display: block; + text-align: left; +} + +.align-center { + display: block; + text-align: center; +} + +.align-right { + display: block; + text-align: right; +} \ No newline at end of file diff --git a/lib/gollum/frontend/public/css/screen.css b/lib/gollum/frontend/public/css/screen.css new file mode 100644 index 00000000..dd9dd232 --- /dev/null +++ b/lib/gollum/frontend/public/css/screen.css @@ -0,0 +1,345 @@ +/****************************************************************************/ +/* Base +/****************************************************************************/ + +* { + margin: 0; + padding: 0; +} + +html, body { + height: 100%; + color: black; +} + +body { + background-color: white; + font: 13.34px helvetica, arial, freesans, clean, sans-serif; + *font-size: small; +} + +table { + font-size: inherit; + font: 100%; +} + +select, input[type=text], input[type=password], input[type=image], textarea { + font: 99% helvetica, arial, freesans, sans-serif; +} +select, option { + padding: 0 .25em; +} +optgroup { + margin-top: .5em; +} + +input.text { + padding: 1px 0; +} +pre, code { + font: 12px Monaco, "Courier New", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", monospace; +} + +body * { + line-height: 1.4em; +} + +p{ margin:1em 0; } + +img { + border: 0; +} + +abbr { + border-bottom: none; +} + +.clearfix:after { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; +} +* html .clearfix {height: 1%;} +.clearfix {display:inline-block;} +.clearfix {display: block;} + +/* always show vertical scroll bar to prevent page jitter */ +html {overflow-y: scroll;} + +.site { + margin: 2em auto 0 auto; + width: 920px; + padding: 0 15px; +} + +/****************************************************************************/ +/* Guides +/****************************************************************************/ + +#guides { + +} + + /* index */ + + #guides .index { + + } + + #guides h1 { + margin-bottom: .5em; + } + + #guides .index ul { + list-style-type: none; + font-size: 120%; + } + + #guides .index ul li { + padding-left: 1.5em; + background: white url(/images/modules/guides/book.png) no-repeat; + } + + #guides .index .new { + margin-top: 1em; + border-top: 1px solid #ccc; + padding-top: .5em; + } + + #guides .index .new ul li { + background: white url(/images/modules/guides/book_add.png) no-repeat; + } + + #guides .index .new ul li a { + color: #c00; + } + + #guides .write .delete_page { + float: right; + } + + /* guide */ + + #guides .guide { + overflow: hidden; + } + + /* main */ + + #guides .guide .main { + float: left; + width: 50em; + } + + /* sidebar */ + + #guides .guide .sidebar { + float: right; + width: 15em; + border-left: 4px solid #e6e6e6; + margin: 2.1em 0 0 0; + padding-left: 1em; + } + + #guides .guide .sidebar h3 { + margin: 0 0 .5em 0; + } + + #guides .guide .sidebar ul { + list-style-type: none; + margin: 0; + color: #888; + + } + + #guides .guide .sidebar ul li { + padding-left: 12px; + background: white url(/images/modules/guides/sidebar/bullet_blue.png) -4px 0 no-repeat; + margin: .2em 0; + } + + /* admin */ + + #guides .admin { + clear: both; + margin-top: 3em; + border-top: 4px solid #e6e6e6; + padding-top: .3em; + overflow: hidden; + } + + /* write */ + + #guides .write { + + } + + #guides .write label { + font-size: 110%; + color: #666; + display: block; + margin: 1em 0; + } + + #guides .write input.text, + #guides .write textarea { + padding: 5px; + border: 1px solid #888; + } + + #guides .write input.text { + width: 40em; + } + + #guides .write textarea { + width: 100%; + height: 25em; + } + + #guides .write label span.title { + color: black; + font-weight: bold; + } + + #guides .write .actions input { + margin-right: 1em; + } + +/****************************************************************************/ +/* Wiki +/****************************************************************************/ + +.wikistyle h1, .wikistyle h2, .wikistyle h3, .wikistyle h4, .wikistyle h5, .wikistyle h6 { + border: 0 !important; +} + +.wikistyle h1 { + font-size: 170% !important; + border-top: 4px solid #aaa !important; + padding-top: .5em !important; + margin-top: 1.5em !important; +} + + .wikistyle h1:first-child { + margin-top: 0 !important; + padding-top: .25em !important; + border-top: none !important; + } + +.wikistyle h2 { + font-size: 150% !important; + margin-top: 1.5em !important; + border-top: 4px solid #e0e0e0 !important; + padding-top: .5em !important; +} + +.wikistyle h3 { + margin-top: 1em !important; +} + +.wikistyle p { + margin: 1em 0 !important; + line-height: 1.5em !important; +} + +.wikistyle ul { + margin: 1em 0 1em 2em !important; +} + +.wikistyle ol { + margin: 1em 0 1em 2em !important; +} + +.wikistyle ul ul, +.wikistyle ul ol, +.wikistyle ol ol, +.wikistyle ol ul { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.wikistyle blockquote { + margin: 1em 0 !important; + border-left: 5px solid #ddd !important; + padding-left: .6em !important; + color: #555 !important; +} + +.wikistyle dt { + font-weight: bold !important; + margin-left: 1em !important; +} + +.wikistyle dd { + margin-left: 2em !important; + margin-bottom: 1em !important; +} + +.wikistyle table { + margin: 1em 0 !important; +} + + .wikistyle table th { + border-bottom: 1px solid #bbb !important; + padding: .2em 1em !important; + } + + .wikistyle table td { + border-bottom: 1px solid #ddd !important; + padding: .2em 1em !important; + } + +.wikistyle pre { + margin: 1em 0 !important; + font-size: 90% !important; + background-color: #f8f8ff !important; + border: 1px solid #dedede !important; + padding: .5em !important; + line-height: 1.5em !important; + color: #444 !important; + overflow: auto !important; +} + + .wikistyle pre code { + padding: 0 !important; + font-size: 100% !important; + background-color: #f8f8ff !important; + border: none !important; + } + +.wikistyle code { + font-size: 90% !important; + background-color: #f8f8ff !important; + color: #444 !important; + padding: 0 .2em !important; + border: 1px solid #dedede !important; +} + +/* console */ + +.wikistyle pre.console { + margin: 1em 0 !important; + font-size: 90% !important; + background-color: black !important; + padding: .5em !important; + line-height: 1.5em !important; + color: white !important; +} + + .wikistyle pre.console code { + padding: 0 !important; + font-size: 100% !important; + background-color: black !important; + border: none !important; + color: white !important; + } + + .wikistyle pre.console span { + color: #888 !important; + } + + .wikistyle pre.console span.command { + color: yellow !important; + } \ No newline at end of file diff --git a/lib/gollum/frontend/templates/create.mustache b/lib/gollum/frontend/templates/create.mustache index 1678ccff..4bb9aa76 100644 --- a/lib/gollum/frontend/templates/create.mustache +++ b/lib/gollum/frontend/templates/create.mustache @@ -1,13 +1,18 @@ -

Create a new page

+
+ « Home +

Create a new page

-
-
- -
-
- -
-
- -
-
\ No newline at end of file +
+ + +
+ +
+
+
\ No newline at end of file diff --git a/lib/gollum/frontend/templates/edit.mustache b/lib/gollum/frontend/templates/edit.mustache index d3f942ea..3d6ae8d7 100644 --- a/lib/gollum/frontend/templates/edit.mustache +++ b/lib/gollum/frontend/templates/edit.mustache @@ -1,10 +1,14 @@ -

Editing {{name}}

+
+ « Back +

Editing “{{name}}”

-
-
- -
-
- -
-
\ No newline at end of file +
+ +
+ +
+
+
\ No newline at end of file diff --git a/lib/gollum/frontend/templates/layout.mustache b/lib/gollum/frontend/templates/layout.mustache index 59ae7b3a..c1710342 100644 --- a/lib/gollum/frontend/templates/layout.mustache +++ b/lib/gollum/frontend/templates/layout.mustache @@ -4,16 +4,18 @@ Gollum - {{title}} - + + - -
- {{{yield}}} +
+
+
+ {{{yield}}} +
+
diff --git a/lib/gollum/frontend/templates/page.mustache b/lib/gollum/frontend/templates/page.mustache index 86ee4641..2b57d98f 100644 --- a/lib/gollum/frontend/templates/page.mustache +++ b/lib/gollum/frontend/templates/page.mustache @@ -1 +1,10 @@ -{{{content}}} \ No newline at end of file +
+
+
+ Home | Edit +
+
+ {{{content}}} +
+
+
From e46a845ef5b391e4cfcf7e4187dc396c67f2e17f Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Fri, 9 Jul 2010 16:09:01 -0700 Subject: [PATCH 11/17] Show human name as title. --- lib/gollum/frontend/templates/page.mustache | 1 + lib/gollum/frontend/views/page.rb | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/lib/gollum/frontend/templates/page.mustache b/lib/gollum/frontend/templates/page.mustache index 2b57d98f..f8724a66 100644 --- a/lib/gollum/frontend/templates/page.mustache +++ b/lib/gollum/frontend/templates/page.mustache @@ -3,6 +3,7 @@ +

{{human_name}}

{{{content}}}
diff --git a/lib/gollum/frontend/views/page.rb b/lib/gollum/frontend/views/page.rb index a1aa9b0d..689ddb54 100644 --- a/lib/gollum/frontend/views/page.rb +++ b/lib/gollum/frontend/views/page.rb @@ -3,6 +3,10 @@ module Precious class Page < Layout attr_reader :content + def human_name + @name.gsub(/-/, ' ') + end + def title "A Page" end From 970bb92c7ae617836e1382912e3e2b6f1de8f10e Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Fri, 9 Jul 2010 16:09:24 -0700 Subject: [PATCH 12/17] Preserve orgmode-style double links. --- lib/gollum/markup.rb | 2 ++ test/test_markup.rb | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/gollum/markup.rb b/lib/gollum/markup.rb index 63529de5..134b2fe5 100644 --- a/lib/gollum/markup.rb +++ b/lib/gollum/markup.rb @@ -47,6 +47,8 @@ module Gollum data.gsub(/(.?)\[\[(.+?)\]\](.?)/m) do if $1 == "'" && $3 != "'" "[[#{$2}]]#{$3}" + elsif $2.include?('][') + $& else id = Digest::SHA1.hexdigest($2) @tagmap[id] = $2 diff --git a/test/test_markup.rb b/test/test_markup.rb index d14a5d9a..5cf35269 100644 --- a/test/test_markup.rb +++ b/test/test_markup.rb @@ -194,10 +194,16 @@ context "Markup" do compare(content, output) end - def compare(content, output) + test "org mode style double links" do + content = "a [[http://google.com][Google]] b" + output = "

a Google b

" + compare(content, output, 'org') + end + + def compare(content, output, ext = "md") index = @wiki.repo.index - index.add("Bilbo-Baggins.md", content) - index.commit("Add alpha.jpg") + index.add("Bilbo-Baggins.#{ext}", content) + index.commit("Add baggins") page = @wiki.page("Bilbo Baggins") rendered = Gollum::Markup.new(page).render From d14c16bf616f4908fd848880e1bd95f70b49bb6e Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Fri, 9 Jul 2010 16:46:52 -0700 Subject: [PATCH 13/17] Add Creole to valid markup formats. --- README.md | 1 + lib/gollum/page.rb | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fa89535e..01cb6a59 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ formats and allowed extensions is: * Textile: .textile * RDoc: .rdoc * Org Mode: .org + * Creole: .creole * ReStructured Text: .rest.txt, .rst.txt, .rest, .rst * ASCIIDoc: .asciidoc * POD: .pod diff --git a/lib/gollum/page.rb b/lib/gollum/page.rb index fd6f119d..ee142520 100644 --- a/lib/gollum/page.rb +++ b/lib/gollum/page.rb @@ -4,7 +4,7 @@ module Gollum Wiki.page_class = self - VALID_PAGE_RE = /^(.+)\.(md|mkdn?|mdown|markdown|textile|rdoc|org|re?st(\.txt)?|asciidoc|pod|\d)$/i + VALID_PAGE_RE = /^(.+)\.(md|mkdn?|mdown|markdown|textile|rdoc|org|creole|re?st(\.txt)?|asciidoc|pod|\d)$/i # Public: Initialize a page. # @@ -57,6 +57,8 @@ module Gollum :rdoc when /\.(org)$/i :org + when /\.(creole)$/i + :creole when /\.(re?st(\.txt)?)$/i :rest when /\.(asciidoc)$/i @@ -117,6 +119,7 @@ module Gollum when :textile then 'textile' when :rdoc then 'rdoc' when :org then 'org' + when :creole then 'creole' when :rest then 'rest' when :asciidoc then 'asciidoc' when :pod then 'pod' From 74e42c47cc71d9373e3aa65e55d2adb45c7b0da9 Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Sat, 10 Jul 2010 21:27:54 -0700 Subject: [PATCH 14/17] Add admin footer. --- lib/gollum/frontend/app.rb | 1 + lib/gollum/frontend/templates/page.mustache | 16 ++++++++++++++++ lib/gollum/frontend/views/page.rb | 21 ++++++++++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/lib/gollum/frontend/app.rb b/lib/gollum/frontend/app.rb index 3757a470..90d5e398 100644 --- a/lib/gollum/frontend/app.rb +++ b/lib/gollum/frontend/app.rb @@ -80,6 +80,7 @@ module Precious def show_page_or_file(name) wiki = Gollum::Wiki.new($path) if page = wiki.page(name) + @page = page @name = name @content = page.formatted_data mustache :page diff --git a/lib/gollum/frontend/templates/page.mustache b/lib/gollum/frontend/templates/page.mustache index f8724a66..360aba81 100644 --- a/lib/gollum/frontend/templates/page.mustache +++ b/lib/gollum/frontend/templates/page.mustache @@ -9,3 +9,19 @@
+
+
+ Last edited by {{author}}, {{date}} +
+ Home | Edit +
+
+
+ Versions: + +
+
diff --git a/lib/gollum/frontend/views/page.rb b/lib/gollum/frontend/views/page.rb index 689ddb54..ed5012a9 100644 --- a/lib/gollum/frontend/views/page.rb +++ b/lib/gollum/frontend/views/page.rb @@ -1,7 +1,7 @@ module Precious module Views class Page < Layout - attr_reader :content + attr_reader :content, :page def human_name @name.gsub(/-/, ' ') @@ -10,6 +10,25 @@ module Precious def title "A Page" end + + def author + @page.version.author.name + end + + def date + @page.version.authored_date.strftime("%Y-%m-%d %H:%M:%S") + end + + def versions + i = @page.versions.size + 1 + @page.versions.map do |v| + i -= 1 + { :id => v.id, + :id7 => v.id[0..6], + :num => i, + :author => v.author.name } + end + end end end end From 06e2cbbf59162b12cff70e2777af08ebd5bb5bae Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Sun, 11 Jul 2010 21:23:42 -0700 Subject: [PATCH 15/17] View old versions of pages. --- lib/gollum/frontend/app.rb | 13 +++++++++++++ lib/gollum/frontend/templates/page.mustache | 2 +- lib/gollum/frontend/views/page.rb | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/gollum/frontend/app.rb b/lib/gollum/frontend/app.rb index 90d5e398..12707337 100644 --- a/lib/gollum/frontend/app.rb +++ b/lib/gollum/frontend/app.rb @@ -73,6 +73,19 @@ module Precious redirect "/#{page}" end + get %r{/(.+?)/([0-9a-f]{40})} do + name = params[:captures][0] + wiki = Gollum::Wiki.new($path) + if page = wiki.page(name, params[:captures][1]) + @page = page + @name = name + @content = page.formatted_data + mustache :page + else + halt 404 + end + end + get '/*' do show_page_or_file(params[:splat].first) end diff --git a/lib/gollum/frontend/templates/page.mustache b/lib/gollum/frontend/templates/page.mustache index 360aba81..96420561 100644 --- a/lib/gollum/frontend/templates/page.mustache +++ b/lib/gollum/frontend/templates/page.mustache @@ -20,7 +20,7 @@ Versions: diff --git a/lib/gollum/frontend/views/page.rb b/lib/gollum/frontend/views/page.rb index ed5012a9..95ef8f13 100644 --- a/lib/gollum/frontend/views/page.rb +++ b/lib/gollum/frontend/views/page.rb @@ -26,6 +26,7 @@ module Precious { :id => v.id, :id7 => v.id[0..6], :num => i, + :selected => @page.version.id == v.id, :author => v.author.name } end end From 8f1100fbd63bdf30c9e07aeb2ffe983f20109117 Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Sun, 11 Jul 2010 21:52:26 -0700 Subject: [PATCH 16/17] Make version selector active (add jquery). --- .../public/javascript/jquery-1.4.2.min.js | 154 ++++++++++++++++++ lib/gollum/frontend/templates/layout.mustache | 1 + lib/gollum/frontend/templates/page.mustache | 6 + 3 files changed, 161 insertions(+) create mode 100644 lib/gollum/frontend/public/javascript/jquery-1.4.2.min.js diff --git a/lib/gollum/frontend/public/javascript/jquery-1.4.2.min.js b/lib/gollum/frontend/public/javascript/jquery-1.4.2.min.js new file mode 100644 index 00000000..48a88b8f --- /dev/null +++ b/lib/gollum/frontend/public/javascript/jquery-1.4.2.min.js @@ -0,0 +1,154 @@ +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, +Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& +(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, +a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== +"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, +function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; +var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, +parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= +false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= +s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, +applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; +else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, +a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== +w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, +cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= +c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); +a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, +function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); +k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), +C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= +e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& +f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; +if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", +e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, +"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, +d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); +t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| +g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, +CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, +text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, +setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= +h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& +q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: +function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= +{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== +"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", +d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? +a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== +1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, +""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); +return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", +""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= +c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? +c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= +function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= +Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, +"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= +a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= +a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== +"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, +serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), +function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, +global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& +e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? +"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== +false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= +false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", +c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| +d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); +g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== +1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== +"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; +if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== +"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| +c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; +this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= +this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, +e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; +a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); +c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, +d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- +f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": +"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in +e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); \ No newline at end of file diff --git a/lib/gollum/frontend/templates/layout.mustache b/lib/gollum/frontend/templates/layout.mustache index c1710342..10e3276c 100644 --- a/lib/gollum/frontend/templates/layout.mustache +++ b/lib/gollum/frontend/templates/layout.mustache @@ -7,6 +7,7 @@ + \ No newline at end of file From baaa7c6b93112418b692a973e7491de0506c4f4c Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Mon, 12 Jul 2010 17:05:48 -0700 Subject: [PATCH 17/17] Allow base path to be specified for wiki links. --- README.md | 4 ++++ lib/gollum/markup.rb | 8 +++----- lib/gollum/wiki.rb | 6 ++++++ test/test_markup.rb | 17 ++++++++++++++--- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 01cb6a59..d8e55e8f 100644 --- a/README.md +++ b/README.md @@ -231,6 +231,10 @@ Initialize the Gollum::Repo object: wiki = Gollum::Wiki.new("my-gollum-repo.git") # => +By default, internal wiki links are all absolute from the root. To specify a different base path, you can send specify the `:base_path` option: + + wiki = Gollum::Wiki.new("my-gollum-repo.git", :base_path => "/wiki") + Get the latest version of the given human or canonical page name: page = wiki.page('page-name') diff --git a/lib/gollum/markup.rb b/lib/gollum/markup.rb index 134b2fe5..f8246058 100644 --- a/lib/gollum/markup.rb +++ b/lib/gollum/markup.rb @@ -202,11 +202,9 @@ module Gollum parts = tag.split('|') name = parts[0].strip cname = Page.cname((parts[1] || parts[0]).strip) - if @wiki.page(cname) - %{#{name}} - else - %{#{name}} - end + link = ::File.join(@wiki.base_path, cname) + presence = @wiki.page(cname) ? "present" : "absent" + %{#{name}} end # Find the given file in the repo. diff --git a/lib/gollum/wiki.rb b/lib/gollum/wiki.rb index 2eb893e1..05f8ca41 100644 --- a/lib/gollum/wiki.rb +++ b/lib/gollum/wiki.rb @@ -6,6 +6,11 @@ module Gollum attr_accessor :page_class, :file_class end + # The String base path to prefix to internal links. For example, when set + # to "/wiki", the page "Hobbit" will be linked as "/wiki/Hobbit". Defaults + # to "/". + attr_reader :base_path + # Public: Initialize a new Gollum Repo. # # repo - The String path to the Git repository that holds the Gollum @@ -18,6 +23,7 @@ module Gollum def initialize(path, options = {}) @path = path @repo = Grit::Repo.new(path) + @base_path = options[:base_path] || "/" @page_class = options[:page_class] || self.class.page_class @file_class = options[:file_class] || self.class.file_class end diff --git a/test/test_markup.rb b/test/test_markup.rb index 5cf35269..822c1c10 100644 --- a/test/test_markup.rb +++ b/test/test_markup.rb @@ -21,7 +21,7 @@ context "Markup" do page = @wiki.page("Bilbo Baggins") output = Gollum::Markup.new(page).render - assert_equal %{

a Bilbo Baggins b

}, output + assert_equal %{

a Bilbo Baggins b

}, output end test "absent page link" do @@ -29,7 +29,18 @@ context "Markup" do page = @wiki.page("Tolkien") output = Gollum::Markup.new(page).render - assert_equal %{

a J. R. R. Tolkien's b

}, output + assert_equal %{

a J. R. R. Tolkien's b

}, output + end + + test "page link with custom base path" do + ["/wiki", "/wiki/"].each do |path| + @wiki = Gollum::Wiki.new(@path, :base_path => path) + @wiki.write_page("Bilbo Baggins", :markdown, "a [[Bilbo Baggins]] b", @commit) + + page = @wiki.page("Bilbo Baggins") + output = Gollum::Markup.new(page).render + assert_equal %{

a Bilbo Baggins b

}, output + end end test "image with http url" do @@ -190,7 +201,7 @@ context "Markup" do test "quoted wiki link" do content = "a '[[Foo]]', b" - output = "

a 'Foo', b

" + output = "

a 'Foo', b

" compare(content, output) end