| 1 | #!/usr/bin/ruby |
|---|
| 2 | $:.unshift File.dirname(__FILE__) + "/../../lib" |
|---|
| 3 | %w(rubygems redcloth camping camping/db acts_as_versioned).each { |lib| require lib } |
|---|
| 4 | |
|---|
| 5 | Camping.goes :Tepee |
|---|
| 6 | |
|---|
| 7 | module Tepee::Models |
|---|
| 8 | |
|---|
| 9 | class Page < Base |
|---|
| 10 | PAGE_LINK = /\[\[([^\]|]*)[|]?([^\]]*)\]\]/ |
|---|
| 11 | validates_uniqueness_of :title |
|---|
| 12 | before_save { |r| r.title = r.title.underscore } |
|---|
| 13 | acts_as_versioned |
|---|
| 14 | end |
|---|
| 15 | |
|---|
| 16 | class CreateTepee < V 1.0 |
|---|
| 17 | def self.up |
|---|
| 18 | create_table :tepee_pages do |t| |
|---|
| 19 | t.column :title, :string, :limit => 255 |
|---|
| 20 | t.column :body, :text |
|---|
| 21 | end |
|---|
| 22 | Page.create_versioned_table |
|---|
| 23 | Page.reset_column_information |
|---|
| 24 | end |
|---|
| 25 | def self.down |
|---|
| 26 | drop_table :tepee_pages |
|---|
| 27 | Page.drop_versioned_table |
|---|
| 28 | end |
|---|
| 29 | end |
|---|
| 30 | |
|---|
| 31 | end |
|---|
| 32 | |
|---|
| 33 | module Tepee::Controllers |
|---|
| 34 | class Index < R '/' |
|---|
| 35 | def get |
|---|
| 36 | redirect Show, 'home' |
|---|
| 37 | end |
|---|
| 38 | end |
|---|
| 39 | |
|---|
| 40 | class Show < R '/(\w+)', '/(\w+)/(\d+)' |
|---|
| 41 | def get page_name, version = nil |
|---|
| 42 | redirect(Edit, page_name, 1) and return unless @page = Page.find_by_title(page_name) |
|---|
| 43 | @version = (version.nil? or version == @page.version.to_s) ? @page : @page.versions.find_by_version(version) |
|---|
| 44 | render :show |
|---|
| 45 | end |
|---|
| 46 | end |
|---|
| 47 | |
|---|
| 48 | class Edit < R '/(\w+)/edit', '/(\w+)/(\d+)/edit' |
|---|
| 49 | def get page_name, version = nil |
|---|
| 50 | @page = Page.find_or_create_by_title(page_name) |
|---|
| 51 | @page = @page.versions.find_by_version(version) unless version.nil? or version == @page.version.to_s |
|---|
| 52 | render :edit |
|---|
| 53 | end |
|---|
| 54 | |
|---|
| 55 | def post page_name |
|---|
| 56 | Page.find_or_create_by_title(page_name).update_attributes :body => input.post_body and redirect Show, page_name |
|---|
| 57 | end |
|---|
| 58 | end |
|---|
| 59 | |
|---|
| 60 | class Versions < R '/(\w+)/versions' |
|---|
| 61 | def get page_name |
|---|
| 62 | @page = Page.find_or_create_by_title(page_name) |
|---|
| 63 | @versions = @page.versions |
|---|
| 64 | render :versions |
|---|
| 65 | end |
|---|
| 66 | end |
|---|
| 67 | |
|---|
| 68 | class List < R '/all/list' |
|---|
| 69 | def get |
|---|
| 70 | @pages = Page.find :all, :order => 'title' |
|---|
| 71 | render :list |
|---|
| 72 | end |
|---|
| 73 | end |
|---|
| 74 | |
|---|
| 75 | class Stylesheet < R '/css/tepee.css' |
|---|
| 76 | def get |
|---|
| 77 | @headers['Content-Type'] = 'text/css' |
|---|
| 78 | File.read(__FILE__).gsub(/.*__END__/m, '') |
|---|
| 79 | end |
|---|
| 80 | end |
|---|
| 81 | end |
|---|
| 82 | |
|---|
| 83 | module Tepee::Views |
|---|
| 84 | def layout |
|---|
| 85 | html do |
|---|
| 86 | head do |
|---|
| 87 | title 'test' |
|---|
| 88 | link :href=>R(Stylesheet), :rel=>'stylesheet', :type=>'text/css' |
|---|
| 89 | end |
|---|
| 90 | style <<-END, :type => 'text/css' |
|---|
| 91 | body { |
|---|
| 92 | font-family: verdana, arial, sans-serif; |
|---|
| 93 | } |
|---|
| 94 | h1, h2, h3, h4, h5 { |
|---|
| 95 | font-weight: normal; |
|---|
| 96 | } |
|---|
| 97 | p.actions a { |
|---|
| 98 | margin-right: 6px; |
|---|
| 99 | } |
|---|
| 100 | END |
|---|
| 101 | body do |
|---|
| 102 | p do |
|---|
| 103 | small do |
|---|
| 104 | span "welcome to " ; a 'tepee', :href => "http://code.whytheluckystiff.net/svn/camping/trunk/examples/tepee.rb" |
|---|
| 105 | span '. go ' ; a 'home', :href => R(Show, 'home') |
|---|
| 106 | span '. list all ' ; a 'pages', :href => R(List) |
|---|
| 107 | end |
|---|
| 108 | end |
|---|
| 109 | div.content do |
|---|
| 110 | self << yield |
|---|
| 111 | end |
|---|
| 112 | end |
|---|
| 113 | end |
|---|
| 114 | end |
|---|
| 115 | |
|---|
| 116 | def show |
|---|
| 117 | h1 @page.title |
|---|
| 118 | div { _markup @version.body } |
|---|
| 119 | p.actions do |
|---|
| 120 | _button 'edit', :href => R(Edit, @version.title, @version.version) |
|---|
| 121 | _button 'back', :href => R(Show, @version.title, @version.version-1) unless @version.version == 1 |
|---|
| 122 | _button 'next', :href => R(Show, @version.title, @version.version+1) unless @version.version == @page.version |
|---|
| 123 | _button 'current', :href => R(Show, @version.title) unless @version.version == @page.version |
|---|
| 124 | _button 'versions', :href => R(Versions, @page.title) |
|---|
| 125 | end |
|---|
| 126 | end |
|---|
| 127 | |
|---|
| 128 | def edit |
|---|
| 129 | h1 @page.title |
|---|
| 130 | form :method => 'post', :action => R(Edit, @page.title) do |
|---|
| 131 | p do |
|---|
| 132 | textarea @page.body, :name => 'post_body', :rows => 50, :cols => 100 |
|---|
| 133 | end |
|---|
| 134 | input :type => 'submit', :value=>'change' |
|---|
| 135 | end |
|---|
| 136 | _button 'cancel', :href => R(Show, @page.title, @page.version) |
|---|
| 137 | a 'syntax', :href => 'http://hobix.com/textile/', :target=>'_blank' |
|---|
| 138 | end |
|---|
| 139 | |
|---|
| 140 | def list |
|---|
| 141 | h1 'all pages' |
|---|
| 142 | ul { @pages.each { |p| li { a p.title, :href => R(Show, p.title) } } } |
|---|
| 143 | end |
|---|
| 144 | |
|---|
| 145 | def versions |
|---|
| 146 | h1 @page.title |
|---|
| 147 | ul do |
|---|
| 148 | @versions.each do |page| |
|---|
| 149 | li do |
|---|
| 150 | span page.version |
|---|
| 151 | _button 'show', :href => R(Show, page.title, page.version) |
|---|
| 152 | _button 'edit', :href => R(Edit, page.title, page.version) |
|---|
| 153 | end |
|---|
| 154 | end |
|---|
| 155 | end |
|---|
| 156 | end |
|---|
| 157 | |
|---|
| 158 | def _button(text, options={}) |
|---|
| 159 | form :method=>:get, :action=>options[:href] do |
|---|
| 160 | input :type=>'submit', :name=>'submit', :value=>text |
|---|
| 161 | end |
|---|
| 162 | end |
|---|
| 163 | |
|---|
| 164 | def _markup body |
|---|
| 165 | return '' if body.blank? |
|---|
| 166 | body.gsub!(Tepee::Models::Page::PAGE_LINK) do |
|---|
| 167 | page = title = $1 |
|---|
| 168 | title = $2 unless $2.empty? |
|---|
| 169 | page = page.gsub /\W/, '_' |
|---|
| 170 | if Tepee::Models::Page.find(:all, :select => 'title').collect { |p| p.title }.include?(page) |
|---|
| 171 | %Q{<a href="#{self/R(Show, page)}">#{title}</a>} |
|---|
| 172 | else |
|---|
| 173 | %Q{<span>#{title}<a href="#{self/R(Edit, page, 1)}">?</a></span>} |
|---|
| 174 | end |
|---|
| 175 | end |
|---|
| 176 | RedCloth.new(body, [ :hard_breaks ]).to_html |
|---|
| 177 | end |
|---|
| 178 | end |
|---|
| 179 | |
|---|
| 180 | def Tepee.create |
|---|
| 181 | Tepee::Models.create_schema :assume => (Tepee::Models::Page.table_exists? ? 1.0 : 0.0) |
|---|
| 182 | end |
|---|
| 183 | __END__ |
|---|
| 184 | /** focus **/ |
|---|
| 185 | /* |
|---|
| 186 | a:hover:active { |
|---|
| 187 | color: #10bae0; |
|---|
| 188 | } |
|---|
| 189 | |
|---|
| 190 | a:not(:hover):active { |
|---|
| 191 | color: #0000ff; |
|---|
| 192 | } |
|---|
| 193 | |
|---|
| 194 | *:focus { |
|---|
| 195 | -moz-outline: 2px solid #10bae0 !important; |
|---|
| 196 | -moz-outline-offset: 1px !important; |
|---|
| 197 | -moz-outline-radius: 3px !important; |
|---|
| 198 | } |
|---|
| 199 | |
|---|
| 200 | button:focus, |
|---|
| 201 | input[type="reset"]:focus, |
|---|
| 202 | input[type="button"]:focus, |
|---|
| 203 | input[type="submit"]:focus, |
|---|
| 204 | input[type="file"] > input[type="button"]:focus { |
|---|
| 205 | -moz-outline-radius: 5px !important; |
|---|
| 206 | } |
|---|
| 207 | |
|---|
| 208 | button:focus::-moz-focus-inner { |
|---|
| 209 | border-color: transparent !important; |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | button::-moz-focus-inner, |
|---|
| 213 | input[type="reset"]::-moz-focus-inner, |
|---|
| 214 | input[type="button"]::-moz-focus-inner, |
|---|
| 215 | input[type="submit"]::-moz-focus-inner, |
|---|
| 216 | input[type="file"] > input[type="button"]::-moz-focus-inner { |
|---|
| 217 | border: 1px dotted transparent !important; |
|---|
| 218 | } |
|---|
| 219 | textarea:focus, button:focus, select:focus, input:focus { |
|---|
| 220 | -moz-outline-offset: -1px !important; |
|---|
| 221 | } |
|---|
| 222 | input[type="radio"]:focus { |
|---|
| 223 | -moz-outline-radius: 12px; |
|---|
| 224 | -moz-outline-offset: 0px !important; |
|---|
| 225 | } |
|---|
| 226 | a:focus { |
|---|
| 227 | -moz-outline-offset: 0px !important; |
|---|
| 228 | } |
|---|
| 229 | */ |
|---|
| 230 | form { display: inline; } |
|---|
| 231 | |
|---|
| 232 | /** Gradient **/ |
|---|
| 233 | small, pre, textarea, textfield, button, input, select { |
|---|
| 234 | color: #4B4B4C !important; |
|---|
| 235 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAAeCAMAAAAxfD/2AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAtUExURfT09PLy8vHx8fv7+/j4+PX19fn5+fr6+vf39/z8/Pb29vPz8/39/f7+/v///0c8Y4oAAAA5SURBVHjaXMZJDgAgCMDAuouA/3+uHPRiMmlKzmhCFRorLOakVnpnDEpBBDHM8ODs/bz372+PAAMAXIQCfD6uIDsAAAAASUVORK5CYII=) !important; |
|---|
| 236 | background-color: #FFF !important; |
|---|
| 237 | background-repeat: repeat-x !important; |
|---|
| 238 | border: 1px solid #CCC !important; |
|---|
| 239 | } |
|---|
| 240 | |
|---|
| 241 | button, input { margin: 3px; } |
|---|
| 242 | |
|---|