sr / git-wiki
- Source
- Commits
- Network (44)
- Issues (0)
- Downloads (0)
- Wiki (1)
- Graphs
-
Tree:
b50336a
git-wiki / git-wiki.rb
| cd4545f4 » | Alex Payne | 2008-02-19 | 1 | #!/usr/bin/env ruby | |
| e24139e9 » | sr | 2009-01-21 | 2 | require "rubygems" | |
| 3 | gem "mojombo-grit" | ||||
| 8c1a4779 » | sr | 2008-09-21 | 4 | ||
| b50336ac » | sr | 2009-01-21 | 5 | require "sinatra/base" | |
| 6 | require "grit" | ||||
| 7 | require "redcloth" | ||||
| e34a1f77 » | sr | 2008-08-26 | 8 | ||
| 8e732dcc » | sr | 2008-08-24 | 9 | class String | |
| 10 | def titleize | ||||
| 11 | self.gsub(/([A-Z]+)([A-Z][a-z])/,'\1 \2').gsub(/([a-z\d])([A-Z])/,'\1 \2') | ||||
| 12 | end | ||||
| 13 | end | ||||
| 14 | |||||
| b50336ac » | sr | 2009-01-21 | 15 | module GitWiki | |
| 16 | class << self | ||||
| 17 | attr_accessor :homepage, :extension, :repository | ||||
| 18 | end | ||||
| 19 | |||||
| 20 | def self.new(repository, extension, homepage) | ||||
| 21 | self.homepage = homepage | ||||
| 22 | self.extension = extension | ||||
| 23 | self.repository = Grit::Repo.new(repository) | ||||
| ea533a23 » | sr | 2008-08-28 | 24 | ||
| b50336ac » | sr | 2009-01-21 | 25 | App | |
| ea533a23 » | sr | 2008-08-28 | 26 | end | |
| 27 | |||||
| b50336ac » | sr | 2009-01-21 | 28 | class PageNotFound < Sinatra::NotFound | |
| 29 | attr_reader :name | ||||
| 30 | |||||
| 31 | def initialize(name) | ||||
| 32 | @name = name | ||||
| 33 | end | ||||
| 34 | end | ||||
| 91e11a63 » | sr | 2008-03-08 | 35 | ||
| b50336ac » | sr | 2009-01-21 | 36 | class Page | |
| 37 | def self.find_all | ||||
| d8e708df » | sr | 2009-01-21 | 38 | return [] if repository.tree.contents.empty? | |
| 39 | repository.tree.contents.collect { |blob| new(blob) } | ||||
| 44e73c3e » | sr | 2008-08-26 | 40 | end | |
| ea533a23 » | sr | 2008-08-28 | 41 | ||
| b50336ac » | sr | 2009-01-21 | 42 | def self.find(name) | |
| ea533a23 » | sr | 2008-08-28 | 43 | page_blob = find_blob(name) | |
| 44 | raise PageNotFound.new(name) unless page_blob | ||||
| 45 | new(page_blob) | ||||
| 46 | end | ||||
| 47 | |||||
| b50336ac » | sr | 2009-01-21 | 48 | def self.find_or_create(name) | |
| ea533a23 » | sr | 2008-08-28 | 49 | find(name) | |
| 50 | rescue PageNotFound | ||||
| 51 | new(create_blob_for(name)) | ||||
| 52 | end | ||||
| 53 | |||||
| b50336ac » | sr | 2009-01-21 | 54 | def self.css_class_for(name) | |
| 6acef383 » | sr | 2008-09-21 | 55 | find(name) | |
| e24139e9 » | sr | 2009-01-21 | 56 | "exists" | |
| 6acef383 » | sr | 2008-09-21 | 57 | rescue PageNotFound | |
| e24139e9 » | sr | 2009-01-21 | 58 | "unknown" | |
| 6acef383 » | sr | 2008-09-21 | 59 | end | |
| 60 | |||||
| b50336ac » | sr | 2009-01-21 | 61 | def self.repository | |
| 62 | GitWiki.repository || raise | ||||
| 63 | end | ||||
| 31259071 » | sr | 2008-09-21 | 64 | ||
| b50336ac » | sr | 2009-01-21 | 65 | def self.extension | |
| 66 | GitWiki.extension || raise | ||||
| 67 | end | ||||
| 31259071 » | sr | 2008-09-21 | 68 | ||
| b50336ac » | sr | 2009-01-21 | 69 | def self.find_blob(page_name) | |
| 70 | repository.tree/(page_name + extension) | ||||
| 71 | end | ||||
| 72 | private_class_method :find_blob | ||||
| 3bdddd51 » | sr | 2008-01-29 | 73 | ||
| b50336ac » | sr | 2009-01-21 | 74 | def self.create_blob_for(page_name) | |
| 75 | Grit::Blob.create(repository, { | ||||
| 76 | :name => page_name + extension, | ||||
| 77 | :data => "" | ||||
| 78 | }) | ||||
| 79 | end | ||||
| 80 | private_class_method :create_blob_for | ||||
| 3bdddd51 » | sr | 2008-01-29 | 81 | ||
| b50336ac » | sr | 2009-01-21 | 82 | def initialize(blob) | |
| 83 | @blob = blob | ||||
| 84 | end | ||||
| 3bdddd51 » | sr | 2008-01-29 | 85 | ||
| b50336ac » | sr | 2009-01-21 | 86 | def to_html | |
| 87 | linked = auto_link(wiki_link(content)) | ||||
| 88 | RedCloth.new(linked).to_html | ||||
| 89 | end | ||||
| 3bdddd51 » | sr | 2008-01-29 | 90 | ||
| b50336ac » | sr | 2009-01-21 | 91 | def to_s | |
| 92 | name | ||||
| 44e73c3e » | sr | 2008-08-26 | 93 | end | |
| 94 | |||||
| b50336ac » | sr | 2009-01-21 | 95 | def new? | |
| 96 | @blob.id.nil? | ||||
| 44e73c3e » | sr | 2008-08-26 | 97 | end | |
| 98 | |||||
| b50336ac » | sr | 2009-01-21 | 99 | def name | |
| 100 | @blob.name.gsub(/#{File.extname(@blob.name)}$/, '') | ||||
| 44e73c3e » | sr | 2008-08-26 | 101 | end | |
| d8e708df » | sr | 2009-01-21 | 102 | ||
| b50336ac » | sr | 2009-01-21 | 103 | def content | |
| 104 | @blob.data | ||||
| d8e708df » | sr | 2009-01-21 | 105 | end | |
| 106 | |||||
| b50336ac » | sr | 2009-01-21 | 107 | def update_content(new_content) | |
| 108 | return if new_content == content | ||||
| 109 | File.open(file_name, "w") { |f| f << new_content } | ||||
| 110 | add_to_index_and_commit! | ||||
| d8e708df » | sr | 2009-01-21 | 111 | end | |
| 3bdddd51 » | sr | 2008-01-29 | 112 | ||
| b50336ac » | sr | 2009-01-21 | 113 | private | |
| 114 | def add_to_index_and_commit! | ||||
| 115 | Dir.chdir(self.class.repository.working_dir) { | ||||
| 116 | self.class.repository.add(@blob.name) | ||||
| 117 | } | ||||
| 118 | self.class.repository.commit_index(commit_message) | ||||
| 119 | end | ||||
| 5b5675c7 » | sr | 2008-03-28 | 120 | ||
| b50336ac » | sr | 2009-01-21 | 121 | def file_name | |
| 122 | File.join(self.class.repository.working_dir, name + self.class.extension) | ||||
| 123 | end | ||||
| 9c2e1ee5 » | sr | 2008-09-29 | 124 | ||
| b50336ac » | sr | 2009-01-21 | 125 | def commit_message | |
| 126 | new? ? "Created #{name}" : "Updated #{name}" | ||||
| 127 | end | ||||
| e8ace3b0 » | sr | 2008-03-28 | 128 | ||
| b50336ac » | sr | 2009-01-21 | 129 | def auto_link(str) | |
| 130 | str.gsub(/<((https?|ftp|irc):[^'">\s]+)>/xi, %Q{<a href="\\1">\\1</a>}) | ||||
| 131 | end | ||||
| ea533a23 » | sr | 2008-08-28 | 132 | ||
| b50336ac » | sr | 2009-01-21 | 133 | def wiki_link(str) | |
| 134 | str.gsub(/([A-Z][a-z]+[A-Z][A-Za-z0-9]+)/) { |page| | ||||
| 135 | %Q{<a class="#{self.class.css_class_for(page)}"} + | ||||
| 136 | %Q{href="/#{page}">#{page.titleize}</a>} | ||||
| 137 | } | ||||
| 138 | end | ||||
| 16928c6a » | sr | 2008-03-27 | 139 | end | |
| 60dfcabc » | sr | 2008-03-28 | 140 | ||
| b50336ac » | sr | 2009-01-21 | 141 | class App < Sinatra::Base | |
| 142 | set :app_file, __FILE__ | ||||
| 143 | set :haml, { :format => :html5, | ||||
| 144 | :attr_wrapper => '"' } | ||||
| 145 | enable :static | ||||
| 146 | use_in_file_templates! | ||||
| 16928c6a » | sr | 2008-03-27 | 147 | ||
| b50336ac » | sr | 2009-01-21 | 148 | error PageNotFound do | |
| 149 | page = request.env["sinatra.error"].name | ||||
| 150 | redirect "/#{page}/edit" | ||||
| 151 | end | ||||
| 4a2e99ae » | sr | 2008-03-27 | 152 | ||
| b50336ac » | sr | 2009-01-21 | 153 | before do | |
| 154 | content_type "text/html", :charset => "utf-8" | ||||
| 155 | end | ||||
| 4a2e99ae » | sr | 2008-03-27 | 156 | ||
| b50336ac » | sr | 2009-01-21 | 157 | get "/" do | |
| 158 | redirect "/" + GitWiki.homepage | ||||
| 159 | end | ||||
| 3bdddd51 » | sr | 2008-01-29 | 160 | ||
| b50336ac » | sr | 2009-01-21 | 161 | get "/_stylesheet.css" do | |
| 162 | content_type "text/css", :charset => "utf-8" | ||||
| 163 | sass :stylesheet | ||||
| 164 | end | ||||
| 68eeb527 » | sr | 2008-01-31 | 165 | ||
| b50336ac » | sr | 2009-01-21 | 166 | get "/_list" do | |
| 167 | @pages = Page.find_all | ||||
| 168 | haml :list | ||||
| 169 | end | ||||
| 3bdddd51 » | sr | 2008-01-29 | 170 | ||
| b50336ac » | sr | 2009-01-21 | 171 | get "/:page" do | |
| 172 | @page = Page.find(params[:page]) | ||||
| 173 | haml :show | ||||
| 174 | end | ||||
| 175 | |||||
| 176 | get "/e/:page" do | ||||
| 177 | @page = Page.find_or_create(params[:page]) | ||||
| 178 | haml :edit | ||||
| 179 | end | ||||
| 3bdddd51 » | sr | 2008-01-29 | 180 | ||
| b50336ac » | sr | 2009-01-21 | 181 | post "/e/:page" do | |
| 182 | @page = Page.find_or_create(params[:page]) | ||||
| 183 | @page.update_content(params[:body]) | ||||
| 184 | redirect "/#{@page}" | ||||
| 185 | end | ||||
| 186 | |||||
| 187 | private | ||||
| 188 | def title(title=nil) | ||||
| 189 | @title = title.to_s unless title.nil? | ||||
| 190 | @title | ||||
| 191 | end | ||||
| 192 | |||||
| 193 | def list_item(page) | ||||
| 194 | %Q{<a class="page_name" href="/#{page}">#{page.name.titleize}</a>} | ||||
| 195 | end | ||||
| 196 | end | ||||
| 3bdddd51 » | sr | 2008-01-29 | 197 | end | |
| 198 | |||||
| 16928c6a » | sr | 2008-03-27 | 199 | __END__ | |
| 5108abaf » | sr | 2008-05-04 | 200 | @@ layout | |
| 3f130b2d » | sr | 2009-01-21 | 201 | !!! | |
| 3bdddd51 » | sr | 2008-01-29 | 202 | %html | |
| 203 | %head | ||||
| 16928c6a » | sr | 2008-03-27 | 204 | %title= title | |
| 205 | %link{:rel => 'stylesheet', :href => '/_stylesheet.css', :type => 'text/css'} | ||||
| ca698d0e » | sr | 2008-09-29 | 206 | %script{:src => '/jquery-1.2.3.min.js', :type => 'text/javascript'} | |
| 207 | %script{:src => '/jquery.hotkeys.js', :type => 'text/javascript'} | ||||
| 208 | %script{:src => '/to-title-case.js', :type => 'text/javascript'} | ||||
| 38c0188d » | sr | 2008-03-27 | 209 | :javascript | |
| 210 | $(document).ready(function() { | ||||
| b50336ac » | sr | 2009-01-21 | 211 | $.hotkeys.add('Ctrl+h', function(){document.location = '/#{GitWiki.homepage}'}) | |
| 212 | $.hotkeys.add('Ctrl+l', function(){document.location = '/_list'}) | ||||
| 8e732dcc » | sr | 2008-08-24 | 213 | ||
| 214 | /* title-case-ification */ | ||||
| 215 | document.title = document.title.toTitleCase(); | ||||
| 216 | $('h1:first').text($('h1:first').text().toTitleCase()); | ||||
| 217 | $('a').each(function(i) { | ||||
| 218 | var e = $(this) | ||||
| 219 | e.text(e.text().toTitleCase()); | ||||
| 220 | }) | ||||
| 38c0188d » | sr | 2008-03-27 | 221 | }) | |
| 3bdddd51 » | sr | 2008-01-29 | 222 | %body | |
| 16928c6a » | sr | 2008-03-27 | 223 | #content= yield | |
| 3bdddd51 » | sr | 2008-01-29 | 224 | ||
| 5108abaf » | sr | 2008-05-04 | 225 | @@ show | |
| 8e732dcc » | sr | 2008-08-24 | 226 | - title @page.name.titleize | |
| d47f5f25 » | sr | 2008-03-27 | 227 | :javascript | |
| 228 | $(document).ready(function() { | ||||
| b50336ac » | sr | 2009-01-21 | 229 | $.hotkeys.add('Ctrl+e', function(){document.location = '/e/#{@page}'}) | |
| d47f5f25 » | sr | 2008-03-27 | 230 | }) | |
| 35eb7e8e » | sr | 2008-09-24 | 231 | %h1#page_title= title | |
| c266faa8 » | sr | 2008-05-13 | 232 | #page_content | |
| ea533a23 » | sr | 2008-08-28 | 233 | ~"#{@page.to_html}" | |
| 3bdddd51 » | sr | 2008-01-29 | 234 | ||
| 5108abaf » | sr | 2008-05-04 | 235 | @@ edit | |
| 8e732dcc » | sr | 2008-08-24 | 236 | - title "Editing #{@page.name.titleize}" | |
| 16928c6a » | sr | 2008-03-27 | 237 | %h1= title | |
| c47205a1 » | sr | 2008-03-28 | 238 | %form{:method => 'POST', :action => "/e/#{@page}"} | |
| d47f5f25 » | sr | 2008-03-27 | 239 | %p | |
| 35eb7e8e » | sr | 2008-09-24 | 240 | %textarea{:name => 'body'}= @page.content | |
| d47f5f25 » | sr | 2008-03-27 | 241 | %p | |
| 38c0188d » | sr | 2008-03-27 | 242 | %input.submit{:type => :submit, :value => 'Save as the newest version'} | |
| bdd34406 » | sr | 2008-03-28 | 243 | or | |
| c47205a1 » | sr | 2008-03-28 | 244 | %a.cancel{:href=>"/#{@page}"} cancel | |
| 16928c6a » | sr | 2008-03-27 | 245 | ||
| 5108abaf » | sr | 2008-05-04 | 246 | @@ list | |
| 16928c6a » | sr | 2008-03-27 | 247 | - title "Listing pages" | |
| 35eb7e8e » | sr | 2008-09-24 | 248 | %h1#page_title All pages | |
| 16928c6a » | sr | 2008-03-27 | 249 | - if @pages.empty? | |
| 88d664e0 » | Bryan T. Richardson | 2008-08-20 | 250 | %p No pages found. | |
| 16928c6a » | sr | 2008-03-27 | 251 | - else | |
| bdd34406 » | sr | 2008-03-28 | 252 | %ul#pages_list | |
| f88d9eb3 » | sr | 2008-08-26 | 253 | - @pages.each_with_index do |page, index| | |
| 254 | - if (index % 2) == 0 | ||||
| 255 | %li.odd= list_item(page) | ||||
| 256 | - else | ||||
| 257 | %li.even= list_item(page) | ||||
| 16928c6a » | sr | 2008-03-27 | 258 | ||
| 5108abaf » | sr | 2008-05-04 | 259 | @@ stylesheet | |
| 1dfbc578 » | sr | 2008-02-26 | 260 | body | |
| 261 | :font | ||||
| 38c0188d » | sr | 2008-03-27 | 262 | family: "Lucida Grande", Verdana, Arial, Bitstream Vera Sans, Helvetica, sans-serif | |
| 1dfbc578 » | sr | 2008-02-26 | 263 | size: 14px | |
| 264 | color: black | ||||
| 265 | line-height: 160% | ||||
| 266 | background-color: white | ||||
| 35eb7e8e » | sr | 2008-09-24 | 267 | margin: 0 10px | |
| 38c0188d » | sr | 2008-03-27 | 268 | padding: 0 | |
| 35eb7e8e » | sr | 2008-09-24 | 269 | h1#page_title | |
| 270 | font-size: xx-large | ||||
| 271 | text-align: center | ||||
| 272 | padding: .9em | ||||
| 273 | h1 | ||||
| 274 | font-size: x-large | ||||
| 275 | h2 | ||||
| 276 | font-size: large | ||||
| 277 | h3 | ||||
| 278 | font-size: medium | ||||
| 1dfbc578 » | sr | 2008-02-26 | 279 | a | |
| 38c0188d » | sr | 2008-03-27 | 280 | padding: 2px | |
| 281 | color: blue | ||||
| bdd34406 » | sr | 2008-03-28 | 282 | &.exists | |
| 283 | &:hover | ||||
| 284 | background-color: blue | ||||
| 285 | text-decoration: none | ||||
| 286 | color: white | ||||
| 287 | &.unknown | ||||
| 288 | color: gray | ||||
| 289 | &:hover | ||||
| 290 | background-color: gray | ||||
| 291 | color: white | ||||
| 292 | text-decoration: none | ||||
| f88d9eb3 » | sr | 2008-08-26 | 293 | &.cancel | |
| 294 | color: red | ||||
| 295 | &:hover | ||||
| 296 | text-decoration: none | ||||
| 297 | background-color: red | ||||
| 298 | color: white | ||||
| 35eb7e8e » | sr | 2008-09-24 | 299 | blockquote | |
| 300 | background-color: #f9f9f9 | ||||
| 301 | padding: 5px 5px | ||||
| 302 | margin: 0 | ||||
| 303 | margin-bottom: 2em | ||||
| 304 | outline: #eee solid 1px | ||||
| 305 | font-size: 0.9em | ||||
| 306 | cite | ||||
| 307 | font-weight: bold | ||||
| 308 | padding-left: 2em | ||||
| 309 | code | ||||
| 310 | background-color: #eee | ||||
| 311 | font-size: smaller | ||||
| 312 | pre | ||||
| 313 | padding: 5px 5px | ||||
| 314 | overflow: auto | ||||
| 315 | font-family: fixed | ||||
| 316 | line-height: 1em | ||||
| 317 | border-right: 1px solid #ccc | ||||
| 318 | border-bottom: 1px solid #ccc | ||||
| 319 | background-color: #eee | ||||
| 38c0188d » | sr | 2008-03-27 | 320 | textarea | |
| 321 | font-family: courrier | ||||
| 35eb7e8e » | sr | 2008-09-24 | 322 | font-size: .9em | |
| 323 | border: 2px solid #ccc | ||||
| 324 | display: block | ||||
| 325 | padding: .5em | ||||
| 326 | height: 37em | ||||
| 327 | width: 100% | ||||
| 38c0188d » | sr | 2008-03-27 | 328 | line-height: 18px | |
| 35eb7e8e » | sr | 2008-09-24 | 329 | input.submit | |
| 38c0188d » | sr | 2008-03-27 | 330 | font-weight: bold | |
| 35eb7e8e » | sr | 2008-09-24 | 331 | ||
| 332 | #content | ||||
| 333 | max-width: 48em | ||||
| 334 | margin: auto | ||||
| 335 | padding: 2em | ||||
| bdd34406 » | sr | 2008-03-28 | 336 | ul#pages_list | |
| 337 | list-style-type: none | ||||
| 338 | margin: 0 | ||||
| 339 | padding: 0 | ||||
| 340 | li | ||||
| 341 | padding: 5px | ||||
| 342 | &.odd | ||||
| 343 | background-color: #D3D3D3 | ||||
| 35eb7e8e » | sr | 2008-09-24 | 344 | a | |
| 345 | text-decoration: none | ||||
| 346 | .highlight | ||||
| 347 | background-color: #f8ec11 | ||||
| 348 | .done | ||||
| 349 | font-size: x-small | ||||
| 350 | color: #999 | ||||
| add3182e » | sr | 2009-01-19 | 351 | table | |
| 352 | text-align: center | ||||
| 353 | width: 100% | ||||
| 354 | border: none | ||||
| 355 | border-collapse: collapse | ||||
| 356 | border-spacing: 0px | ||||
| 357 | th | ||||
| 358 | color: #FFF | ||||
| 359 | background-color: #3F3F3F | ||||
| 360 | border-bottom: 1px solid black | ||||
| 361 | padding: 2px | ||||
| 362 | tr | ||||
| 363 | border-bottom: 1px solid black | ||||

