| 1 | #!/usr/bin/env ruby |
|---|
| 2 | |
|---|
| 3 | $:.unshift File.dirname(__FILE__) + "/../../lib" |
|---|
| 4 | %w(rubygems redcloth camping camping/db acts_as_versioned).each { |lib| require lib } |
|---|
| 5 | |
|---|
| 6 | Camping.goes :CampSh |
|---|
| 7 | |
|---|
| 8 | module CampSh |
|---|
| 9 | NAME = 'CampSh' |
|---|
| 10 | DESCRIPTION = %{ |
|---|
| 11 | Script your own URL commands, then run these commands through |
|---|
| 12 | the proxy with "cmd/CommandName". All scripts are versioned |
|---|
| 13 | and attributed. |
|---|
| 14 | } |
|---|
| 15 | VERSION = '0.1' |
|---|
| 16 | ANON = 'AnonymousCoward' |
|---|
| 17 | |
|---|
| 18 | begin |
|---|
| 19 | require 'syntax/convertors/html' |
|---|
| 20 | SYNTAX = ::Syntax::Convertors::HTML.for_syntax "ruby" |
|---|
| 21 | rescue LoadError |
|---|
| 22 | end |
|---|
| 23 | |
|---|
| 24 | def self.create |
|---|
| 25 | Models.create_schema :assume => (Models::Command.table_exists? ? 1.0 : 0.0) |
|---|
| 26 | end |
|---|
| 27 | end |
|---|
| 28 | |
|---|
| 29 | module CampSh::Models |
|---|
| 30 | class Command < Base |
|---|
| 31 | validates_uniqueness_of :name |
|---|
| 32 | validates_presence_of :author |
|---|
| 33 | acts_as_versioned |
|---|
| 34 | end |
|---|
| 35 | class CreateBasics < V 1.0 |
|---|
| 36 | def self.up |
|---|
| 37 | create_table :campsh_commands do |t| |
|---|
| 38 | t.column :author, :string, :limit => 40 |
|---|
| 39 | t.column :name, :string, :limit => 255 |
|---|
| 40 | t.column :created_at, :datetime |
|---|
| 41 | t.column :doc, :text |
|---|
| 42 | t.column :code, :text |
|---|
| 43 | end |
|---|
| 44 | Command.create_versioned_table |
|---|
| 45 | Command.reset_column_information |
|---|
| 46 | end |
|---|
| 47 | def self.down |
|---|
| 48 | drop_table :campsh_commands |
|---|
| 49 | Command.drop_versioned_table |
|---|
| 50 | end |
|---|
| 51 | end |
|---|
| 52 | end |
|---|
| 53 | |
|---|
| 54 | module CampSh::Controllers |
|---|
| 55 | class Index < R '/' |
|---|
| 56 | def get |
|---|
| 57 | redirect List |
|---|
| 58 | end |
|---|
| 59 | end |
|---|
| 60 | |
|---|
| 61 | class List |
|---|
| 62 | def get |
|---|
| 63 | @cmds = Command.find :all, :order => 'name' |
|---|
| 64 | @title = "Command List" |
|---|
| 65 | render :list |
|---|
| 66 | end |
|---|
| 67 | end |
|---|
| 68 | |
|---|
| 69 | class Run < R '/run/(\w+)', '/run/(\w+)/(.+)', '/run/(\w+) (.+)' |
|---|
| 70 | def get(cmd, args=nil) |
|---|
| 71 | @cmd = Command.find_by_name(cmd) |
|---|
| 72 | unless @cmd |
|---|
| 73 | redirect New, name |
|---|
| 74 | return |
|---|
| 75 | end |
|---|
| 76 | |
|---|
| 77 | args = args.to_s.strip.split(/[\/\s]+/) |
|---|
| 78 | eval(@cmd.code) |
|---|
| 79 | end |
|---|
| 80 | end |
|---|
| 81 | |
|---|
| 82 | class Authors |
|---|
| 83 | def get |
|---|
| 84 | @authors = |
|---|
| 85 | Command.find(:all, :order => "author, name").inject({}) do |hsh, cmd| |
|---|
| 86 | (hsh[cmd.author] ||= []) << cmd |
|---|
| 87 | hsh |
|---|
| 88 | end |
|---|
| 89 | @title = "Author" |
|---|
| 90 | render :authors |
|---|
| 91 | end |
|---|
| 92 | end |
|---|
| 93 | |
|---|
| 94 | class Recent |
|---|
| 95 | def get |
|---|
| 96 | @days = |
|---|
| 97 | Command.find(:all, :order => "created_at DESC").inject({}) do |hsh, cmd| |
|---|
| 98 | (hsh[cmd.created_at.strftime("%B %d, %Y")] ||= []) << cmd |
|---|
| 99 | hsh |
|---|
| 100 | end |
|---|
| 101 | @title = "Recently Revised" |
|---|
| 102 | render :recent |
|---|
| 103 | end |
|---|
| 104 | end |
|---|
| 105 | |
|---|
| 106 | class Show < R '/show/(\w+)', '/show/(\w+)/(\d+)', '/cancel_edit/(\w+)' |
|---|
| 107 | def get(name, version = nil) |
|---|
| 108 | unless @cmd = Command.find_by_name(name) |
|---|
| 109 | redirect(Edit, name) |
|---|
| 110 | return |
|---|
| 111 | end |
|---|
| 112 | @version = (version.nil? or version == @cmd.version.to_s) ? @cmd : @cmd.versions.find_by_version(version) |
|---|
| 113 | render :show |
|---|
| 114 | end |
|---|
| 115 | end |
|---|
| 116 | |
|---|
| 117 | class New < R '/new', '/new/(\w+)' |
|---|
| 118 | def get(name) |
|---|
| 119 | @cmd = Command.new(:name => name) |
|---|
| 120 | @title = "Creating #{name}" |
|---|
| 121 | render :edit |
|---|
| 122 | end |
|---|
| 123 | def post |
|---|
| 124 | @cmd = Command.new(:name => input.cmd) |
|---|
| 125 | @title = "Creating #{input.cmd}" |
|---|
| 126 | render :edit |
|---|
| 127 | end |
|---|
| 128 | end |
|---|
| 129 | |
|---|
| 130 | class Edit < R '/edit/(\w+)', '/edit/(\w+)/(\d+)' |
|---|
| 131 | def get(name, version = nil) |
|---|
| 132 | @cmd = Command.find_by_name(name) |
|---|
| 133 | @cmd = @cmd.versions.find_by_version(version) unless version.nil? or version == @cmd.version.to_s |
|---|
| 134 | @title = "Editing #{name}" |
|---|
| 135 | @author = @cookies.cmd_author || CampSh::ANON |
|---|
| 136 | render :edit |
|---|
| 137 | end |
|---|
| 138 | def post(name) |
|---|
| 139 | @cookies.cmd_author = input.command.author |
|---|
| 140 | Command.find_or_create_by_name(name).update_attributes(input.command) |
|---|
| 141 | redirect Show, name |
|---|
| 142 | end |
|---|
| 143 | end |
|---|
| 144 | |
|---|
| 145 | class HowTo |
|---|
| 146 | def get |
|---|
| 147 | @title = "How To" |
|---|
| 148 | render :howto |
|---|
| 149 | end |
|---|
| 150 | end |
|---|
| 151 | |
|---|
| 152 | class Style < R '/styles.css' |
|---|
| 153 | def get |
|---|
| 154 | @headers['Content-Type'] = 'text/css' |
|---|
| 155 | %Q[ |
|---|
| 156 | h1#pageName, .newWikiWord a, a.existingWikiWord, .newWikiWord a:hover, |
|---|
| 157 | #TextileHelp h3 { color: #003B76; } |
|---|
| 158 | |
|---|
| 159 | #container { width: 720px; } |
|---|
| 160 | |
|---|
| 161 | #container { |
|---|
| 162 | float: none; |
|---|
| 163 | margin: 0 auto; |
|---|
| 164 | text-align: center; |
|---|
| 165 | padding: 2px; |
|---|
| 166 | border: solid 2px #999; |
|---|
| 167 | } |
|---|
| 168 | |
|---|
| 169 | #content { |
|---|
| 170 | margin: 0; |
|---|
| 171 | padding: 9px; |
|---|
| 172 | text-align: left; |
|---|
| 173 | border-top: none; |
|---|
| 174 | border: solid 1px #999; |
|---|
| 175 | background-color: #eee; |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| 178 | body, p, ol, ul, td { |
|---|
| 179 | font-family: verdana, arial, helvetica, sans-serif; |
|---|
| 180 | font-size: 15px; |
|---|
| 181 | line-height: 110%; |
|---|
| 182 | } |
|---|
| 183 | |
|---|
| 184 | a { color: #000; } |
|---|
| 185 | |
|---|
| 186 | .newWikiWord { background-color: #eee; } |
|---|
| 187 | .newWikiWord a:hover { background-color: white; } |
|---|
| 188 | |
|---|
| 189 | a:visited { color: #666; } |
|---|
| 190 | a:hover { color: #fff; background-color:#000; } |
|---|
| 191 | |
|---|
| 192 | /* a.edit:link, a.edit:visited { color: #DA0006; } */ |
|---|
| 193 | |
|---|
| 194 | |
|---|
| 195 | h1, h2, h3 { color: #333; font-family: georgia, verdana; text-align: center; line-height: 70%; margin-bottom: 0; } |
|---|
| 196 | h1 { font-size: 28px } |
|---|
| 197 | h2 { font-size: 22px } |
|---|
| 198 | h3 { font-size: 19px } |
|---|
| 199 | |
|---|
| 200 | h1#pageName { |
|---|
| 201 | margin: 5px 0px 0px 0px; |
|---|
| 202 | padding: 0px 0px 0px 0px; |
|---|
| 203 | line-height: 28px; |
|---|
| 204 | } |
|---|
| 205 | |
|---|
| 206 | h1#pageName small { |
|---|
| 207 | color: grey; |
|---|
| 208 | line-height: 10px; |
|---|
| 209 | font-size: 10px; |
|---|
| 210 | padding: 0px; |
|---|
| 211 | } |
|---|
| 212 | |
|---|
| 213 | a.nav, a.nav:link, a.nav:visited { color: #000; } |
|---|
| 214 | a.nav:hover { color: #fff; background-color:#000; } |
|---|
| 215 | |
|---|
| 216 | li { margin-bottom: 7px } |
|---|
| 217 | |
|---|
| 218 | .navigation { |
|---|
| 219 | margin-top: 5px; |
|---|
| 220 | font-size : 12px; |
|---|
| 221 | color: #999; |
|---|
| 222 | text-align: center; |
|---|
| 223 | } |
|---|
| 224 | |
|---|
| 225 | .navigation a:hover { color: #fff; background-color:#000; } |
|---|
| 226 | |
|---|
| 227 | .navigation a { |
|---|
| 228 | font-size: 11px; |
|---|
| 229 | color: black; |
|---|
| 230 | font-weight: bold; |
|---|
| 231 | } |
|---|
| 232 | |
|---|
| 233 | .navigation small a { |
|---|
| 234 | font-weight: normal; |
|---|
| 235 | font-size: 11px; |
|---|
| 236 | } |
|---|
| 237 | |
|---|
| 238 | .navOn{ |
|---|
| 239 | font-size: 11px; |
|---|
| 240 | color: grey; |
|---|
| 241 | font-weight: bold; |
|---|
| 242 | text-decoration: none; |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | .help { |
|---|
| 246 | font-family: verdana, arial, helvetica, sans-serif; |
|---|
| 247 | font-size: 11px; |
|---|
| 248 | } |
|---|
| 249 | |
|---|
| 250 | .inputBox { |
|---|
| 251 | font-family: verdana, arial, helvetica, sans-serif; |
|---|
| 252 | font-size: 11px; |
|---|
| 253 | background-color: #eee; |
|---|
| 254 | padding: 5px; |
|---|
| 255 | margin-bottom: 20px; |
|---|
| 256 | } |
|---|
| 257 | |
|---|
| 258 | blockquote { |
|---|
| 259 | display: block; |
|---|
| 260 | margin: 0px 0px 20px 0px; |
|---|
| 261 | padding: 0px 30px; |
|---|
| 262 | font-size:11px; |
|---|
| 263 | line-height:17px; |
|---|
| 264 | font-style: italic; |
|---|
| 265 | } |
|---|
| 266 | |
|---|
| 267 | pre { |
|---|
| 268 | background-color: #eee; |
|---|
| 269 | padding: 10px; |
|---|
| 270 | font-size: 11px; |
|---|
| 271 | } |
|---|
| 272 | |
|---|
| 273 | ol.setup { |
|---|
| 274 | font-size: 19px; |
|---|
| 275 | font-family: georgia, verdana; |
|---|
| 276 | padding-left: 25px; |
|---|
| 277 | } |
|---|
| 278 | |
|---|
| 279 | ol.setup li { |
|---|
| 280 | margin-bottom: 20px |
|---|
| 281 | } |
|---|
| 282 | |
|---|
| 283 | .byline { |
|---|
| 284 | font-size: 10px; |
|---|
| 285 | font-style: italic; |
|---|
| 286 | margin-bottom: 10px; |
|---|
| 287 | color: #999; |
|---|
| 288 | } |
|---|
| 289 | |
|---|
| 290 | .references { |
|---|
| 291 | font-size: 10px; |
|---|
| 292 | } |
|---|
| 293 | |
|---|
| 294 | .diffdel { |
|---|
| 295 | background: pink; |
|---|
| 296 | } |
|---|
| 297 | |
|---|
| 298 | .diffins { |
|---|
| 299 | background: lightgreen; |
|---|
| 300 | } |
|---|
| 301 | |
|---|
| 302 | #allCommands ul { |
|---|
| 303 | list-style: none; |
|---|
| 304 | } |
|---|
| 305 | |
|---|
| 306 | #allCommands li { |
|---|
| 307 | padding: 1px 4px; |
|---|
| 308 | } |
|---|
| 309 | |
|---|
| 310 | #allCommands li:hover { |
|---|
| 311 | background-color: white; |
|---|
| 312 | } |
|---|
| 313 | |
|---|
| 314 | #allCommands a, |
|---|
| 315 | #allCommands a:hover, |
|---|
| 316 | #allCommands a:link, |
|---|
| 317 | #allCommands a:visited, |
|---|
| 318 | #allCommands h2 { |
|---|
| 319 | color: #369; |
|---|
| 320 | background-color: transparent; |
|---|
| 321 | font-weight: normal; |
|---|
| 322 | font-size: 24px; |
|---|
| 323 | text-align: left; |
|---|
| 324 | } |
|---|
| 325 | |
|---|
| 326 | #TextileHelp table { |
|---|
| 327 | margin-bottom: 0; |
|---|
| 328 | } |
|---|
| 329 | |
|---|
| 330 | #TextileHelp table+h3 { |
|---|
| 331 | margin-top: 11px; |
|---|
| 332 | } |
|---|
| 333 | |
|---|
| 334 | #TextileHelp table td { |
|---|
| 335 | font-size: 11px; |
|---|
| 336 | padding: 3px; |
|---|
| 337 | vertical-align: top; |
|---|
| 338 | border-top: 1px dotted #ccc; |
|---|
| 339 | } |
|---|
| 340 | |
|---|
| 341 | #TextileHelp table td.arrow { |
|---|
| 342 | padding-right: 5px; |
|---|
| 343 | padding-left: 10px; |
|---|
| 344 | color: #999; |
|---|
| 345 | } |
|---|
| 346 | |
|---|
| 347 | #TextileHelp table td.label { |
|---|
| 348 | font-weight: bold; |
|---|
| 349 | white-space: nowrap; |
|---|
| 350 | font-size: 10px; |
|---|
| 351 | padding-right: 15px; |
|---|
| 352 | color: #000; |
|---|
| 353 | } |
|---|
| 354 | |
|---|
| 355 | #TextileHelp h3 { |
|---|
| 356 | font-size: 11px; |
|---|
| 357 | font-weight: bold; |
|---|
| 358 | font-weight: normal; |
|---|
| 359 | margin: 0 0 5px 0; |
|---|
| 360 | padding: 5px 0 0 0; |
|---|
| 361 | } |
|---|
| 362 | |
|---|
| 363 | #TextileHelp p { |
|---|
| 364 | font-size: 10px; |
|---|
| 365 | } |
|---|
| 366 | |
|---|
| 367 | .rightHandSide { |
|---|
| 368 | float: right; |
|---|
| 369 | width: 147px; |
|---|
| 370 | margin-left: 10px; |
|---|
| 371 | padding-left: 20px; |
|---|
| 372 | border-left: 1px dotted #ccc; |
|---|
| 373 | } |
|---|
| 374 | |
|---|
| 375 | .rightHandSide p { |
|---|
| 376 | font-size: 10px; |
|---|
| 377 | } |
|---|
| 378 | |
|---|
| 379 | .newsList { |
|---|
| 380 | margin-top: 20px; |
|---|
| 381 | } |
|---|
| 382 | |
|---|
| 383 | .newsList p { |
|---|
| 384 | margin-bottom:30px |
|---|
| 385 | } |
|---|
| 386 | |
|---|
| 387 | .leftHandSide |
|---|
| 388 | { |
|---|
| 389 | float: right; |
|---|
| 390 | width: 147px; |
|---|
| 391 | margin-left: 10px; |
|---|
| 392 | padding-left: 20px; |
|---|
| 393 | border-left: 1px dotted #ccc; |
|---|
| 394 | } |
|---|
| 395 | |
|---|
| 396 | .leftHandSide p |
|---|
| 397 | { |
|---|
| 398 | font-size: 10px; |
|---|
| 399 | margin: 0; |
|---|
| 400 | padding: 0; |
|---|
| 401 | } |
|---|
| 402 | |
|---|
| 403 | .leftHandSide h2 |
|---|
| 404 | { |
|---|
| 405 | font-size: 12px; |
|---|
| 406 | margin-bottom: 0; |
|---|
| 407 | padding-bottom: 0; |
|---|
| 408 | } |
|---|
| 409 | |
|---|
| 410 | .property |
|---|
| 411 | { |
|---|
| 412 | color: grey; |
|---|
| 413 | font-size: 9px; |
|---|
| 414 | text-align: right; |
|---|
| 415 | } |
|---|
| 416 | |
|---|
| 417 | body |
|---|
| 418 | { |
|---|
| 419 | background-color: #ccc; |
|---|
| 420 | padding: 0; |
|---|
| 421 | margin: 20px; |
|---|
| 422 | color: #333; |
|---|
| 423 | line-height: 1.5; |
|---|
| 424 | font-size: 85%; |
|---|
| 425 | /* hacky hack */ |
|---|
| 426 | voice-family: "\"}\""; |
|---|
| 427 | voice-family: inherit; |
|---|
| 428 | font-size: 80%; |
|---|
| 429 | } |
|---|
| 430 | |
|---|
| 431 | /* be nice to opera */ |
|---|
| 432 | html>body { font-size: 80%; } |
|---|
| 433 | |
|---|
| 434 | /* syntax highlighting */ |
|---|
| 435 | .keyword { |
|---|
| 436 | font-weight: bold; |
|---|
| 437 | } |
|---|
| 438 | .comment { |
|---|
| 439 | color: #555; |
|---|
| 440 | } |
|---|
| 441 | .string, .number { |
|---|
| 442 | color: #396; |
|---|
| 443 | } |
|---|
| 444 | .regex { |
|---|
| 445 | color: #435; |
|---|
| 446 | } |
|---|
| 447 | .ident { |
|---|
| 448 | color: #369; |
|---|
| 449 | } |
|---|
| 450 | .symbol { |
|---|
| 451 | color: #000; |
|---|
| 452 | } |
|---|
| 453 | .constant, .class { |
|---|
| 454 | color: #630; |
|---|
| 455 | font-weight: bold; |
|---|
| 456 | } |
|---|
| 457 | ] |
|---|
| 458 | end |
|---|
| 459 | end |
|---|
| 460 | |
|---|
| 461 | end |
|---|
| 462 | |
|---|
| 463 | module CampSh::Views |
|---|
| 464 | def red( str ) |
|---|
| 465 | require 'redcloth' |
|---|
| 466 | self << RedCloth.new( str ).to_html |
|---|
| 467 | end |
|---|
| 468 | |
|---|
| 469 | def layout |
|---|
| 470 | html do |
|---|
| 471 | head do |
|---|
| 472 | title "CampShell -- #{ @title }" |
|---|
| 473 | style "@import '#{ self / R(Style) }';", :type => 'text/css' |
|---|
| 474 | end |
|---|
| 475 | body do |
|---|
| 476 | div.container! do |
|---|
| 477 | div.content! do |
|---|
| 478 | h2 "CampShell" |
|---|
| 479 | h1 @title |
|---|
| 480 | _navigation |
|---|
| 481 | self << yield |
|---|
| 482 | end |
|---|
| 483 | end |
|---|
| 484 | end |
|---|
| 485 | end |
|---|
| 486 | end |
|---|
| 487 | |
|---|
| 488 | def _navigation |
|---|
| 489 | form :id => "navigationForm", :class => "navigation", :style => "font-size: 10px" do |
|---|
| 490 | [["Command List", R(List), "Alphabetical list of commands", "A"], |
|---|
| 491 | ["Recently Revised", R(Recent), "Pages sorted by when they were last changed", "U"], |
|---|
| 492 | ["Authors", R(Authors), "Who wrote what", "W"], |
|---|
| 493 | ["How To", R(HowTo), "How to use CampShell", "H"] |
|---|
| 494 | ].map do |txt, link, title, key| |
|---|
| 495 | a txt, :href => link, :title => title, :accesskey => key |
|---|
| 496 | end.join(" | ") |
|---|
| 497 | end |
|---|
| 498 | end |
|---|
| 499 | |
|---|
| 500 | def list |
|---|
| 501 | div.allCommands! :style => "width: 500px; margin: 0 100px" do |
|---|
| 502 | form.editForm! :action => R(New), :method => "post" do |
|---|
| 503 | ul do |
|---|
| 504 | if @cmds.each do |cmd| |
|---|
| 505 | li do |
|---|
| 506 | h2 { a cmd.name, :href => R(Show, cmd.name) } |
|---|
| 507 | red cmd.doc |
|---|
| 508 | end |
|---|
| 509 | end.empty? |
|---|
| 510 | h2 "No commands created yet." |
|---|
| 511 | end |
|---|
| 512 | |
|---|
| 513 | li do |
|---|
| 514 | text "Create command: " |
|---|
| 515 | input :type => "text", :name => "cmd", :id=> "newCmd", :value => "shortcut", |
|---|
| 516 | :onClick => "this.value == 'shortcut' ? this.value = '' : true" |
|---|
| 517 | end |
|---|
| 518 | end |
|---|
| 519 | end |
|---|
| 520 | end |
|---|
| 521 | end |
|---|
| 522 | |
|---|
| 523 | def authors |
|---|
| 524 | ul.authorList! do |
|---|
| 525 | @authors.each do |author, cmds| |
|---|
| 526 | li do |
|---|
| 527 | strong(author) + " worked on: " + |
|---|
| 528 | cmds.map { |cmd| a cmd.name, :href => R(Show, cmd.name) }.join(", ") |
|---|
| 529 | end |
|---|
| 530 | end |
|---|
| 531 | end |
|---|
| 532 | end |
|---|
| 533 | |
|---|
| 534 | def recent |
|---|
| 535 | @days.each do |day, cmds| |
|---|
| 536 | strong day |
|---|
| 537 | ul do |
|---|
| 538 | cmds.each do |cmd| |
|---|
| 539 | li do |
|---|
| 540 | a cmd.name, :href => R(Show, cmd.name) |
|---|
| 541 | div.byline "by #{ cmd.author } at #{ cmd.created_at.strftime("%H:%M") }" |
|---|
| 542 | end |
|---|
| 543 | end |
|---|
| 544 | end |
|---|
| 545 | end |
|---|
| 546 | end |
|---|
| 547 | |
|---|
| 548 | def show |
|---|
| 549 | h2 "Instructions" |
|---|
| 550 | red @version.doc |
|---|
| 551 | |
|---|
| 552 | h2 "Code" |
|---|
| 553 | if defined? SYNTAX |
|---|
| 554 | SYNTAX.convert(@version.code) |
|---|
| 555 | else |
|---|
| 556 | pre @version.code |
|---|
| 557 | end |
|---|
| 558 | |
|---|
| 559 | div.byline "Revised on #{ @version.created_at } by #{ @version.author }" |
|---|
| 560 | |
|---|
| 561 | div.navigation do |
|---|
| 562 | a "Edit Page", :href => R(Edit, @version.name, @version.version), |
|---|
| 563 | :class => "navlink", :accesskey => "E" |
|---|
| 564 | unless @version.version == 1 |
|---|
| 565 | text " | " |
|---|
| 566 | a 'Back in time', :href => R(Show, @version.name, @version.version-1) |
|---|
| 567 | end |
|---|
| 568 | unless @version.version == @cmd.version |
|---|
| 569 | text " | " |
|---|
| 570 | a 'Next', :href => R(Show, @version.name, @version.version+1) |
|---|
| 571 | text " | " |
|---|
| 572 | a 'Current', :href => R(Show, @version.name) |
|---|
| 573 | end |
|---|
| 574 | if @cmd.versions.size > 1 |
|---|
| 575 | small "(#{ @cmd.versions.size } revisions)" |
|---|
| 576 | end |
|---|
| 577 | end |
|---|
| 578 | end |
|---|
| 579 | |
|---|
| 580 | def edit |
|---|
| 581 | form :id => "editForm", :action => R(Edit, @cmd.name), :method => "post", :onSubmit => "cleanAuthorName();" do |
|---|
| 582 | div :style => "margin: 0 100px;" do |
|---|
| 583 | h2 "Instructions" |
|---|
| 584 | textarea @cmd.doc, :name => "command[doc]", :style => "width: 450px; height: 120px" |
|---|
| 585 | |
|---|
| 586 | h2 "Code" |
|---|
| 587 | textarea @cmd.code, :name => "command[code]", :style => "width: 450px; height: 380px" |
|---|
| 588 | |
|---|
| 589 | p do |
|---|
| 590 | input :type => "submit", :value => "Save"; text " as " |
|---|
| 591 | input :type => "text", :name => "command[author]", :id => "authorName", :value => @author, |
|---|
| 592 | :onClick => "this.value == '#{ CampSh::ANON }' ? this.value = '' : true"; text " | " |
|---|
| 593 | a "Cancel", :href => "/cancel_edit/#{ @cmd.name }" |
|---|
| 594 | end |
|---|
| 595 | end |
|---|
| 596 | |
|---|
| 597 | script <<-END, :language => "JavaScript1.2" |
|---|
| 598 | function cleanAuthorName() { |
|---|
| 599 | if (document.getElementById('authorName').value == "") { |
|---|
| 600 | document.getElementById('authorName').value = '#{ @anon }'; |
|---|
| 601 | } |
|---|
| 602 | } |
|---|
| 603 | END |
|---|
| 604 | end |
|---|
| 605 | end |
|---|
| 606 | |
|---|
| 607 | def howto |
|---|
| 608 | red %[ |
|---|
| 609 | Here's the rundown on CampShell. It's wiki-like storage for simple Ruby scripts. You can then run these scripts from |
|---|
| 610 | the URL. So, your job is to fill up CampShell with these commands, some of which can be found |
|---|
| 611 | "here":http://mousehole.rubyforge.org/wiki/wiki.pl?CampShells. |
|---|
| 612 | |
|---|
| 613 | h2. Using with Firefox |
|---|
| 614 | |
|---|
| 615 | For best effect, go to @about:config@ and set @keyword.URL@ to @http://#{env['HTTP_HOST']}#{self./ "/run/"}@. Restart Firefox, |
|---|
| 616 | you will then be able to run commands directly from the address bar. |
|---|
| 617 | |
|---|
| 618 | For example: |
|---|
| 619 | |
|---|
| 620 | * @new google@ will open the page for creating a new @google@ command. |
|---|
| 621 | * @show google@ will display the documentation for that command once it is saved. |
|---|
| 622 | * @edit google@ will open the editor for the @google@ command. |
|---|
| 623 | * @google mousehole commands@ will run the @google@ command with the arguments @mousehole@ and @commands@. |
|---|
| 624 | * @list all@ or @keyword:list@ displays all commands. |
|---|
| 625 | * @howto ?@ or @keyword:howto@ shoots you over to this page. |
|---|
| 626 | ].gsub(/^ +/, '') |
|---|
| 627 | end |
|---|
| 628 | end |
|---|
| 629 | |
|---|