Compare commits
161 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 714985e377 | |||
| 76c37dce96 | |||
| 5a9af40058 | |||
| e871ff35b7 | |||
| ecc6c32933 | |||
| 831cf61a08 | |||
| cc1231dece | |||
| bb3d1a165b | |||
| 3da0426c54 | |||
| e01aa25be3 | |||
| ee2f9d8dcb | |||
| 4d8677965c | |||
| 72729d5510 | |||
| 0b57e70c87 | |||
| 033d6489f8 | |||
| 8608007337 | |||
| 665e493570 | |||
| eb1e2f60f3 | |||
| dc637f0a9b | |||
| f81634728d | |||
| 440cd5ebc0 | |||
| 1cd7d0f205 | |||
| a69d62911c | |||
| 395e9bd006 | |||
| 90e20810d5 | |||
| 9c714e7687 | |||
| 6c3523d61c | |||
| 183840b793 | |||
| 4e2856aa64 | |||
| 4627a39165 | |||
| c87cbe83d2 | |||
| f05282badf | |||
| 957879346e | |||
| 87e64f67f3 | |||
| 43840d246d | |||
| 4aeb9af8a7 | |||
| b37acb8bc6 | |||
| 433865e927 | |||
| 5428161e0f | |||
| db0b536b5b | |||
| a4e50908fb | |||
| 96b89fe83d | |||
| adb131f131 | |||
| 757ab87e8a | |||
| f1d1db1159 | |||
| 3942bf60a6 | |||
| e2c0dcc0da | |||
| f63180d8d8 | |||
| 999bbf3d50 | |||
| eab612bdd0 | |||
| 1147186b4c | |||
| a88314e061 | |||
| 9221f5528d | |||
| 520f60cd65 | |||
| 84c85774e8 | |||
| 1f118deed9 | |||
| 55ce07ae73 | |||
| 85677d5e91 | |||
| 04f9be15b8 | |||
| 09cd72a829 | |||
| f5f5ad70e3 | |||
| a0774b320a | |||
| 4feea6051a | |||
| f548ea757b | |||
| abc8ea5280 | |||
| bacd2313fb | |||
| 63295d3f9b | |||
| 9c25eb20cf | |||
| 7f533f33ae | |||
| 352b4e1ed8 | |||
| 9a4252b579 | |||
| ed7011c229 | |||
| 4ddd6a5207 | |||
| 0a74c7cfd2 | |||
| d84fdc7599 | |||
| dac1268266 | |||
| b42db1c7c1 | |||
| 7a7a27c5c7 | |||
| af83186b10 | |||
| a8646f8fe7 | |||
| 01c1e30284 | |||
| b3980f9e39 | |||
| c9fd50d23e | |||
| ea3544f46d | |||
| 4e04f5f540 | |||
| b1021cf233 | |||
| 8fa3529123 | |||
| 3b494c235a | |||
| 1641c3e3e8 | |||
| ccd5d850ac | |||
| b989f160cf | |||
| 54e144564c | |||
| ab8599da6d | |||
| 0885702873 | |||
| 0083bc9302 | |||
| cbc0821928 | |||
| 7a70169d06 | |||
| bf2377ac11 | |||
| 1f79126b27 | |||
| 624e324383 | |||
| 846ebb285e | |||
| e567759935 | |||
| fe706c184e | |||
| 90bbb8e348 | |||
| e21ec540c2 | |||
| 2a4517ced4 | |||
| 8c8d151b3e | |||
| 44a3cf1934 | |||
| 5dcd3c8c8f | |||
| 251bd7cd3d | |||
| 02dfb0a8c1 | |||
| 544d499ab1 | |||
| 8ebc2f7079 | |||
| a31ba16070 | |||
| 60e3baad8a | |||
| f720a84831 | |||
| b74b2c4399 | |||
| 252aa10d75 | |||
| 6f3d362920 | |||
| 9b54e4c79f | |||
| f908d0d170 | |||
| 852ecdd1a9 | |||
| 78f5df5e56 | |||
| 580a61a515 | |||
| 4faf5a0150 | |||
| 1201d2434a | |||
| e1ca392da6 | |||
| 3ee6d22727 | |||
| 28a0329f65 | |||
| 2dc696c940 | |||
| e3acef0e91 | |||
| 62601f1adc | |||
| 982915a22f | |||
| 9f1bbd097f | |||
| 694bd6e74a | |||
| 394cf0bc8e | |||
| 09257deaae | |||
| 21c4b0dd95 | |||
| 3b4662b583 | |||
| 2e2e6457c7 | |||
| 631a7cccd6 | |||
| 2a3d51c7dc | |||
| e7e8a17b61 | |||
| 8fd8a56893 | |||
| 443c453507 | |||
| 0495c89ba1 | |||
| 78e4dfbece | |||
| 1c7a481ed9 | |||
| c3dedcbba5 | |||
| 1c767a0e9f | |||
| f3b0ba49e0 | |||
| 31dfcbaa9e | |||
| 8e11c5f46d | |||
| 70793ff559 | |||
| 6621e71e6c | |||
| 2af164ee9e | |||
| 9227f0a195 | |||
| f18330b494 | |||
| bb32339ab4 | |||
| ddf4378dfe | |||
| 2a607e209b |
@@ -1,7 +1,6 @@
|
|||||||
rvm:
|
rvm:
|
||||||
- 1.8.7
|
|
||||||
- 1.9.3
|
- 1.9.3
|
||||||
notifications:
|
- 2.0.0
|
||||||
disabled: true
|
|
||||||
before_install:
|
before_install:
|
||||||
- sudo apt-get update
|
- sudo apt-get update
|
||||||
|
- sudo apt-get install libicu-dev
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
gemspec
|
gemspec
|
||||||
gem 'rake', '~> 10.0.2'
|
gem 'rake', '~> 10.0.3'
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
# 2.4.11 / 2013-01-08
|
||||||
|
|
||||||
|
* Numerous security issues have been fixed. Please update to `2.4.11`
|
||||||
|
|
||||||
# 1.4.0 / 2012-04-10
|
# 1.4.0 / 2012-04-10
|
||||||
|
|
||||||
* Minor
|
* Minor
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
gollum -- A wiki built on top of Git
|
gollum -- A wiki built on top of Git
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
[](http://travis-ci.org/github/gollum)
|
[](http://rubygems.org/gems/gollum)
|
||||||
[](https://gemnasium.com/github/gollum)
|
[](http://travis-ci.org/gollum/gollum)
|
||||||
|
[](https://gemnasium.com/gollum/gollum)
|
||||||
|
|
||||||
## DESCRIPTION
|
## DESCRIPTION
|
||||||
|
|
||||||
@@ -20,21 +21,31 @@ Gollum follows the rules of [Semantic Versioning](http://semver.org/) and uses
|
|||||||
[TomDoc](http://tomdoc.org/) for inline documentation.
|
[TomDoc](http://tomdoc.org/) for inline documentation.
|
||||||
|
|
||||||
## SYSTEM REQUIREMENTS
|
## SYSTEM REQUIREMENTS
|
||||||
|
|
||||||
- Python 2.5+ (2.7.3 recommended)
|
- Python 2.5+ (2.7.3 recommended)
|
||||||
- Ruby 1.8.7+ (1.9.3 recommended)
|
- Ruby 1.8.7+ (1.9.3 recommended)
|
||||||
- Unix like operating system (OS X, Ubuntu, Debian, and more)
|
- Unix like operating system (OS X, Ubuntu, Debian, and more)
|
||||||
- Will not work on Windows (because of [grit](https://github.com/github/grit))
|
- Will not work on Windows (because of [grit](https://github.com/github/grit))
|
||||||
|
|
||||||
|
## SECURITY
|
||||||
|
|
||||||
|
Don't enable `--custom-css` or `--custom-js` unless you trust every user who has the ability to edit the wiki.
|
||||||
|
A better solution with more security is being tracked in [#665](https://github.com/gollum/gollum/issues/665).
|
||||||
|
|
||||||
## INSTALLATION
|
## INSTALLATION
|
||||||
|
|
||||||
The best way to install Gollum is with RubyGems:
|
The best way to install Gollum is with RubyGems:
|
||||||
|
|
||||||
$ [sudo] gem install gollum
|
```bash
|
||||||
|
$ [sudo] gem install gollum
|
||||||
|
```
|
||||||
|
|
||||||
If you're installing from source, you can use [Bundler][bundler] to pick up all the
|
If you're installing from source, you can use [Bundler][bundler] to pick up all the
|
||||||
gems:
|
gems:
|
||||||
|
|
||||||
$ bundle install
|
```bash
|
||||||
|
$ bundle install
|
||||||
|
```
|
||||||
|
|
||||||
In order to use the various formats that Gollum supports, you will need to
|
In order to use the various formats that Gollum supports, you will need to
|
||||||
separately install the necessary dependencies for each format. You only need
|
separately install the necessary dependencies for each format. You only need
|
||||||
@@ -43,7 +54,7 @@ to install the dependencies for the formats that you plan to use.
|
|||||||
* [ASCIIDoc](http://www.methods.co.nz/asciidoc/) -- `brew install asciidoc` on mac or `apt-get install -y asciidoc` on Ubuntu
|
* [ASCIIDoc](http://www.methods.co.nz/asciidoc/) -- `brew install asciidoc` on mac or `apt-get install -y asciidoc` on Ubuntu
|
||||||
* [Creole](http://wikicreole.org/) -- `gem install creole`
|
* [Creole](http://wikicreole.org/) -- `gem install creole`
|
||||||
* [Markdown](http://daringfireball.net/projects/markdown/) -- `gem install redcarpet`
|
* [Markdown](http://daringfireball.net/projects/markdown/) -- `gem install redcarpet`
|
||||||
* [GitHub Flavored Markdown](http://github.github.com/github-flavored-markdown/) -- `gem install github-markdown`
|
* [GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown) -- `gem install github-markdown`
|
||||||
* [Org](http://orgmode.org/) -- `gem install org-ruby`
|
* [Org](http://orgmode.org/) -- `gem install org-ruby`
|
||||||
* [Pod](http://search.cpan.org/dist/perl/pod/perlpod.pod) -- `Pod::Simple::HTML` comes with Perl >= 5.10. Lower versions should install Pod::Simple from CPAN.
|
* [Pod](http://search.cpan.org/dist/perl/pod/perlpod.pod) -- `Pod::Simple::HTML` comes with Perl >= 5.10. Lower versions should install Pod::Simple from CPAN.
|
||||||
* [RDoc](http://rdoc.sourceforge.net/)
|
* [RDoc](http://rdoc.sourceforge.net/)
|
||||||
@@ -53,508 +64,78 @@ to install the dependencies for the formats that you plan to use.
|
|||||||
|
|
||||||
[bundler]: http://gembundler.com/
|
[bundler]: http://gembundler.com/
|
||||||
|
|
||||||
|
|
||||||
|
## SYNTAX
|
||||||
|
|
||||||
|
Gollum supports a variety of formats and extensions (Markdown, MediaWiki, Textile, …).
|
||||||
|
On top of these formats Gollum lets you insert headers, footers, links, image, math and more.
|
||||||
|
|
||||||
|
Check out the [Gollum Wiki](https://github.com/gollum/gollum/wiki) for all of Gollum's formats and syntactic options.
|
||||||
|
|
||||||
|
|
||||||
## RUNNING
|
## RUNNING
|
||||||
|
|
||||||
To view and edit your Gollum repository locally via the built in web
|
To view and edit your Gollum repository locally via the built in web
|
||||||
interface, simply install the Gollum gem, navigate to your repository via the
|
interface, simply install the Gollum gem, navigate to your repository via the
|
||||||
command line, and run the executable:
|
command line, and run the executable:
|
||||||
|
|
||||||
$ gollum
|
```bash
|
||||||
|
$ gollum
|
||||||
|
```
|
||||||
|
|
||||||
This will start up a web server running the Gollum frontend and you can view
|
This will start up a web server running the Gollum frontend and you can view
|
||||||
and edit your wiki at http://localhost:4567. To get help on the command line
|
and edit your wiki at http://localhost:4567. To get help on the command line
|
||||||
utility, you can run it like so:
|
utility, you can run it like so:
|
||||||
|
|
||||||
$ gollum --help
|
```bash
|
||||||
|
$ gollum --help
|
||||||
|
```
|
||||||
|
|
||||||
Note that the gollum server will not run on Windows because of [an issue](https://github.com/rtomayko/posix-spawn/issues/9) with posix-spawn (which is used by Grit).
|
Note that the gollum server will not run on Windows because of [an issue](https://github.com/rtomayko/posix-spawn/issues/9) with posix-spawn (which is used by Grit).
|
||||||
|
|
||||||
## REPO STRUCTURE
|
|
||||||
|
|
||||||
A Gollum repository's contents are designed to be human editable. Page content
|
|
||||||
is written in `page files` and may be organized into directories any way you
|
|
||||||
choose. Special footers can be created in `footer files`. Other content
|
|
||||||
(images, PDFs, etc) may also be present and organized in the same way.
|
|
||||||
|
|
||||||
|
|
||||||
## PAGE FILES
|
|
||||||
|
|
||||||
Page files may be written in any format supported by
|
|
||||||
[GitHub-Markup](http://github.com/github/markup) (except roff). The
|
|
||||||
current list of formats and allowed extensions is:
|
|
||||||
|
|
||||||
* ASCIIDoc: .asciidoc
|
|
||||||
* Creole: .creole
|
|
||||||
* Markdown: .markdown, .mdown, .mkdn, .mkd, .md
|
|
||||||
* Org Mode: .org
|
|
||||||
* Pod: .pod
|
|
||||||
* RDoc: .rdoc
|
|
||||||
* ReStructuredText: .rest.txt, .rst.txt, .rest, .rst
|
|
||||||
* Textile: .textile
|
|
||||||
* MediaWiki: .mediawiki, .wiki
|
|
||||||
|
|
||||||
Gollum detects the page file format via the extension, so files must have one
|
|
||||||
of the supported extensions in order to be converted.
|
|
||||||
|
|
||||||
Page file names may contain any printable UTF-8 character except space
|
|
||||||
(U+0020) and forward slash (U+002F). If you commit a page file with any of
|
|
||||||
these characters in the name it will not be accessible via the web interface.
|
|
||||||
|
|
||||||
Even though page files may be placed in any directory, there is still only a
|
|
||||||
single namespace for page names, so all page files should have globally unique
|
|
||||||
names regardless of where they are located in the repository.
|
|
||||||
|
|
||||||
The special page file `Home.ext` (where the extension is one of the supported
|
|
||||||
formats) will be used as the entrance page to your wiki. If it is missing, an
|
|
||||||
automatically generated table of contents will be shown instead.
|
|
||||||
|
|
||||||
## SIDEBAR FILES
|
|
||||||
|
|
||||||
Sidebar files allow you to add a simple sidebar to your wiki. Sidebar files
|
|
||||||
are named `_Sidebar.ext` where the extension is one of the supported formats.
|
|
||||||
Sidebars affect all pages in their directory and any subdirectories that do not
|
|
||||||
have a sidebar file of their own.
|
|
||||||
|
|
||||||
## HEADER FILES
|
|
||||||
|
|
||||||
Header files allow you to add a simple header to your wiki. Header files must
|
|
||||||
be named `_Header.ext` where the extension is one of the supported formats.
|
|
||||||
Like sidebars, headers affect all pages in their directory and any
|
|
||||||
subdirectories that do not have a header file of their own.
|
|
||||||
|
|
||||||
## FOOTER FILES
|
|
||||||
|
|
||||||
Footer files allow you to add a simple footer to your wiki. Footer files must
|
|
||||||
be named `_Footer.ext` where the extension is one of the supported formats.
|
|
||||||
Like sidebars, footers affect all pages in their directory and any
|
|
||||||
subdirectories that do not have a footer file of their own.
|
|
||||||
|
|
||||||
## HTML SANITIZATION
|
|
||||||
|
|
||||||
For security and compatibility reasons Gollum wikis may not contain custom CSS
|
|
||||||
or JavaScript. These tags will be stripped from the converted HTML. See
|
|
||||||
`docs/sanitization.md` for more details on what tags and attributes are
|
|
||||||
allowed.
|
|
||||||
|
|
||||||
## TITLES
|
|
||||||
|
|
||||||
The first defined `h1` will override the default header on a page. There are two ways to set a page title. The metadata syntax:
|
|
||||||
|
|
||||||
`<!-- --- title: New Title -->`
|
|
||||||
|
|
||||||
The first `h1` tag can be set to always override the page title, without needing to use the metadata syntax. Start gollum with the `--h1-title` flag.
|
|
||||||
## BRACKET TAGS
|
|
||||||
|
|
||||||
A variety of Gollum tags use a double bracket syntax. For example:
|
|
||||||
|
|
||||||
[[Link]]
|
|
||||||
|
|
||||||
Some tags will accept attributes which are separated by pipe symbols. For
|
|
||||||
example:
|
|
||||||
|
|
||||||
[[Link|Page Title]]
|
|
||||||
|
|
||||||
In all cases, the first thing in the link is what is displayed on the page.
|
|
||||||
So, if the tag is an internal wiki link, the first thing in the tag will be
|
|
||||||
the link text displayed on the page. If the tag is an embedded image, the
|
|
||||||
first thing in the tag will be a path to an image file. Use this trick to
|
|
||||||
easily remember which order things should appear in tags.
|
|
||||||
|
|
||||||
Some formats, such as MediaWiki, support the opposite syntax:
|
|
||||||
|
|
||||||
[[Page Title|Link]]
|
|
||||||
|
|
||||||
## PAGE LINKS
|
|
||||||
|
|
||||||
To link to another Gollum wiki page, use the Gollum Page Link Tag.
|
|
||||||
|
|
||||||
[[Frodo Baggins]]
|
|
||||||
|
|
||||||
The above tag will create a link to the corresponding page file named
|
|
||||||
`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)
|
|
||||||
2. Replace any slashes (U+002F) with dashes (U+002D)
|
|
||||||
|
|
||||||
If you'd like the link text to be something that doesn't map directly to the
|
|
||||||
page name, you can specify the actual page name after a pipe:
|
|
||||||
|
|
||||||
[[Frodo|Frodo Baggins]]
|
|
||||||
|
|
||||||
The above tag will link to `Frodo-Baggins.ext` using "Frodo" as the link text.
|
|
||||||
|
|
||||||
The page file may exist anywhere in the directory structure of the repository.
|
|
||||||
Gollum does a breadth first search and uses the first match that it finds.
|
|
||||||
|
|
||||||
Here are a few more examples:
|
|
||||||
|
|
||||||
[[J. R. R. Tolkien]] -> J.-R.-R.-Tolkien.ext
|
|
||||||
[[Movies / The Hobbit]] -> Movies---The-Hobbit.ext
|
|
||||||
[[モルドール]] -> モルドール.ext
|
|
||||||
|
|
||||||
|
|
||||||
## EXTERNAL LINKS
|
|
||||||
|
|
||||||
As a convenience, simple external links can be placed within brackets and they
|
|
||||||
will be linked to the given URL with the URL as the link text. For example:
|
|
||||||
|
|
||||||
[[http://example.com]]
|
|
||||||
|
|
||||||
External links must begin with either "http://" or "https://". If you need
|
|
||||||
something more flexible, you can resort to the link syntax in the page's
|
|
||||||
underlying markup format.
|
|
||||||
|
|
||||||
|
|
||||||
## ABSOLUTE VS. RELATIVE VS. EXTERNAL PATH
|
|
||||||
|
|
||||||
For Gollum tags that operate on static files (images, PDFs, etc), the paths
|
|
||||||
may be referenced as either relative, absolute, or external. Relative paths
|
|
||||||
point to a static file relative to the page file within the directory
|
|
||||||
structure of the Gollum repo (even though after conversion, all page files
|
|
||||||
appear to be top level). These paths are NOT prefixed with a slash. For
|
|
||||||
example:
|
|
||||||
|
|
||||||
gollum.pdf
|
|
||||||
docs/diagram.png
|
|
||||||
|
|
||||||
Absolute paths point to a static file relative to the Gollum repo's
|
|
||||||
root, regardless of where the page file is stored within the directory
|
|
||||||
structure. These paths ARE prefixed with a slash. For example:
|
|
||||||
|
|
||||||
/pdfs/gollum.pdf
|
|
||||||
/docs/diagram.png
|
|
||||||
|
|
||||||
External paths are full URLs. An external path must begin with either
|
|
||||||
"http://" or "https://". For example:
|
|
||||||
|
|
||||||
http://example.com/pdfs/gollum.pdf
|
|
||||||
http://example.com/images/diagram.png
|
|
||||||
|
|
||||||
All of the examples in this README use relative paths, but you may use
|
|
||||||
whatever works best in your situation.
|
|
||||||
|
|
||||||
|
|
||||||
## FILE LINKS
|
|
||||||
|
|
||||||
To link to static files that are contained in the Gollum repository you should
|
|
||||||
use the Gollum File Link Tag.
|
|
||||||
|
|
||||||
[[Gollum|gollum.pdf]]
|
|
||||||
|
|
||||||
The first part of the tag is the link text. The path to the file appears after
|
|
||||||
the pipe.
|
|
||||||
|
|
||||||
|
|
||||||
## IMAGES
|
|
||||||
|
|
||||||
To display images that are contained in the Gollum repository you should use
|
|
||||||
the Gollum Image Tag. This will display the actual image on the page.
|
|
||||||
|
|
||||||
[[gollum.png]]
|
|
||||||
|
|
||||||
In addition to the simple format, there are a variety of options that you
|
|
||||||
can specify between pipe delimiters.
|
|
||||||
|
|
||||||
To specify alt text, use the `alt=` option. Default is no alt text.
|
|
||||||
|
|
||||||
[[gollum.png|alt=Gollum and his precious wiki]]
|
|
||||||
|
|
||||||
To place the image in a frame, use the `frame` option. When combined with the
|
|
||||||
`alt=` option, the alt text will be used as a caption as well. Default is no
|
|
||||||
frame.
|
|
||||||
|
|
||||||
[[gollum.png|frame|alt=Gollum and his precious wiki]]
|
|
||||||
|
|
||||||
To specify the alignment of the image on the page, use the `align=` option.
|
|
||||||
Possible values are `left`, `center`, and `right`. Default is `left`.
|
|
||||||
|
|
||||||
[[gollum.png|align=center]]
|
|
||||||
|
|
||||||
To float an image so that text flows around it, use the `float` option. When
|
|
||||||
`float` is specified, only `left` and `right` are valid `align` options.
|
|
||||||
Default is not floating. When floating is activated but no alignment is
|
|
||||||
specified, default alignment is `left`.
|
|
||||||
|
|
||||||
[[gollum.png|float]]
|
|
||||||
|
|
||||||
To specify a max-width, use the `width=` option. Units must be specified in
|
|
||||||
either `px` or `em`.
|
|
||||||
|
|
||||||
[[gollum.png|width=400px]]
|
|
||||||
|
|
||||||
To specify a max-height, use the `height=` option. Units must be specified in
|
|
||||||
either `px` or `em`.
|
|
||||||
|
|
||||||
[[gollum.png|height=300px]]
|
|
||||||
|
|
||||||
Any of these options may be composed together by simply separating them with
|
|
||||||
pipes.
|
|
||||||
|
|
||||||
|
|
||||||
## ESCAPING GOLLUM TAGS
|
|
||||||
|
|
||||||
If you need the literal text of a wiki or static link to show up in your final
|
|
||||||
wiki page, simply preface the link with a single quote (like in LISP):
|
|
||||||
|
|
||||||
'[[Page Link]]
|
|
||||||
'[[File Link|file.pdf]]
|
|
||||||
'[[image.jpg]]
|
|
||||||
|
|
||||||
This is useful for writing about the link syntax in your wiki pages.
|
|
||||||
|
|
||||||
## TABLE OF CONTENTS
|
|
||||||
|
|
||||||
Gollum has a special tag to insert a table of contents (new in v2.1)
|
|
||||||
|
|
||||||
[[_TOC_]]
|
|
||||||
|
|
||||||
This tag is case sensitive, use all upper case. The TOC tag can be inserted
|
|
||||||
into the `_Header`, `_Footer` or `_Sidebar` files too.
|
|
||||||
|
|
||||||
There is also a wiki option `:universal_toc` which will display a
|
|
||||||
table of contents at the top of all your wiki pages if it is enabled.
|
|
||||||
The `:universal_toc` is not enabled by default. To set the option,
|
|
||||||
add the option to the `:wiki_options` hash before starting the
|
|
||||||
frontend app:
|
|
||||||
|
|
||||||
Precious::App.set(:wiki_options, {:universal_toc => true})
|
|
||||||
|
|
||||||
## SYNTAX HIGHLIGHTING
|
|
||||||
|
|
||||||
In page files you can get automatic syntax highlighting for a wide range of
|
|
||||||
languages (courtesy of [Pygments](http://pygments.org/) - must install
|
|
||||||
separately) by using the following syntax:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
def foo
|
|
||||||
puts 'bar'
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
The block must start with three backticks, at the beginning of a line or
|
|
||||||
indented with any number of spaces or tabs.
|
|
||||||
After that comes the name of the language that is contained by the
|
|
||||||
block. The language must be one of the `short name` lexer strings supported by
|
|
||||||
Pygments. See the [list of lexers](http://pygments.org/docs/lexers/) for valid
|
|
||||||
options.
|
|
||||||
|
|
||||||
The block contents should be indented at the same level than the opening backticks.
|
|
||||||
If the block contents are indented with an additional two spaces or one tab,
|
|
||||||
then that whitespace will be ignored (this makes the blocks easier to read in plaintext).
|
|
||||||
|
|
||||||
The block must end with three backticks indented at the same level than the opening
|
|
||||||
backticks.
|
|
||||||
|
|
||||||
### GITHUB SYNTAX HIGHLIGHTING
|
|
||||||
|
|
||||||
As an extra feature, you can syntax highlight a file from your repository, allowing
|
|
||||||
you keep some of your sample code in the main repository. The code-snippet is
|
|
||||||
updated when the wiki is rebuilt. You include github code like this:
|
|
||||||
|
|
||||||
```html:github/gollum/master/test/file_view/1_file.txt```
|
|
||||||
|
|
||||||
This will make the builder look at the **github user**, in the **gollum project**,
|
|
||||||
in the **master branch**, at path **test/file_view/1_file.txt**. It will be
|
|
||||||
rewritten to:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<ol class="tree">
|
|
||||||
<li class="file"><a href="0">0</a></li>
|
|
||||||
</ol>
|
|
||||||
```
|
|
||||||
|
|
||||||
Which will be parsed as HTML code during the Pygments run, and thereby coloured
|
|
||||||
appropriately.
|
|
||||||
|
|
||||||
## MATHEMATICAL EQUATIONS
|
|
||||||
|
|
||||||
Start gollum with the `--mathjax` flag. Read more about [MathJax](http://docs.mathjax.org/en/latest/index.html) on the web. Gollum uses the `TeX-AMS-MML_HTMLorMML` config with the `autoload-all` extension.
|
|
||||||
|
|
||||||
Inline math:
|
|
||||||
|
|
||||||
- $2^2$
|
|
||||||
- `\\(2^2\\)`
|
|
||||||
|
|
||||||
Display math:
|
|
||||||
|
|
||||||
- $$2^2$$
|
|
||||||
- [2^2]
|
|
||||||
|
|
||||||
## SEQUENCE DIAGRAMS
|
|
||||||
|
|
||||||
You may imbed sequence diagrams into your wiki page (rendered by
|
|
||||||
[WebSequenceDiagrams](http://www.websequencediagrams.com) by using the
|
|
||||||
following syntax:
|
|
||||||
|
|
||||||
{{{{{{ blue-modern
|
|
||||||
alice->bob: Test
|
|
||||||
bob->alice: Test response
|
|
||||||
}}}}}}
|
|
||||||
|
|
||||||
You can replace the string "blue-modern" with any supported style.
|
|
||||||
|
|
||||||
## API DOCUMENTATION
|
|
||||||
|
|
||||||
The Gollum API allows you to retrieve raw or formatted wiki content from a Git
|
|
||||||
repository, write new content to the repository, and collect various meta data
|
|
||||||
about the wiki as a whole.
|
|
||||||
|
|
||||||
Initialize the Gollum::Repo object:
|
|
||||||
|
|
||||||
# Require rubygems if necessary
|
|
||||||
require 'rubygems'
|
|
||||||
|
|
||||||
# Require the Gollum library
|
|
||||||
require 'gollum'
|
|
||||||
|
|
||||||
# Create a new Gollum::Wiki object by initializing it with the path to the
|
|
||||||
# Git repository.
|
|
||||||
wiki = Gollum::Wiki.new("my-gollum-repo.git")
|
|
||||||
# => <Gollum::Wiki>
|
|
||||||
|
|
||||||
By default, internal wiki links are all absolute from the root. To specify a different base path, you can specify the `:base_path` option:
|
|
||||||
|
|
||||||
wiki = Gollum::Wiki.new("my-gollum-repo.git", :base_path => "/wiki")
|
|
||||||
|
|
||||||
Note that base_path just modifies the links. To map gollum to a non-root location:
|
|
||||||
|
|
||||||
- Use the gollum binary: `gollum path/to/wiki --base-path mywiki`
|
|
||||||
- Define config.ru with `map`. See [#532](https://github.com/github/gollum/issues/532) for an example.
|
|
||||||
|
|
||||||
> :base_path - String base path for all Wiki links.
|
|
||||||
>
|
|
||||||
> 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 "/".
|
|
||||||
|
|
||||||
Get the latest version of the given human or canonical page name:
|
|
||||||
|
|
||||||
page = wiki.page('page-name')
|
|
||||||
# => <Gollum::Page>
|
|
||||||
|
|
||||||
page.raw_data
|
|
||||||
# => "# My wiki page"
|
|
||||||
|
|
||||||
page.formatted_data
|
|
||||||
# => "<h1>My wiki page</h1>"
|
|
||||||
|
|
||||||
page.format
|
|
||||||
# => :markdown
|
|
||||||
|
|
||||||
vsn = page.version
|
|
||||||
# => <Grit::Commit>
|
|
||||||
|
|
||||||
vsn.id
|
|
||||||
# => '3ca43e12377ea1e32ea5c9ce5992ec8bf266e3e5'
|
|
||||||
|
|
||||||
Get the footer (if any) for a given page:
|
|
||||||
|
|
||||||
page.footer
|
|
||||||
# => <Gollum::Page>
|
|
||||||
|
|
||||||
Get the header (if any) for a given page:
|
|
||||||
|
|
||||||
page.header
|
|
||||||
# => <Gollum::Page>
|
|
||||||
|
|
||||||
Get a list of versions for a given page:
|
|
||||||
|
|
||||||
vsns = wiki.page('page-name').versions
|
|
||||||
# => [<Grit::Commit, <Grit::Commit, <Grit::Commit>]
|
|
||||||
|
|
||||||
vsns.first.id
|
|
||||||
# => '3ca43e12377ea1e32ea5c9ce5992ec8bf266e3e5'
|
|
||||||
|
|
||||||
vsns.first.authored_date
|
|
||||||
# => Sun Mar 28 19:11:21 -0700 2010
|
|
||||||
|
|
||||||
Get a specific version of a given canonical page file:
|
|
||||||
|
|
||||||
wiki.page('page-name', '5ec521178e0eec4dc39741a8978a2ba6616d0f0a')
|
|
||||||
|
|
||||||
Get the latest version of a given static file:
|
|
||||||
|
|
||||||
file = wiki.file('asset.js')
|
|
||||||
# => <Gollum::File>
|
|
||||||
|
|
||||||
file.raw_data
|
|
||||||
# => "alert('hello');"
|
|
||||||
|
|
||||||
file.version
|
|
||||||
# => <Grit::Commit>
|
|
||||||
|
|
||||||
Get a specific version of a given static file:
|
|
||||||
|
|
||||||
wiki.file('asset.js', '5ec521178e0eec4dc39741a8978a2ba6616d0f0a')
|
|
||||||
|
|
||||||
Get an in-memory Page preview (useful for generating previews for web
|
|
||||||
interfaces):
|
|
||||||
|
|
||||||
preview = wiki.preview_page("My Page", "# Contents", :markdown)
|
|
||||||
preview.formatted_data
|
|
||||||
# => "<h1>Contents</h1>"
|
|
||||||
|
|
||||||
Methods that write to the repository require a Hash of commit data that takes
|
|
||||||
the following form:
|
|
||||||
|
|
||||||
commit = { :message => 'commit message',
|
|
||||||
:name => 'Tom Preston-Werner',
|
|
||||||
:email => 'tom@github.com' }
|
|
||||||
|
|
||||||
Write a new version of a page (the file will be created if it does not already
|
|
||||||
exist) and commit the change. The file will be written at the repo root.
|
|
||||||
|
|
||||||
wiki.write_page('Page Name', :markdown, 'Page contents', commit)
|
|
||||||
|
|
||||||
Update an existing page. If the format is different than the page's current
|
|
||||||
format, the file name will be changed to reflect the new format.
|
|
||||||
|
|
||||||
page = wiki.page('Page Name')
|
|
||||||
wiki.update_page(page, page.name, page.format, 'Page contents', commit)
|
|
||||||
|
|
||||||
To delete a page and commit the change:
|
|
||||||
|
|
||||||
wiki.delete_page(page, commit)
|
|
||||||
|
|
||||||
### RACK
|
### RACK
|
||||||
|
|
||||||
You can also run gollum with any rack-compatible server by placing this config.ru
|
You can also run gollum with any rack-compatible server by placing this config.ru
|
||||||
file inside your wiki repository. This allows you to utilize any Rack middleware
|
file inside your wiki repository. This allows you to utilize any Rack middleware
|
||||||
like Rack::Auth, OmniAuth, etc.
|
like Rack::Auth, OmniAuth, etc.
|
||||||
|
|
||||||
#!/usr/bin/env ruby
|
```ruby
|
||||||
require 'rubygems'
|
#!/usr/bin/env ruby
|
||||||
require 'gollum/frontend/app'
|
require 'rubygems'
|
||||||
|
require 'gollum/app'
|
||||||
|
|
||||||
gollum_path = File.expand_path(File.dirname(__FILE__)) # CHANGE THIS TO POINT TO YOUR OWN WIKI REPO
|
gollum_path = File.expand_path(File.dirname(__FILE__)) # CHANGE THIS TO POINT TO YOUR OWN WIKI REPO
|
||||||
Precious::App.set(:gollum_path, gollum_path)
|
Precious::App.set(:gollum_path, gollum_path)
|
||||||
Precious::App.set(:default_markup, :markdown) # set your favorite markup language
|
Precious::App.set(:default_markup, :markdown) # set your favorite markup language
|
||||||
Precious::App.set(:wiki_options, {:universal_toc => false})
|
Precious::App.set(:wiki_options, {:universal_toc => false})
|
||||||
run Precious::App
|
run Precious::App
|
||||||
|
```
|
||||||
|
|
||||||
Your Rack middleware can pass author details to Gollum in a Hash in the session under the 'gollum.author' key.
|
Your Rack middleware can pass author details to Gollum in a Hash in the session under the 'gollum.author' key.
|
||||||
|
|
||||||
## WINDOWS FILENAME VALIDATION
|
|
||||||
Note that filenames on windows must not contain any of the following characters `\ / : * ? " < > |`. See [this support article](http://support.microsoft.com/kb/177506) for details.
|
|
||||||
|
|
||||||
## CONFIG FILE
|
## CONFIG FILE
|
||||||
|
|
||||||
Gollum optionally takes a `--config file`. See [config.rb](https://github.com/github/gollum/blob/master/config.rb) for an example.
|
Gollum optionally takes a `--config file`. See [config.rb](https://github.com/gollum/gollum/blob/master/config.rb) for an example.
|
||||||
|
|
||||||
## CUSTOM CSS
|
## CUSTOM CSS/JS
|
||||||
|
|
||||||
The `--css` flag will inject `custom.css` from the root of your git repository into each page. `custom.css` must be commited to git or you will get a 302 redirect to the create page. Here's an example of floating the sidebar to the left.
|
The `--css` flag will inject `custom.css` from the root of your git repository into each page. `custom.css` must be commited to git or you will get a 302 redirect to the create page.
|
||||||
|
|
||||||
|
The `--js` flag will inject `custom.js` from the root of your git repository into each page. `custom.js` must be commited to git or you will get a 302 redirect to the create page.
|
||||||
|
|
||||||
|
|
||||||
|
## API DOCUMENTATION
|
||||||
|
|
||||||
|
The [Gollum API](https://github.com/gollum/gollum-lib/) allows you to retrieve
|
||||||
|
raw or formatted wiki content from a Git repository, write new content to the
|
||||||
|
repository, and collect various meta data about the wiki as a whole.
|
||||||
|
|
||||||
```css
|
|
||||||
#wiki-rightbar { float: left !important; }
|
|
||||||
```
|
|
||||||
|
|
||||||
## CONTRIBUTE
|
## CONTRIBUTE
|
||||||
|
|
||||||
If you'd like to hack on Gollum, start by forking my repo on GitHub:
|
If you'd like to hack on Gollum, start by forking the repo on GitHub:
|
||||||
|
|
||||||
http://github.com/github/gollum
|
http://github.com/gollum/gollum
|
||||||
|
|
||||||
To get all of the dependencies, install the gem first. The best way to get
|
To get all of the dependencies, install the gem first. The best way to get
|
||||||
your changes merged back into core is as follows:
|
your changes merged back into core is as follows:
|
||||||
@@ -567,23 +148,57 @@ your changes merged back into core is as follows:
|
|||||||
1. Do not change the version number, I will do that on my end
|
1. Do not change the version number, I will do that on my end
|
||||||
1. If necessary, rebase your commits into logical chunks, without errors
|
1. If necessary, rebase your commits into logical chunks, without errors
|
||||||
1. Push the branch up to GitHub
|
1. Push the branch up to GitHub
|
||||||
1. Send a pull request to the github/gollum project.
|
1. Send a pull request to the gollum/gollum project.
|
||||||
|
|
||||||
## RELEASING
|
## RELEASING
|
||||||
|
|
||||||
|
Gollum uses [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
x.y.z
|
x.y.z
|
||||||
|
|
||||||
For z releases:
|
For z releases:
|
||||||
$ rake bump
|
|
||||||
$ rake release
|
```bash
|
||||||
|
$ rake bump
|
||||||
|
$ rake release
|
||||||
|
```
|
||||||
|
|
||||||
|
For x.y releases:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Update VERSION in lib/gollum.rb
|
||||||
|
$ rake gemspec
|
||||||
|
$ rake release
|
||||||
|
```
|
||||||
|
|
||||||
For x.y releases:
|
|
||||||
Update VERSION in lib/gollum.rb
|
|
||||||
$ rake gemspec
|
|
||||||
$ rake release
|
|
||||||
|
|
||||||
## BUILDING THE GEM FROM MASTER
|
## BUILDING THE GEM FROM MASTER
|
||||||
$ gem uninstall -aIx gollum
|
|
||||||
$ git clone https://github.com/github/gollum.git
|
```bash
|
||||||
$ cd gollum
|
$ gem uninstall -aIx gollum
|
||||||
gollum$ rake build
|
$ git clone https://github.com/gollum/gollum.git
|
||||||
gollum$ gem install --no-ri --no-rdoc pkg/gollum*.gem
|
$ cd gollum
|
||||||
|
gollum$ rake build
|
||||||
|
gollum$ gem install --no-ri --no-rdoc pkg/gollum*.gem
|
||||||
|
```
|
||||||
|
|
||||||
|
## RUN THE TESTS
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ bundle install
|
||||||
|
$ bundle exec rake test
|
||||||
|
```
|
||||||
|
|
||||||
|
## WORK WITH TEST REPOS
|
||||||
|
|
||||||
|
An example of how to add a test file to the bare repository lotr.git.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ mkdir tmp; cd tmp
|
||||||
|
$ git clone ../lotr.git/ .
|
||||||
|
Cloning into '.'...
|
||||||
|
done.
|
||||||
|
$ git log
|
||||||
|
$ echo "test" > test.md
|
||||||
|
$ git add . ; git commit -am "Add test"
|
||||||
|
$ git push ../lotr.git/ master
|
||||||
|
```
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ require 'gollum'
|
|||||||
|
|
||||||
exec = {}
|
exec = {}
|
||||||
options = { 'port' => 4567, 'bind' => '0.0.0.0' }
|
options = { 'port' => 4567, 'bind' => '0.0.0.0' }
|
||||||
wiki_options = {}
|
wiki_options = {
|
||||||
|
:live_preview => false,
|
||||||
|
:allow_uploads => false,
|
||||||
|
}
|
||||||
|
|
||||||
opts = OptionParser.new do |opts|
|
opts = OptionParser.new do |opts|
|
||||||
opts.banner = help
|
opts.banner = help
|
||||||
@@ -49,6 +52,10 @@ opts = OptionParser.new do |opts|
|
|||||||
wiki_options[:css] = true
|
wiki_options[:css] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
opts.on("--js", "Inject custom js. Uses custom.js from root repository") do
|
||||||
|
wiki_options[:js] = true
|
||||||
|
end
|
||||||
|
|
||||||
opts.on("--page-file-dir [PATH]", "Specify the sub directory for all page files (default: repository root).") do |path|
|
opts.on("--page-file-dir [PATH]", "Specify the sub directory for all page files (default: repository root).") do |path|
|
||||||
wiki_options[:page_file_dir] = path
|
wiki_options[:page_file_dir] = path
|
||||||
end
|
end
|
||||||
@@ -69,6 +76,14 @@ opts = OptionParser.new do |opts|
|
|||||||
wiki_options[:live_preview] = false
|
wiki_options[:live_preview] = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
opts.on("--live-preview", "Enables livepreview.") do
|
||||||
|
wiki_options[:live_preview] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on("--allow-uploads", "Allows file uploads.") do
|
||||||
|
wiki_options[:allow_uploads] = true
|
||||||
|
end
|
||||||
|
|
||||||
opts.on("--mathjax", "Enables mathjax.") do
|
opts.on("--mathjax", "Enables mathjax.") do
|
||||||
wiki_options[:mathjax] = true
|
wiki_options[:mathjax] = true
|
||||||
end
|
end
|
||||||
@@ -129,8 +144,9 @@ if options['irb']
|
|||||||
end
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
require 'gollum-lib'
|
||||||
wiki = Gollum::Wiki.new(gollum_path, wiki_options)
|
wiki = Gollum::Wiki.new(gollum_path, wiki_options)
|
||||||
if !wiki.exist? then raise Grit::InvalidGitRepositoryError end
|
if !wiki.exist? then raise Gollum::InvalidGitRepositoryError end
|
||||||
puts "Loaded Gollum wiki at #{File.expand_path(gollum_path).inspect}."
|
puts "Loaded Gollum wiki at #{File.expand_path(gollum_path).inspect}."
|
||||||
puts
|
puts
|
||||||
puts %( page = wiki.page('page-name'))
|
puts %( page = wiki.page('page-name'))
|
||||||
@@ -144,12 +160,12 @@ if options['irb']
|
|||||||
puts
|
puts
|
||||||
puts "Check out the Gollum README for more."
|
puts "Check out the Gollum README for more."
|
||||||
IRB.start_session(binding)
|
IRB.start_session(binding)
|
||||||
rescue Grit::InvalidGitRepositoryError, Grit::NoSuchPathError
|
rescue Gollum::InvalidGitRepositoryError, Gollum::NoSuchPathError
|
||||||
puts "Invalid Gollum wiki at #{File.expand_path(gollum_path).inspect}"
|
puts "Invalid Gollum wiki at #{File.expand_path(gollum_path).inspect}"
|
||||||
exit 0
|
exit 0
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
require 'gollum/frontend/app'
|
require 'gollum/app'
|
||||||
Precious::App.set(:gollum_path, gollum_path)
|
Precious::App.set(:gollum_path, gollum_path)
|
||||||
Precious::App.set(:wiki_options, wiki_options)
|
Precious::App.set(:wiki_options, wiki_options)
|
||||||
|
|
||||||
|
|||||||
@@ -5,33 +5,21 @@ require 'digest/sha1'
|
|||||||
require 'ostruct'
|
require 'ostruct'
|
||||||
|
|
||||||
# external
|
# external
|
||||||
require 'grit'
|
|
||||||
require 'github/markup'
|
require 'github/markup'
|
||||||
require 'sanitize'
|
require 'sanitize'
|
||||||
|
|
||||||
# internal
|
# internal
|
||||||
require File.expand_path('../gollum/git_access', __FILE__)
|
require File.expand_path('../gollum/uri_encode_component', __FILE__)
|
||||||
require File.expand_path('../gollum/committer', __FILE__)
|
|
||||||
require File.expand_path('../gollum/pagination', __FILE__)
|
|
||||||
require File.expand_path('../gollum/blob_entry', __FILE__)
|
|
||||||
require File.expand_path('../gollum/wiki', __FILE__)
|
|
||||||
require File.expand_path('../gollum/page', __FILE__)
|
|
||||||
require File.expand_path('../gollum/file', __FILE__)
|
|
||||||
require File.expand_path('../gollum/file_view', __FILE__)
|
|
||||||
require File.expand_path('../gollum/markup', __FILE__)
|
|
||||||
require File.expand_path('../gollum/sanitization', __FILE__)
|
|
||||||
require File.expand_path('../gollum/web_sequence_diagram', __FILE__)
|
|
||||||
require File.expand_path('../gollum/frontend/uri_encode_component', __FILE__)
|
|
||||||
|
|
||||||
# Set ruby to UTF-8 mode
|
# Set ruby to UTF-8 mode
|
||||||
# This is required for Ruby 1.8.7 which gollum still supports.
|
# This is required for Ruby 1.8.7 which gollum still supports.
|
||||||
$KCODE = 'U' if RUBY_VERSION[0,3] == '1.8'
|
$KCODE = 'U' if RUBY_VERSION[0,3] == '1.8'
|
||||||
|
|
||||||
module Gollum
|
module Gollum
|
||||||
VERSION = '2.4.6'
|
VERSION = '2.5.2'
|
||||||
|
|
||||||
def self.assets_path
|
def self.assets_path
|
||||||
::File.expand_path('gollum/frontend/public', ::File.dirname(__FILE__))
|
::File.expand_path('gollum/public', ::File.dirname(__FILE__))
|
||||||
end
|
end
|
||||||
|
|
||||||
class Error < StandardError; end
|
class Error < StandardError; end
|
||||||
|
|||||||
@@ -1,24 +1,29 @@
|
|||||||
# ~*~ encoding: utf-8 ~*~
|
# ~*~ encoding: utf-8 ~*~
|
||||||
require 'cgi'
|
require 'cgi'
|
||||||
require 'sinatra'
|
require 'sinatra'
|
||||||
require 'gollum'
|
require 'gollum-lib'
|
||||||
require 'mustache/sinatra'
|
require 'mustache/sinatra'
|
||||||
require 'useragent'
|
require 'useragent'
|
||||||
require 'stringex'
|
require 'stringex'
|
||||||
|
|
||||||
require 'gollum/frontend/views/layout'
|
require 'gollum'
|
||||||
require 'gollum/frontend/views/editable'
|
require 'gollum/views/layout'
|
||||||
require 'gollum/frontend/views/has_page'
|
require 'gollum/views/editable'
|
||||||
|
require 'gollum/views/has_page'
|
||||||
|
|
||||||
require File.expand_path '../helpers', __FILE__
|
require File.expand_path '../helpers', __FILE__
|
||||||
|
|
||||||
|
#required to upload bigger binary files
|
||||||
|
Gollum::set_git_timeout(120)
|
||||||
|
Gollum::set_git_max_filesize(190 * 10**6)
|
||||||
|
|
||||||
# Fix to_url
|
# Fix to_url
|
||||||
class String
|
class String
|
||||||
alias :upstream_to_url :to_url
|
alias :upstream_to_url :to_url
|
||||||
# _Header => header which causes errors
|
# _Header => header which causes errors
|
||||||
def to_url
|
def to_url
|
||||||
return nil if self.nil?
|
return nil if self.nil?
|
||||||
upstream_to_url :exclude => ['_Header', '_Footer', '_Sidebar']
|
upstream_to_url :exclude => ['_Header', '_Footer', '_Sidebar'], :force_downcase => false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -27,7 +32,7 @@ end
|
|||||||
# There are a number of wiki options that can be set for the frontend
|
# There are a number of wiki options that can be set for the frontend
|
||||||
#
|
#
|
||||||
# Example
|
# Example
|
||||||
# require 'gollum/frontend/app'
|
# require 'gollum/app'
|
||||||
# Precious::App.set(:wiki_options, {
|
# Precious::App.set(:wiki_options, {
|
||||||
# :universal_toc => false,
|
# :universal_toc => false,
|
||||||
# }
|
# }
|
||||||
@@ -85,10 +90,12 @@ module Precious
|
|||||||
# above will detect base_path when it's used with map in a config.ru
|
# above will detect base_path when it's used with map in a config.ru
|
||||||
settings.wiki_options.merge!({ :base_path => @base_url })
|
settings.wiki_options.merge!({ :base_path => @base_url })
|
||||||
@css = settings.wiki_options[:css]
|
@css = settings.wiki_options[:css]
|
||||||
|
@js = settings.wiki_options[:js]
|
||||||
end
|
end
|
||||||
|
|
||||||
get '/' do
|
get '/' do
|
||||||
redirect ::File.join(@base_url, 'Home')
|
page_dir = settings.wiki_options[:page_file_dir].to_s
|
||||||
|
redirect clean_url(::File.join(@base_url, page_dir, wiki_new.index_page))
|
||||||
end
|
end
|
||||||
|
|
||||||
# path is set to name if path is nil.
|
# path is set to name if path is nil.
|
||||||
@@ -97,13 +104,13 @@ module Precious
|
|||||||
# extract_path will trim path to 'a'
|
# extract_path will trim path to 'a'
|
||||||
# name, path, version
|
# name, path, version
|
||||||
def wiki_page(name, path = nil, version = nil, exact = true)
|
def wiki_page(name, path = nil, version = nil, exact = true)
|
||||||
|
wiki = wiki_new
|
||||||
|
|
||||||
path = name if path.nil?
|
path = name if path.nil?
|
||||||
name = extract_name(name)
|
name = extract_name(name) || wiki.index_page
|
||||||
path = extract_path(path)
|
path = extract_path(path)
|
||||||
path = '/' if exact && path.nil?
|
path = '/' if exact && path.nil?
|
||||||
|
|
||||||
wiki = wiki_new
|
|
||||||
|
|
||||||
OpenStruct.new(:wiki => wiki, :page => wiki.paged(name, path, exact, version),
|
OpenStruct.new(:wiki => wiki, :page => wiki.paged(name, path, exact, version),
|
||||||
:name => name, :path => path)
|
:name => name, :path => path)
|
||||||
end
|
end
|
||||||
@@ -122,6 +129,7 @@ module Precious
|
|||||||
wikip = wiki_page(params[:splat].first)
|
wikip = wiki_page(params[:splat].first)
|
||||||
@name = wikip.name
|
@name = wikip.name
|
||||||
@path = wikip.path
|
@path = wikip.path
|
||||||
|
|
||||||
wiki = wikip.wiki
|
wiki = wikip.wiki
|
||||||
if page = wikip.page
|
if page = wikip.page
|
||||||
if wiki.live_preview && page.format.to_s.include?('markdown') && supported_useragent?(request.user_agent)
|
if wiki.live_preview && page.format.to_s.include?('markdown') && supported_useragent?(request.user_agent)
|
||||||
@@ -133,8 +141,7 @@ module Precious
|
|||||||
else
|
else
|
||||||
@page = page
|
@page = page
|
||||||
@page.version = wiki.repo.log(wiki.ref, @page.path).first
|
@page.version = wiki.repo.log(wiki.ref, @page.path).first
|
||||||
raw_data = page.raw_data
|
@content = page.text_data
|
||||||
@content = raw_data.respond_to?(:force_encoding) ? raw_data.force_encoding('UTF-8') : raw_data
|
|
||||||
mustache :edit
|
mustache :edit
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -142,25 +149,104 @@ module Precious
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
post '/uploadFile' do
|
||||||
|
wiki = wiki_new
|
||||||
|
|
||||||
|
unless wiki.allow_uploads
|
||||||
|
@message = "File uploads are disabled"
|
||||||
|
mustache :error
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if params[:file]
|
||||||
|
fullname = params[:file][:filename]
|
||||||
|
tempfile = params[:file][:tempfile]
|
||||||
|
end
|
||||||
|
|
||||||
|
dir = 'uploads'
|
||||||
|
ext = ::File.extname(fullname)
|
||||||
|
format = ext.split('.').last || 'txt'
|
||||||
|
filename = ::File.basename(fullname, ext)
|
||||||
|
contents = ::File.read(tempfile)
|
||||||
|
reponame = filename + '.' + format
|
||||||
|
|
||||||
|
head = wiki.repo.head
|
||||||
|
|
||||||
|
options = {
|
||||||
|
:message => "Uploaded file to uploads/#{reponame}",
|
||||||
|
:parent => wiki.repo.head.commit,
|
||||||
|
}
|
||||||
|
author = session['gollum.author']
|
||||||
|
unless author.nil?
|
||||||
|
options.merge! author
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
committer = Gollum::Committer.new(wiki, options)
|
||||||
|
committer.add_to_index(dir, filename, format, contents)
|
||||||
|
committer.after_commit do |committer, sha|
|
||||||
|
wiki.clear_cache
|
||||||
|
committer.update_working_dir(dir, filename, format)
|
||||||
|
end
|
||||||
|
committer.commit
|
||||||
|
redirect to('/')
|
||||||
|
rescue Gollum::DuplicatePageError => e
|
||||||
|
@message = "Duplicate page: #{e.message}"
|
||||||
|
mustache :error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
post '/rename/*' do
|
||||||
|
wikip = wiki_page(params[:splat].first)
|
||||||
|
halt 500 if wikip.nil?
|
||||||
|
wiki = wikip.wiki
|
||||||
|
page = wiki.paged(wikip.name, wikip.path, exact = true)
|
||||||
|
rename = params[:rename]
|
||||||
|
halt 500 if page.nil?
|
||||||
|
halt 500 if rename.nil? or rename.empty?
|
||||||
|
|
||||||
|
# Fixup the rename if it is a relative path
|
||||||
|
# In 1.8.7 rename[0] != rename[0..0]
|
||||||
|
if rename[0..0] != '/'
|
||||||
|
source_dir = ::File.dirname(page.path)
|
||||||
|
source_dir = '' if source_dir == '.'
|
||||||
|
(target_dir, target_name) = ::File.split(rename)
|
||||||
|
target_dir = target_dir == '' ? source_dir : "#{source_dir}/#{target_dir}"
|
||||||
|
rename = "#{target_dir}/#{target_name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
committer = Gollum::Committer.new(wiki, commit_message)
|
||||||
|
commit = {:committer => committer}
|
||||||
|
|
||||||
|
success = wiki.rename_page(page, rename, commit)
|
||||||
|
if !success
|
||||||
|
# This occurs on NOOPs, for example renaming A => A
|
||||||
|
redirect to("/#{page.escaped_url_path}")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
committer.commit
|
||||||
|
|
||||||
|
wikip = wiki_page(rename)
|
||||||
|
page = wiki.paged(wikip.name, wikip.path, exact = true)
|
||||||
|
return if page.nil?
|
||||||
|
redirect to("/#{page.escaped_url_path}")
|
||||||
|
end
|
||||||
|
|
||||||
post '/edit/*' do
|
post '/edit/*' do
|
||||||
path = '/' + clean_url(sanitize_empty_params(params[:path])).to_s
|
path = '/' + clean_url(sanitize_empty_params(params[:path])).to_s
|
||||||
page_name = CGI.unescape(params[:page])
|
page_name = CGI.unescape(params[:page])
|
||||||
wiki = wiki_new
|
wiki = wiki_new
|
||||||
page = wiki.paged(page_name, path, exact = true)
|
page = wiki.paged(page_name, path, exact = true)
|
||||||
return if page.nil?
|
return if page.nil?
|
||||||
rename = params[:rename].to_url if params[:rename]
|
|
||||||
name = rename || page.name
|
|
||||||
committer = Gollum::Committer.new(wiki, commit_message)
|
committer = Gollum::Committer.new(wiki, commit_message)
|
||||||
commit = {:committer => committer}
|
commit = {:committer => committer}
|
||||||
|
|
||||||
update_wiki_page(wiki, page, params[:content], commit, name, params[:format])
|
update_wiki_page(wiki, page, params[:content], commit, page.name, params[:format])
|
||||||
update_wiki_page(wiki, page.header, params[:header], commit) if params[:header]
|
update_wiki_page(wiki, page.header, params[:header], commit) if params[:header]
|
||||||
update_wiki_page(wiki, page.footer, params[:footer], commit) if params[:footer]
|
update_wiki_page(wiki, page.footer, params[:footer], commit) if params[:footer]
|
||||||
update_wiki_page(wiki, page.sidebar, params[:sidebar], commit) if params[:sidebar]
|
update_wiki_page(wiki, page.sidebar, params[:sidebar], commit) if params[:sidebar]
|
||||||
committer.commit
|
committer.commit
|
||||||
|
|
||||||
page = wiki.page(rename) if rename
|
|
||||||
|
|
||||||
redirect to("/#{page.escaped_url_path}") unless page.nil?
|
redirect to("/#{page.escaped_url_path}") unless page.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -179,9 +265,19 @@ module Precious
|
|||||||
@name = wikip.name.to_url
|
@name = wikip.name.to_url
|
||||||
@path = wikip.path
|
@path = wikip.path
|
||||||
|
|
||||||
|
page_dir = settings.wiki_options[:page_file_dir].to_s
|
||||||
|
unless page_dir.empty?
|
||||||
|
# --page-file-dir docs
|
||||||
|
# /docs/Home should be created in /Home
|
||||||
|
# not /docs/Home because write_page will append /docs
|
||||||
|
@path = @path.sub(page_dir, '/') if @path.start_with? page_dir
|
||||||
|
end
|
||||||
|
@path = clean_path(@path)
|
||||||
|
|
||||||
page = wikip.page
|
page = wikip.page
|
||||||
if page
|
if page
|
||||||
redirect to("/#{page.escaped_url_path}")
|
page_dir = settings.wiki_options[:page_file_dir].to_s
|
||||||
|
redirect to("/#{clean_url(::File.join(page_dir, page.escaped_url_path))}")
|
||||||
else
|
else
|
||||||
mustache :create
|
mustache :create
|
||||||
end
|
end
|
||||||
@@ -191,16 +287,13 @@ module Precious
|
|||||||
name = params[:page].to_url
|
name = params[:page].to_url
|
||||||
path = sanitize_empty_params(params[:path]) || ''
|
path = sanitize_empty_params(params[:path]) || ''
|
||||||
format = params[:format].intern
|
format = params[:format].intern
|
||||||
|
|
||||||
# ensure pages are created in page_file_dir
|
|
||||||
page_dir = settings.wiki_options[:page_file_dir].to_s
|
|
||||||
path = clean_url(::File.join(page_dir, path)) unless path.start_with?(page_dir)
|
|
||||||
|
|
||||||
wiki = wiki_new
|
wiki = wiki_new
|
||||||
|
|
||||||
begin
|
begin
|
||||||
wiki.write_page(name, format, params[:content], commit_message, path)
|
wiki.write_page(name, format, params[:content], commit_message, path)
|
||||||
redirect to("/#{clean_url(::File.join(path,name))}")
|
|
||||||
|
page_dir = settings.wiki_options[:page_file_dir].to_s
|
||||||
|
redirect to("/#{clean_url(::File.join(page_dir, path, name))}")
|
||||||
rescue Gollum::DuplicatePageError => e
|
rescue Gollum::DuplicatePageError => e
|
||||||
@message = "Duplicate page: #{e.message}"
|
@message = "Duplicate page: #{e.message}"
|
||||||
mustache :error
|
mustache :error
|
||||||
@@ -217,7 +310,9 @@ module Precious
|
|||||||
sha1 = shas.shift
|
sha1 = shas.shift
|
||||||
sha2 = shas.shift
|
sha2 = shas.shift
|
||||||
|
|
||||||
if wiki.revert_page(@page, sha1, sha2, commit_message)
|
commit = commit_message
|
||||||
|
commit[:message] = "Revert commit #{sha1.chars.take(7).join}"
|
||||||
|
if wiki.revert_page(@page, sha1, sha2, commit)
|
||||||
redirect to("/#{@page.escaped_url_path}")
|
redirect to("/#{@page.escaped_url_path}")
|
||||||
else
|
else
|
||||||
sha2, sha1 = sha1, "#{sha1}^" if !sha2
|
sha2, sha1 = sha1, "#{sha1}^" if !sha2
|
||||||
@@ -238,6 +333,7 @@ module Precious
|
|||||||
@mathjax = wiki.mathjax
|
@mathjax = wiki.mathjax
|
||||||
@h1_title = wiki.h1_title
|
@h1_title = wiki.h1_title
|
||||||
@editable = false
|
@editable = false
|
||||||
|
@allow_uploads = wiki.allow_uploads
|
||||||
mustache :page
|
mustache :page
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -291,7 +387,6 @@ module Precious
|
|||||||
@page = page
|
@page = page
|
||||||
@name = name
|
@name = name
|
||||||
@content = page.formatted_data
|
@content = page.formatted_data
|
||||||
@editable = true
|
|
||||||
mustache :page
|
mustache :page
|
||||||
else
|
else
|
||||||
halt 404
|
halt 404
|
||||||
@@ -341,25 +436,32 @@ module Precious
|
|||||||
end
|
end
|
||||||
|
|
||||||
def show_page_or_file(fullpath)
|
def show_page_or_file(fullpath)
|
||||||
name = extract_name(fullpath)
|
wiki = wiki_new
|
||||||
path = extract_path(fullpath) || '/'
|
|
||||||
wiki = wiki_new
|
|
||||||
|
|
||||||
page_dir = settings.wiki_options[:page_file_dir].to_s
|
name = extract_name(fullpath) || wiki.index_page
|
||||||
path = ::File.join(page_dir, path) unless path.start_with?(page_dir)
|
path = extract_path(fullpath) || '/'
|
||||||
|
|
||||||
if page = wiki.paged(name, path, exact = true)
|
if page = wiki.paged(name, path, exact = true)
|
||||||
@page = page
|
@page = page
|
||||||
@name = name
|
@name = name
|
||||||
|
@content = page.formatted_data
|
||||||
|
|
||||||
|
# Extensions and layout data
|
||||||
@editable = true
|
@editable = true
|
||||||
@content = page.formatted_data
|
|
||||||
@toc_content = wiki.universal_toc ? @page.toc_data : nil
|
@toc_content = wiki.universal_toc ? @page.toc_data : nil
|
||||||
@mathjax = wiki.mathjax
|
@mathjax = wiki.mathjax
|
||||||
@h1_title = wiki.h1_title
|
@h1_title = wiki.h1_title
|
||||||
|
@bar_side = wiki.bar_side
|
||||||
|
@allow_uploads = wiki.allow_uploads
|
||||||
|
|
||||||
mustache :page
|
mustache :page
|
||||||
elsif file = wiki.file(fullpath)
|
elsif file = wiki.file(fullpath, wiki.ref, true)
|
||||||
content_type file.mime_type
|
if file.on_disk?
|
||||||
file.raw_data
|
send_file file.on_disk_path, :disposition => 'inline'
|
||||||
|
else
|
||||||
|
content_type file.mime_type
|
||||||
|
file.raw_data
|
||||||
|
end
|
||||||
else
|
else
|
||||||
page_path = [path, name].compact.join('/')
|
page_path = [path, name].compact.join('/')
|
||||||
redirect to("/create/#{clean_url(encodeURIComponent(page_path))}")
|
redirect to("/create/#{clean_url(encodeURIComponent(page_path))}")
|
||||||
@@ -384,7 +486,8 @@ module Precious
|
|||||||
# message is sourced from the incoming request parameters
|
# message is sourced from the incoming request parameters
|
||||||
# author details are sourced from the session, to be populated by rack middleware ahead of us
|
# author details are sourced from the session, to be populated by rack middleware ahead of us
|
||||||
def commit_message
|
def commit_message
|
||||||
commit_message = { :message => params[:message] }
|
msg = (params[:message].nil? or params[:message].empty?) ? "[no message]" : params[:message]
|
||||||
|
commit_message = { :message => msg }
|
||||||
author_parameters = session['gollum.author']
|
author_parameters = session['gollum.author']
|
||||||
commit_message.merge! author_parameters unless author_parameters.nil?
|
commit_message.merge! author_parameters unless author_parameters.nil?
|
||||||
commit_message
|
commit_message
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
# ~*~ encoding: utf-8 ~*~
|
|
||||||
module Gollum
|
|
||||||
class BlobEntry
|
|
||||||
# Gets the String SHA for this blob.
|
|
||||||
attr_reader :sha
|
|
||||||
|
|
||||||
# Gets the full path String for this blob.
|
|
||||||
attr_reader :path
|
|
||||||
|
|
||||||
# Gets the Fixnum size of this blob.
|
|
||||||
attr_reader :size
|
|
||||||
|
|
||||||
def initialize(sha, path, size = nil)
|
|
||||||
@sha = sha
|
|
||||||
@path = path
|
|
||||||
@size = size
|
|
||||||
@dir = @name = @blob = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Gets the normalized directory path String for this blob.
|
|
||||||
def dir
|
|
||||||
@dir ||= self.class.normalize_dir(::File.dirname(@path))
|
|
||||||
end
|
|
||||||
|
|
||||||
# Gets the file base name String for this blob.
|
|
||||||
def name
|
|
||||||
@name ||= ::File.basename(@path)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Gets a Grit::Blob instance for this blob.
|
|
||||||
#
|
|
||||||
# repo - Grit::Repo instance for the Grit::Blob.
|
|
||||||
#
|
|
||||||
# Returns an unbaked Grit::Blob instance.
|
|
||||||
def blob(repo)
|
|
||||||
@blob ||= Grit::Blob.create(repo,
|
|
||||||
:id => @sha, :name => name, :size => @size)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Gets a Page instance for this blob.
|
|
||||||
#
|
|
||||||
# wiki - Gollum::Wiki instance for the Gollum::Page
|
|
||||||
#
|
|
||||||
# Returns a Gollum::Page instance.
|
|
||||||
def page(wiki, commit)
|
|
||||||
blob = self.blob(wiki.repo)
|
|
||||||
page = wiki.page_class.new(wiki).populate(blob, self.dir)
|
|
||||||
page.version = commit
|
|
||||||
page
|
|
||||||
end
|
|
||||||
|
|
||||||
# Gets a File instance for this blob.
|
|
||||||
#
|
|
||||||
# wiki - Gollum::Wiki instance for the Gollum::File
|
|
||||||
#
|
|
||||||
# Returns a Gollum::File instance.
|
|
||||||
def file(wiki, commit)
|
|
||||||
blob = self.blob(wiki.repo)
|
|
||||||
file = wiki.file_class.new(wiki).populate(blob, self.dir)
|
|
||||||
file.version = commit
|
|
||||||
file
|
|
||||||
end
|
|
||||||
|
|
||||||
def inspect
|
|
||||||
%(#<Gollum::BlobEntry #{@sha} #{@path}>)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Normalizes a given directory name for searching through tree paths.
|
|
||||||
# Ensures that a directory begins with a slash, or
|
|
||||||
#
|
|
||||||
# normalize_dir("") # => ""
|
|
||||||
# normalize_dir(".") # => ""
|
|
||||||
# normalize_dir("foo") # => "/foo"
|
|
||||||
# normalize_dir("/foo/") # => "/foo"
|
|
||||||
# normalize_dir("/") # => ""
|
|
||||||
# normalize_dir("c:/") # => ""
|
|
||||||
#
|
|
||||||
# dir - String directory name.
|
|
||||||
#
|
|
||||||
# Returns a normalized String directory name, or nil if no directory
|
|
||||||
# is given.
|
|
||||||
def self.normalize_dir(dir)
|
|
||||||
return '' if dir =~ /^.:\/$/
|
|
||||||
if dir
|
|
||||||
dir = ::File.expand_path(dir, '/')
|
|
||||||
dir = '' if dir == '/'
|
|
||||||
end
|
|
||||||
dir
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,232 +0,0 @@
|
|||||||
# ~*~ encoding: utf-8 ~*~
|
|
||||||
module Gollum
|
|
||||||
# Responsible for handling the commit process for a Wiki. It sets up the
|
|
||||||
# Git index, provides methods for modifying the tree, and stores callbacks
|
|
||||||
# to be fired after the commit has been made. This is specifically
|
|
||||||
# designed to handle multiple updated pages in a single commit.
|
|
||||||
class Committer
|
|
||||||
# Gets the instance of the Gollum::Wiki that is being updated.
|
|
||||||
attr_reader :wiki
|
|
||||||
|
|
||||||
# Gets a Hash of commit options.
|
|
||||||
attr_reader :options
|
|
||||||
|
|
||||||
# Initializes the Committer.
|
|
||||||
#
|
|
||||||
# wiki - The Gollum::Wiki instance that is being updated.
|
|
||||||
# options - The commit Hash details:
|
|
||||||
# :message - The String commit message.
|
|
||||||
# :name - The String author full name.
|
|
||||||
# :email - The String email address.
|
|
||||||
# :parent - Optional Grit::Commit parent to this update.
|
|
||||||
# :tree - Optional String SHA of the tree to create the
|
|
||||||
# index from.
|
|
||||||
# :committer - Optional Gollum::Committer instance. If provided,
|
|
||||||
# assume that this operation is part of batch of
|
|
||||||
# updates and the commit happens later.
|
|
||||||
#
|
|
||||||
# Returns the Committer instance.
|
|
||||||
def initialize(wiki, options = {})
|
|
||||||
@wiki = wiki
|
|
||||||
@options = options
|
|
||||||
@callbacks = []
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: References the Git index for this commit.
|
|
||||||
#
|
|
||||||
# Returns a Grit::Index.
|
|
||||||
def index
|
|
||||||
@index ||= begin
|
|
||||||
idx = @wiki.repo.index
|
|
||||||
if tree = options[:tree]
|
|
||||||
idx.read_tree(tree)
|
|
||||||
elsif parent = parents.first
|
|
||||||
idx.read_tree(parent.tree.id)
|
|
||||||
end
|
|
||||||
idx
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The committer for this commit.
|
|
||||||
#
|
|
||||||
# Returns a Grit::Actor.
|
|
||||||
def actor
|
|
||||||
@actor ||= begin
|
|
||||||
@options[:name] = @wiki.default_committer_name if @options[:name].to_s.empty?
|
|
||||||
@options[:email] = @wiki.default_committer_email if @options[:email].to_s.empty?
|
|
||||||
Grit::Actor.new(@options[:name], @options[:email])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The parent commits to this pending commit.
|
|
||||||
#
|
|
||||||
# Returns an array of Grit::Commit instances.
|
|
||||||
def parents
|
|
||||||
@parents ||= begin
|
|
||||||
arr = [@options[:parent] || @wiki.repo.commit(@wiki.ref)]
|
|
||||||
arr.flatten!
|
|
||||||
arr.compact!
|
|
||||||
arr
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adds a page to the given Index.
|
|
||||||
#
|
|
||||||
# dir - The String subdirectory of the Gollum::Page without any
|
|
||||||
# prefix or suffix slashes (e.g. "foo/bar").
|
|
||||||
# name - The String Gollum::Page filename_stripped.
|
|
||||||
# format - The Symbol Gollum::Page format.
|
|
||||||
# data - The String wiki data to store in the tree map.
|
|
||||||
# allow_same_ext - A Boolean determining if the tree map allows the same
|
|
||||||
# filename with the same extension.
|
|
||||||
#
|
|
||||||
# Raises Gollum::DuplicatePageError if a matching filename already exists.
|
|
||||||
# This way, pages are not inadvertently overwritten.
|
|
||||||
#
|
|
||||||
# Returns nothing (modifies the Index in place).
|
|
||||||
def add_to_index(dir, name, format, data, allow_same_ext = false)
|
|
||||||
path = @wiki.page_file_name(name, format)
|
|
||||||
|
|
||||||
dir = '/' if dir.strip.empty?
|
|
||||||
|
|
||||||
fullpath = ::File.join(*[@wiki.page_file_dir, dir, path].compact)
|
|
||||||
fullpath = fullpath[1..-1] if fullpath =~ /^\//
|
|
||||||
|
|
||||||
if index.current_tree && tree = index.current_tree / (@wiki.page_file_dir || '/')
|
|
||||||
tree = tree / dir unless tree.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
if tree
|
|
||||||
downpath = path.downcase.sub(/\.\w+$/, '')
|
|
||||||
|
|
||||||
tree.blobs.each do |blob|
|
|
||||||
next if page_path_scheduled_for_deletion?(index.tree, fullpath)
|
|
||||||
|
|
||||||
existing_file = blob.name.downcase.sub(/\.\w+$/, '')
|
|
||||||
existing_file_ext = ::File.extname(blob.name).sub(/^\./, '')
|
|
||||||
|
|
||||||
new_file_ext = ::File.extname(path).sub(/^\./, '')
|
|
||||||
|
|
||||||
if downpath == existing_file && !(allow_same_ext && new_file_ext == existing_file_ext)
|
|
||||||
raise DuplicatePageError.new(dir, blob.name, path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
fullpath = fullpath.force_encoding('ascii-8bit') if fullpath.respond_to?(:force_encoding)
|
|
||||||
|
|
||||||
index.add(fullpath, @wiki.normalize(data))
|
|
||||||
end
|
|
||||||
|
|
||||||
# Update the given file in the repository's working directory if there
|
|
||||||
# is a working directory present.
|
|
||||||
#
|
|
||||||
# dir - The String directory in which the file lives.
|
|
||||||
# name - The String name of the page or the stripped filename
|
|
||||||
# (should be pre-canonicalized if required).
|
|
||||||
# format - The Symbol format of the page.
|
|
||||||
#
|
|
||||||
# Returns nothing.
|
|
||||||
def update_working_dir(dir, name, format)
|
|
||||||
unless @wiki.repo.bare
|
|
||||||
if @wiki.page_file_dir
|
|
||||||
dir = dir.size.zero? ? @wiki.page_file_dir : ::File.join(dir, @wiki.page_file_dir)
|
|
||||||
end
|
|
||||||
|
|
||||||
path =
|
|
||||||
if dir == ''
|
|
||||||
@wiki.page_file_name(name, format)
|
|
||||||
else
|
|
||||||
::File.join(dir, @wiki.page_file_name(name, format))
|
|
||||||
end
|
|
||||||
|
|
||||||
path = path.force_encoding('ascii-8bit') if path.respond_to?(:force_encoding)
|
|
||||||
|
|
||||||
Dir.chdir(::File.join(@wiki.repo.path, '..')) do
|
|
||||||
if file_path_scheduled_for_deletion?(index.tree, path)
|
|
||||||
@wiki.repo.git.rm({'f' => true}, '--', path)
|
|
||||||
else
|
|
||||||
@wiki.repo.git.checkout({}, 'HEAD', '--', path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Writes the commit to Git and runs the after_commit callbacks.
|
|
||||||
#
|
|
||||||
# Returns the String SHA1 of the new commit.
|
|
||||||
def commit
|
|
||||||
sha1 = index.commit(@options[:message], parents, actor, nil, @wiki.ref)
|
|
||||||
@callbacks.each do |cb|
|
|
||||||
cb.call(self, sha1)
|
|
||||||
end
|
|
||||||
sha1
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adds a callback to be fired after a commit.
|
|
||||||
#
|
|
||||||
# block - A block that expects this Committer instance and the created
|
|
||||||
# commit's SHA1 as the arguments.
|
|
||||||
#
|
|
||||||
# Returns nothing.
|
|
||||||
def after_commit(&block)
|
|
||||||
@callbacks << block
|
|
||||||
end
|
|
||||||
|
|
||||||
# Determine if a given page (regardless of format) is scheduled to be
|
|
||||||
# deleted in the next commit for the given Index.
|
|
||||||
#
|
|
||||||
# map - The Hash map:
|
|
||||||
# key - The String directory or filename.
|
|
||||||
# val - The Hash submap or the String contents of the file.
|
|
||||||
# path - The String path of the page file. This may include the format
|
|
||||||
# extension in which case it will be ignored.
|
|
||||||
#
|
|
||||||
# Returns the Boolean response.
|
|
||||||
def page_path_scheduled_for_deletion?(map, path)
|
|
||||||
parts = path.split('/')
|
|
||||||
if parts.size == 1
|
|
||||||
deletions = map.keys.select { |k| !map[k] }
|
|
||||||
downfile = parts.first.downcase.sub(/\.\w+$/, '')
|
|
||||||
deletions.any? { |d| d.downcase.sub(/\.\w+$/, '') == downfile }
|
|
||||||
else
|
|
||||||
part = parts.shift
|
|
||||||
if rest = map[part]
|
|
||||||
page_path_scheduled_for_deletion?(rest, parts.join('/'))
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Determine if a given file is scheduled to be deleted in the next commit
|
|
||||||
# for the given Index.
|
|
||||||
#
|
|
||||||
# map - The Hash map:
|
|
||||||
# key - The String directory or filename.
|
|
||||||
# val - The Hash submap or the String contents of the file.
|
|
||||||
# path - The String path of the file including extension.
|
|
||||||
#
|
|
||||||
# Returns the Boolean response.
|
|
||||||
def file_path_scheduled_for_deletion?(map, path)
|
|
||||||
parts = path.split('/')
|
|
||||||
if parts.size == 1
|
|
||||||
deletions = map.keys.select { |k| !map[k] }
|
|
||||||
deletions.any? { |d| d == parts.first }
|
|
||||||
else
|
|
||||||
part = parts.shift
|
|
||||||
if rest = map[part]
|
|
||||||
file_path_scheduled_for_deletion?(rest, parts.join('/'))
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Proxies methods t
|
|
||||||
def method_missing(name, *args)
|
|
||||||
args.map! { |item| item.respond_to?(:force_encoding) ? item.force_encoding('ascii-8bit') : item }
|
|
||||||
index.send(name, *args)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
# ~*~ encoding: utf-8 ~*~
|
|
||||||
module Gollum
|
|
||||||
class File
|
|
||||||
Wiki.file_class = self
|
|
||||||
|
|
||||||
# Public: Initialize a file.
|
|
||||||
#
|
|
||||||
# wiki - The Gollum::Wiki in question.
|
|
||||||
#
|
|
||||||
# Returns a newly initialized Gollum::File.
|
|
||||||
def initialize(wiki)
|
|
||||||
@wiki = wiki
|
|
||||||
@blob = nil
|
|
||||||
@path = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The url path required to reach this page within the repo.
|
|
||||||
#
|
|
||||||
# Returns the String url_path
|
|
||||||
def url_path
|
|
||||||
path = self.path
|
|
||||||
path = path.sub(/\/[^\/]+$/, '/') if path.include?('/')
|
|
||||||
path
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The url_path, but CGI escaped.
|
|
||||||
#
|
|
||||||
# Returns the String url_path
|
|
||||||
def escaped_url_path
|
|
||||||
CGI.escape(self.url_path).gsub('%2F','/')
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The on-disk filename of the file.
|
|
||||||
#
|
|
||||||
# Returns the String name.
|
|
||||||
def name
|
|
||||||
@blob && @blob.name
|
|
||||||
end
|
|
||||||
alias filename name
|
|
||||||
|
|
||||||
# Public: The raw contents of the page.
|
|
||||||
#
|
|
||||||
# Returns the String data.
|
|
||||||
def raw_data
|
|
||||||
@blob && @blob.data
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The Grit::Commit version of the file.
|
|
||||||
attr_accessor :version
|
|
||||||
|
|
||||||
# Public: The String path of the file.
|
|
||||||
attr_reader :path
|
|
||||||
|
|
||||||
# Public: The String mime type of the file.
|
|
||||||
def mime_type
|
|
||||||
@blob.mime_type
|
|
||||||
end
|
|
||||||
|
|
||||||
# Populate the File with information from the Blob.
|
|
||||||
#
|
|
||||||
# blob - The Grit::Blob that contains the info.
|
|
||||||
# path - The String directory path of the file.
|
|
||||||
#
|
|
||||||
# Returns the populated Gollum::File.
|
|
||||||
def populate(blob, path=nil)
|
|
||||||
@blob = blob
|
|
||||||
@path = "#{path}/#{blob.name}"[1..-1]
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
#########################################################################
|
|
||||||
#
|
|
||||||
# Internal Methods
|
|
||||||
#
|
|
||||||
#########################################################################
|
|
||||||
|
|
||||||
# Find a file in the given Gollum repo.
|
|
||||||
#
|
|
||||||
# name - The full String path.
|
|
||||||
# version - The String version ID to find.
|
|
||||||
#
|
|
||||||
# Returns a Gollum::File or nil if the file could not be found.
|
|
||||||
def find(name, version)
|
|
||||||
checked = name.downcase
|
|
||||||
map = @wiki.tree_map_for(version)
|
|
||||||
if entry = map.detect { |entry| entry.path.downcase == checked }
|
|
||||||
@path = name
|
|
||||||
@blob = entry.blob(@wiki.repo)
|
|
||||||
@version = version.is_a?(Grit::Commit) ? version : @wiki.commit_for(version)
|
|
||||||
self
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
# ~*~ encoding: utf-8 ~*~
|
|
||||||
module Gollum
|
|
||||||
=begin
|
|
||||||
FileView requires that:
|
|
||||||
- All files in root dir are processed first
|
|
||||||
- Then all the folders are sorted and processed
|
|
||||||
=end
|
|
||||||
class FileView
|
|
||||||
# common use cases:
|
|
||||||
# set pages to wiki.pages and show_all to false
|
|
||||||
# set pages to wiki.pages + wiki.files and show_all to true
|
|
||||||
def initialize pages, options = {}
|
|
||||||
@pages = pages
|
|
||||||
@show_all = options[:show_all] || false
|
|
||||||
@checked = options[:collapse_tree] ? '' : "checked"
|
|
||||||
end
|
|
||||||
|
|
||||||
def enclose_tree string
|
|
||||||
%Q(<ol class="tree">\n) + string + %Q(</ol>)
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_page page
|
|
||||||
name = page.name
|
|
||||||
url = url_for_page page
|
|
||||||
%Q( <li class="file"><a href="#{url}"><span class="icon"></span>#{name}</a></li>)
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_folder folder_path
|
|
||||||
new_sub_folder folder_path
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_sub_folder path
|
|
||||||
<<-HTML
|
|
||||||
<li>
|
|
||||||
<label>#{path}</label> <input type="checkbox" #{@checked} />
|
|
||||||
<ol>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def end_folder
|
|
||||||
"</ol></li>\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
def url_for_page page
|
|
||||||
url = ''
|
|
||||||
if @show_all
|
|
||||||
# Remove ext for valid pages.
|
|
||||||
filename = page.filename
|
|
||||||
filename = Page::valid_page_name?(filename) ? filename.chomp(::File.extname(filename)) : filename
|
|
||||||
|
|
||||||
url = ::File.join(::File.dirname(page.path), filename)
|
|
||||||
else
|
|
||||||
url = ::File.join(::File.dirname(page.path), page.filename_stripped)
|
|
||||||
end
|
|
||||||
url = url[2..-1] if url[0,2] == './'
|
|
||||||
url
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_files
|
|
||||||
html = ''
|
|
||||||
count = @pages.size
|
|
||||||
folder_start = -1
|
|
||||||
|
|
||||||
# Process all pages until folders start
|
|
||||||
count.times do | index |
|
|
||||||
page = @pages[ index ]
|
|
||||||
path = page.path
|
|
||||||
|
|
||||||
unless path.include? '/'
|
|
||||||
# Page processed (not contained in a folder)
|
|
||||||
html += new_page page
|
|
||||||
else
|
|
||||||
# Folders start at the next index
|
|
||||||
folder_start = index
|
|
||||||
break # Pages finished, move on to folders
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# If there are no folders, then we're done.
|
|
||||||
return enclose_tree(html) if folder_start <= -1
|
|
||||||
|
|
||||||
# Handle special case of only one folder.
|
|
||||||
if (count - folder_start == 1)
|
|
||||||
page = @pages[ folder_start ]
|
|
||||||
html += <<-HTML
|
|
||||||
<li>
|
|
||||||
<label>#{::File.dirname(page.path)}</label> <input type="checkbox" #{@checked} />
|
|
||||||
<ol>
|
|
||||||
#{new_page page}
|
|
||||||
</ol>
|
|
||||||
</li>
|
|
||||||
HTML
|
|
||||||
|
|
||||||
return enclose_tree html
|
|
||||||
end
|
|
||||||
|
|
||||||
sorted_folders = []
|
|
||||||
(folder_start).upto count - 1 do | index |
|
|
||||||
sorted_folders += [[ @pages[ index ].path, index ]]
|
|
||||||
end
|
|
||||||
|
|
||||||
# http://stackoverflow.com/questions/3482814/sorting-list-of-string-paths-in-vb-net
|
|
||||||
sorted_folders.sort! do |first,second|
|
|
||||||
a = first[0]
|
|
||||||
b = second[0]
|
|
||||||
|
|
||||||
# use :: operator because gollum defines its own conflicting File class
|
|
||||||
dir_compare = ::File.dirname(a) <=> ::File.dirname(b)
|
|
||||||
|
|
||||||
# Sort based on directory name unless they're equal (0) in
|
|
||||||
# which case sort based on file name.
|
|
||||||
if dir_compare == 0
|
|
||||||
::File.basename(a) <=> ::File.basename(b)
|
|
||||||
else
|
|
||||||
dir_compare
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# keep track of folder depth, 0 = at root.
|
|
||||||
cwd_array = []
|
|
||||||
changed = false
|
|
||||||
|
|
||||||
# process rest of folders
|
|
||||||
(0...sorted_folders.size).each do | index |
|
|
||||||
page = @pages[ sorted_folders[ index ][ 1 ] ]
|
|
||||||
path = page.path
|
|
||||||
folder = ::File.dirname path
|
|
||||||
|
|
||||||
tmp_array = folder.split '/'
|
|
||||||
|
|
||||||
(0...tmp_array.size).each do | index |
|
|
||||||
if cwd_array[ index ].nil? || changed
|
|
||||||
html += new_sub_folder tmp_array[ index ]
|
|
||||||
next
|
|
||||||
end
|
|
||||||
|
|
||||||
if cwd_array[ index ] != tmp_array[ index ]
|
|
||||||
changed = true
|
|
||||||
(cwd_array.size - index).times do
|
|
||||||
html += end_folder
|
|
||||||
end
|
|
||||||
html += new_sub_folder tmp_array[ index ]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
html += new_page page
|
|
||||||
cwd_array = tmp_array
|
|
||||||
changed = false
|
|
||||||
end
|
|
||||||
|
|
||||||
# return the completed html
|
|
||||||
enclose_tree html
|
|
||||||
end # end render_files
|
|
||||||
end # end FileView class
|
|
||||||
end # end Gollum module
|
|
||||||
@@ -1,249 +0,0 @@
|
|||||||
# ~*~ encoding: utf-8 ~*~
|
|
||||||
module Gollum
|
|
||||||
# Controls all access to the Git objects from Gollum. Extend this class to
|
|
||||||
# add custom caching for special cases.
|
|
||||||
class GitAccess
|
|
||||||
# Initializes the GitAccess instance.
|
|
||||||
#
|
|
||||||
# path - The String path to the Git repository that holds the
|
|
||||||
# Gollum site.
|
|
||||||
# page_file_dir - String the directory in which all page files reside
|
|
||||||
#
|
|
||||||
# Returns this instance.
|
|
||||||
def initialize(path, page_file_dir = nil, bare = false)
|
|
||||||
@page_file_dir = page_file_dir
|
|
||||||
@path = path
|
|
||||||
@repo = Grit::Repo.new(path, { :is_bare => bare })
|
|
||||||
clear
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: Determines whether the Git repository exists on disk.
|
|
||||||
#
|
|
||||||
# Returns true if it exists, or false.
|
|
||||||
def exist?
|
|
||||||
@repo.git.exist?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: Converts a given Git reference to a SHA, using the cache if
|
|
||||||
# available.
|
|
||||||
#
|
|
||||||
# ref - a String Git reference (ex: "master")
|
|
||||||
#
|
|
||||||
# Returns a String, or nil if the ref isn't found.
|
|
||||||
def ref_to_sha(ref)
|
|
||||||
ref = ref.to_s
|
|
||||||
return if ref.empty?
|
|
||||||
sha =
|
|
||||||
if sha?(ref)
|
|
||||||
ref
|
|
||||||
else
|
|
||||||
get_cache(:ref, ref) { ref_to_sha!(ref) }
|
|
||||||
end.to_s
|
|
||||||
sha.empty? ? nil : sha
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: Gets a recursive list of Git blobs for the whole tree at the
|
|
||||||
# given commit.
|
|
||||||
#
|
|
||||||
# ref - A String Git reference or Git SHA to a commit.
|
|
||||||
#
|
|
||||||
# Returns an Array of BlobEntry instances.
|
|
||||||
def tree(ref)
|
|
||||||
if sha = ref_to_sha(ref)
|
|
||||||
get_cache(:tree, sha) { tree!(sha) }
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: Fetches the contents of the Git blob at the given SHA.
|
|
||||||
#
|
|
||||||
# sha - A String Git SHA.
|
|
||||||
#
|
|
||||||
# Returns the String content of the blob.
|
|
||||||
def blob(sha)
|
|
||||||
cat_file!(sha)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: Looks up the Git commit using the given Git SHA or ref.
|
|
||||||
#
|
|
||||||
# ref - A String Git SHA or ref.
|
|
||||||
#
|
|
||||||
# Returns a Grit::Commit.
|
|
||||||
def commit(ref)
|
|
||||||
if sha?(ref)
|
|
||||||
get_cache(:commit, ref) { commit!(ref) }
|
|
||||||
else
|
|
||||||
if sha = get_cache(:ref, ref)
|
|
||||||
commit(sha)
|
|
||||||
else
|
|
||||||
if cm = commit!(ref)
|
|
||||||
set_cache(:ref, ref, cm.id)
|
|
||||||
set_cache(:commit, cm.id, cm)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: Clears all of the cached data that this GitAccess is tracking.
|
|
||||||
#
|
|
||||||
# Returns nothing.
|
|
||||||
def clear
|
|
||||||
@ref_map = {}
|
|
||||||
@tree_map = {}
|
|
||||||
@commit_map = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: Refreshes just the cached Git reference data. This should
|
|
||||||
# be called after every Gollum update.
|
|
||||||
#
|
|
||||||
# Returns nothing.
|
|
||||||
def refresh
|
|
||||||
@ref_map.clear
|
|
||||||
end
|
|
||||||
|
|
||||||
#########################################################################
|
|
||||||
#
|
|
||||||
# Internal Methods
|
|
||||||
#
|
|
||||||
#########################################################################
|
|
||||||
|
|
||||||
# Gets the String path to the Git repository.
|
|
||||||
attr_reader :path
|
|
||||||
|
|
||||||
# Gets the Grit::Repo instance for the Git repository.
|
|
||||||
attr_reader :repo
|
|
||||||
|
|
||||||
# Gets a Hash cache of refs to commit SHAs.
|
|
||||||
#
|
|
||||||
# {"master" => "abc123", ...}
|
|
||||||
#
|
|
||||||
attr_reader :ref_map
|
|
||||||
|
|
||||||
# Gets a Hash cache of commit SHAs to a recursive tree of blobs.
|
|
||||||
#
|
|
||||||
# {"abc123" => [<BlobEntry>, <BlobEntry>]}
|
|
||||||
#
|
|
||||||
attr_reader :tree_map
|
|
||||||
|
|
||||||
# Gets a Hash cache of commit SHAs to the Grit::Commit instance.
|
|
||||||
#
|
|
||||||
# {"abcd123" => <Grit::Commit>}
|
|
||||||
#
|
|
||||||
attr_reader :commit_map
|
|
||||||
|
|
||||||
# Checks to see if the given String is a 40 character hex SHA.
|
|
||||||
#
|
|
||||||
# str - Possible String SHA.
|
|
||||||
#
|
|
||||||
# Returns true if the String is a SHA, or false.
|
|
||||||
def sha?(str)
|
|
||||||
!!(str =~ /^[0-9a-f]{40}$/)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Looks up the Git SHA for the given Git ref.
|
|
||||||
#
|
|
||||||
# ref - String Git ref.
|
|
||||||
#
|
|
||||||
# Returns a String SHA.
|
|
||||||
def ref_to_sha!(ref)
|
|
||||||
@repo.git.rev_list({:max_count=>1}, ref)
|
|
||||||
rescue Grit::GitRuby::Repository::NoSuchShaFound
|
|
||||||
end
|
|
||||||
|
|
||||||
# Looks up the Git blobs for a given commit.
|
|
||||||
#
|
|
||||||
# sha - String commit SHA.
|
|
||||||
#
|
|
||||||
# Returns an Array of BlobEntry instances.
|
|
||||||
def tree!(sha)
|
|
||||||
tree = @repo.git.native(:ls_tree,
|
|
||||||
{:r => true, :l => true, :z => true}, sha)
|
|
||||||
if tree.respond_to?(:force_encoding)
|
|
||||||
tree.force_encoding("UTF-8")
|
|
||||||
end
|
|
||||||
items = tree.split("\0").inject([]) do |memo, line|
|
|
||||||
memo << parse_tree_line(line)
|
|
||||||
end
|
|
||||||
|
|
||||||
if dir = @page_file_dir
|
|
||||||
regex = /^#{dir}\//
|
|
||||||
items.select { |i| i.path =~ regex }
|
|
||||||
else
|
|
||||||
items
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Reads the content from the Git db at the given SHA.
|
|
||||||
#
|
|
||||||
# sha - The String SHA.
|
|
||||||
#
|
|
||||||
# Returns the String content of the Git object.
|
|
||||||
def cat_file!(sha)
|
|
||||||
@repo.git.cat_file({:p => true}, sha)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Reads a Git commit.
|
|
||||||
#
|
|
||||||
# sha - The string SHA of the Git commit.
|
|
||||||
#
|
|
||||||
# Returns a Grit::Commit.
|
|
||||||
def commit!(sha)
|
|
||||||
@repo.commit(sha)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Attempts to get the given data from a cache. If it doesn't exist, it'll
|
|
||||||
# pass the results of the yielded block to the cache for future accesses.
|
|
||||||
#
|
|
||||||
# name - The cache prefix used in building the full cache key.
|
|
||||||
# key - The unique cache key suffix, usually a String Git SHA.
|
|
||||||
#
|
|
||||||
# Yields a block to pass to the cache.
|
|
||||||
# Returns the cached result.
|
|
||||||
def get_cache(name, key)
|
|
||||||
cache = instance_variable_get("@#{name}_map")
|
|
||||||
value = cache[key]
|
|
||||||
if value.nil? && block_given?
|
|
||||||
set_cache(name, key, value = yield)
|
|
||||||
end
|
|
||||||
value == :_nil ? nil : value
|
|
||||||
end
|
|
||||||
|
|
||||||
# Writes some data to the internal cache.
|
|
||||||
#
|
|
||||||
# name - The cache prefix used in building the full cache key.
|
|
||||||
# key - The unique cache key suffix, usually a String Git SHA.
|
|
||||||
# value - The value to write to the cache.
|
|
||||||
#
|
|
||||||
# Returns nothing.
|
|
||||||
def set_cache(name, key, value)
|
|
||||||
cache = instance_variable_get("@#{name}_map")
|
|
||||||
cache[key] = value || :_nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parses a line of output from the `ls-tree` command.
|
|
||||||
#
|
|
||||||
# line - A String line of output:
|
|
||||||
# "100644 blob 839c2291b30495b9a882c17d08254d3c90d8fb53 Home.md"
|
|
||||||
#
|
|
||||||
# Returns an Array of BlobEntry instances.
|
|
||||||
def parse_tree_line(line)
|
|
||||||
mode, type, sha, size, *name = line.split(/\s+/)
|
|
||||||
BlobEntry.new(sha, name.join(' '), size.to_i)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Decode octal sequences (\NNN) in tree path names.
|
|
||||||
#
|
|
||||||
# path - String path name.
|
|
||||||
#
|
|
||||||
# Returns a decoded String.
|
|
||||||
def decode_git_path(path)
|
|
||||||
if path[0] == ?" && path[-1] == ?"
|
|
||||||
path = path[1...-1]
|
|
||||||
path.gsub!(/\\\d{3}/) { |m| m[1..-1].to_i(8).chr }
|
|
||||||
end
|
|
||||||
path.gsub!(/\\[rn"\\]/) { |m| eval(%("#{m.to_s}")) }
|
|
||||||
path
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
# ~*~ encoding: utf-8 ~*~
|
|
||||||
require 'net/http'
|
|
||||||
require 'net/https' # ruby 1.8.7 fix, remove at upgrade
|
|
||||||
require 'uri'
|
|
||||||
require 'open-uri'
|
|
||||||
|
|
||||||
module Gollum
|
|
||||||
class Gitcode
|
|
||||||
def initialize path
|
|
||||||
raise(ArgumentError, 'path is nil or empty') if path.nil? or path.empty?
|
|
||||||
|
|
||||||
@uri = URI::HTTP.build({
|
|
||||||
:path => self.unchomp(path),
|
|
||||||
:host => 'raw.github.com',
|
|
||||||
:scheme => 'https',
|
|
||||||
:port => 443 })
|
|
||||||
end
|
|
||||||
|
|
||||||
def contents
|
|
||||||
@contents ||= self.req @uri
|
|
||||||
end
|
|
||||||
|
|
||||||
def unchomp p
|
|
||||||
return p if p.nil?
|
|
||||||
p[0] == '/' ? p : ('/' + p)
|
|
||||||
end
|
|
||||||
|
|
||||||
def req uri, cut = 1
|
|
||||||
return "Too many redirects or retries" if cut >= 10
|
|
||||||
http = Net::HTTP.new uri.host, uri.port
|
|
||||||
http.use_ssl = true
|
|
||||||
resp = http.get uri.path, {
|
|
||||||
'Accept' => 'text/plain',
|
|
||||||
'Cache-Control' => 'no-cache',
|
|
||||||
'Connection' => 'keep-alive',
|
|
||||||
'Host' => uri.host,
|
|
||||||
'User-Agent' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0'
|
|
||||||
}
|
|
||||||
code = resp.code.to_i
|
|
||||||
return resp.body if code == 200
|
|
||||||
return "Not Found" if code == 404
|
|
||||||
return "Unhandled Response Code #{code}" unless code == 304 or not resp.header['location'].nil?
|
|
||||||
loc = URI.parse resp.header['location']
|
|
||||||
uri2 = loc.relative?() ? (uri + loc) : loc # overloads (+)
|
|
||||||
return req uri2, (cut + 1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -12,6 +12,12 @@ module Precious
|
|||||||
|
|
||||||
# Extract the 'page' name from the file_path
|
# Extract the 'page' name from the file_path
|
||||||
def extract_name(file_path)
|
def extract_name(file_path)
|
||||||
|
if file_path[-1, 1] == "/"
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# File.basename is too eager to please and will return the last
|
||||||
|
# component of the path even if it ends with a directory separator.
|
||||||
::File.basename(file_path)
|
::File.basename(file_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -19,6 +25,13 @@ module Precious
|
|||||||
[nil,''].include?(param) ? nil : CGI.unescape(param)
|
[nil,''].include?(param) ? nil : CGI.unescape(param)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Ensure path begins with a single leading slash
|
||||||
|
def clean_path(path)
|
||||||
|
if path
|
||||||
|
(path[0] != '/' ? path.insert(0, '/') : path).gsub(/\/{2,}/,'/')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Remove all slashes from the start of string.
|
# Remove all slashes from the start of string.
|
||||||
# Remove all double slashes
|
# Remove all double slashes
|
||||||
def clean_url url
|
def clean_url url
|
||||||
@@ -26,11 +39,5 @@ module Precious
|
|||||||
url.gsub('%2F','/').gsub(/^\/+/,'').gsub('//','/')
|
url.gsub('%2F','/').gsub(/^\/+/,'').gsub('//','/')
|
||||||
end
|
end
|
||||||
|
|
||||||
def trim_leading_slash url
|
|
||||||
return url if url.nil?
|
|
||||||
url.gsub!('%2F','/')
|
|
||||||
return '/' + url.gsub(/^\/+/,'') if url[0,1] == '/'
|
|
||||||
url
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1,672 +0,0 @@
|
|||||||
# ~*~ encoding: utf-8 ~*~
|
|
||||||
require 'digest/sha1'
|
|
||||||
require 'cgi'
|
|
||||||
require 'pygments'
|
|
||||||
require 'base64'
|
|
||||||
|
|
||||||
require File.expand_path '../frontend/helpers', __FILE__
|
|
||||||
require File.expand_path '../gitcode', __FILE__
|
|
||||||
|
|
||||||
# initialize Pygments
|
|
||||||
Pygments.start
|
|
||||||
|
|
||||||
module Gollum
|
|
||||||
|
|
||||||
class Markup
|
|
||||||
include Precious::Helpers
|
|
||||||
|
|
||||||
attr_accessor :toc
|
|
||||||
attr_reader :metadata
|
|
||||||
|
|
||||||
# Initialize a new Markup object.
|
|
||||||
#
|
|
||||||
# page - The Gollum::Page.
|
|
||||||
#
|
|
||||||
# Returns a new Gollum::Markup object, ready for rendering.
|
|
||||||
def initialize(page)
|
|
||||||
@wiki = page.wiki
|
|
||||||
@name = page.filename
|
|
||||||
@data = page.text_data
|
|
||||||
@version = page.version.id if page.version
|
|
||||||
@format = page.format
|
|
||||||
@sub_page = page.sub_page
|
|
||||||
@parent_page = page.parent_page
|
|
||||||
@dir = ::File.dirname(page.path)
|
|
||||||
@tagmap = {}
|
|
||||||
@codemap = {}
|
|
||||||
@wsdmap = {}
|
|
||||||
@premap = {}
|
|
||||||
@toc = nil
|
|
||||||
@metadata = nil
|
|
||||||
@to_xml = { :save_with => Nokogiri::XML::Node::SaveOptions::DEFAULT_XHTML ^ 1, :indent => 0, :encoding => 'UTF-8' }
|
|
||||||
end
|
|
||||||
|
|
||||||
# Render the content with Gollum wiki syntax on top of the file's own
|
|
||||||
# markup language.
|
|
||||||
#
|
|
||||||
# no_follow - Boolean that determines if rel="nofollow" is added to all
|
|
||||||
# <a> tags.
|
|
||||||
# encoding - Encoding Constant or String.
|
|
||||||
#
|
|
||||||
# Returns the formatted String content.
|
|
||||||
def render(no_follow = false, encoding = nil)
|
|
||||||
sanitize = no_follow ?
|
|
||||||
@wiki.history_sanitizer :
|
|
||||||
@wiki.sanitizer
|
|
||||||
|
|
||||||
data = @data.dup
|
|
||||||
data = extract_metadata(data)
|
|
||||||
data = extract_gitcode(data)
|
|
||||||
data = extract_code(data)
|
|
||||||
data = extract_wsd(data)
|
|
||||||
data = extract_tags(data)
|
|
||||||
begin
|
|
||||||
data = GitHub::Markup.render(@name, data)
|
|
||||||
if data.nil?
|
|
||||||
raise "There was an error converting #{@name} to HTML."
|
|
||||||
end
|
|
||||||
rescue Object => e
|
|
||||||
data = %{<p class="gollum-error">#{e.message}</p>}
|
|
||||||
end
|
|
||||||
data = process_tags(data)
|
|
||||||
data = process_code(data, encoding)
|
|
||||||
|
|
||||||
doc = Nokogiri::HTML::DocumentFragment.parse(data)
|
|
||||||
doc = sanitize.clean_node!(doc) if sanitize
|
|
||||||
doc,toc = process_headers(doc)
|
|
||||||
@toc = @sub_page ? ( @parent_page ? @parent_page.toc_data : "[[_TOC_]]" ) : toc
|
|
||||||
yield doc if block_given?
|
|
||||||
# nokogiri's save options are ored together. FORMAT has a value of 1 so ^ 1 removes it.
|
|
||||||
# formatting will create extra spaces in pre tags.
|
|
||||||
# https://github.com/sparklemotion/nokogiri/issues/782
|
|
||||||
# DEFAULT_HTML encodes unicode so XHTML is used for proper unicode support in href.
|
|
||||||
data = doc.to_xml( @to_xml )
|
|
||||||
|
|
||||||
data = process_toc_tags(data)
|
|
||||||
data = process_wsd(data)
|
|
||||||
data.gsub!(/<p><\/p>/) do
|
|
||||||
''
|
|
||||||
end
|
|
||||||
|
|
||||||
data
|
|
||||||
end
|
|
||||||
|
|
||||||
# Inserts header anchors and creates TOC
|
|
||||||
#
|
|
||||||
# doc - Nokogiri parsed document
|
|
||||||
#
|
|
||||||
# Returns doc Document and toc String
|
|
||||||
def process_headers(doc)
|
|
||||||
toc = nil
|
|
||||||
doc.css('h1,h2,h3,h4,h5,h6').each do |h|
|
|
||||||
# must escape "
|
|
||||||
h_name = h.content.gsub(' ','-').gsub('"','%22')
|
|
||||||
|
|
||||||
level = h.name.gsub(/[hH]/,'').to_i
|
|
||||||
|
|
||||||
# Add anchors
|
|
||||||
h.add_child(%Q{<a class="anchor" id="#{h_name}" href="##{h_name}"></a>})
|
|
||||||
|
|
||||||
# Build TOC
|
|
||||||
toc ||= Nokogiri::XML::DocumentFragment.parse('<div class="toc"><div class="toc-title">Table of Contents</div></div>')
|
|
||||||
tail ||= toc.child
|
|
||||||
tail_level ||= 0
|
|
||||||
|
|
||||||
while tail_level < level
|
|
||||||
node = Nokogiri::XML::Node.new('ul', doc)
|
|
||||||
tail = tail.add_child(node)
|
|
||||||
tail_level += 1
|
|
||||||
end
|
|
||||||
while tail_level > level
|
|
||||||
tail = tail.parent
|
|
||||||
tail_level -= 1
|
|
||||||
end
|
|
||||||
node = Nokogiri::XML::Node.new('li', doc)
|
|
||||||
# % -> %25 so anchors work on Firefox. See issue #475
|
|
||||||
node.add_child(%Q{<a href="##{h_name}">#{h.content}</a>})
|
|
||||||
tail.add_child(node)
|
|
||||||
end
|
|
||||||
toc = toc.to_xml(@to_xml) if toc != nil
|
|
||||||
[doc, toc]
|
|
||||||
end
|
|
||||||
|
|
||||||
#########################################################################
|
|
||||||
#
|
|
||||||
# Tags
|
|
||||||
#
|
|
||||||
#########################################################################
|
|
||||||
|
|
||||||
# Extract all tags into the tagmap and replace with placeholders.
|
|
||||||
#
|
|
||||||
# data - The raw String data.
|
|
||||||
#
|
|
||||||
# Returns the placeholder'd String data.
|
|
||||||
def extract_tags(data)
|
|
||||||
if @format == :asciidoc
|
|
||||||
return data
|
|
||||||
end
|
|
||||||
data.gsub!(/(.?)\[\[(.+?)\]\]([^\[]?)/m) do
|
|
||||||
if $1 == "'" && $3 != "'"
|
|
||||||
"[[#{$2}]]#{$3}"
|
|
||||||
elsif $2.include?('][')
|
|
||||||
if $2[0..4] == 'file:'
|
|
||||||
pre = $1
|
|
||||||
post = $3
|
|
||||||
parts = $2.split('][')
|
|
||||||
parts[0][0..4] = ""
|
|
||||||
link = "#{parts[1]}|#{parts[0].sub(/\.org/,'')}"
|
|
||||||
id = Digest::SHA1.hexdigest(link)
|
|
||||||
@tagmap[id] = link
|
|
||||||
"#{pre}#{id}#{post}"
|
|
||||||
else
|
|
||||||
$&
|
|
||||||
end
|
|
||||||
else
|
|
||||||
id = Digest::SHA1.hexdigest($2)
|
|
||||||
@tagmap[id] = $2
|
|
||||||
"#{$1}#{id}#{$3}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
data
|
|
||||||
end
|
|
||||||
|
|
||||||
# Process all tags from the tagmap and replace the placeholders with the
|
|
||||||
# final markup.
|
|
||||||
#
|
|
||||||
# data - The String data (with placeholders).
|
|
||||||
#
|
|
||||||
# Returns the marked up String data.
|
|
||||||
def process_tags(data)
|
|
||||||
@tagmap.each do |id, tag|
|
|
||||||
# If it's preformatted, just put the tag back
|
|
||||||
if is_preformatted?(data, id)
|
|
||||||
data.gsub!(id) do
|
|
||||||
"[[#{tag}]]"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
data.gsub!(id) do
|
|
||||||
process_tag(tag).gsub('%2F', '/')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
data
|
|
||||||
end
|
|
||||||
|
|
||||||
# Find `id` within `data` and determine if it's within
|
|
||||||
# preformatted tags.
|
|
||||||
#
|
|
||||||
# data - The String data (with placeholders).
|
|
||||||
# id - The String SHA1 hash.
|
|
||||||
PREFORMATTED_TAGS = %w(code tt)
|
|
||||||
def is_preformatted?(data, id)
|
|
||||||
doc = Nokogiri::HTML::DocumentFragment.parse(data)
|
|
||||||
node = doc.search("[text()*='#{id}']").first
|
|
||||||
node && (PREFORMATTED_TAGS.include?(node.name) ||
|
|
||||||
node.ancestors.any? { |a| PREFORMATTED_TAGS.include?(a.name) })
|
|
||||||
end
|
|
||||||
|
|
||||||
# Process a single tag into its final HTML form.
|
|
||||||
#
|
|
||||||
# tag - The String tag contents (the stuff inside the double
|
|
||||||
# brackets).
|
|
||||||
#
|
|
||||||
# Returns the String HTML version of the tag.
|
|
||||||
def process_tag(tag)
|
|
||||||
if tag =~ /^_TOC_$/
|
|
||||||
%{[[#{tag}]]}
|
|
||||||
elsif html = process_image_tag(tag)
|
|
||||||
html
|
|
||||||
elsif html = process_file_link_tag(tag)
|
|
||||||
html
|
|
||||||
else
|
|
||||||
process_page_link_tag(tag)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Attempt to process the tag as an image tag.
|
|
||||||
#
|
|
||||||
# tag - The String tag contents (the stuff inside the double brackets).
|
|
||||||
#
|
|
||||||
# Returns the String HTML if the tag is a valid image tag or nil
|
|
||||||
# if it is not.
|
|
||||||
def process_image_tag(tag)
|
|
||||||
parts = tag.split('|')
|
|
||||||
return if parts.size.zero?
|
|
||||||
|
|
||||||
name = parts[0].strip
|
|
||||||
path = if file = find_file(name)
|
|
||||||
::File.join @wiki.base_path, file.path
|
|
||||||
elsif name =~ /^https?:\/\/.+(jpg|png|gif|svg|bmp)$/i
|
|
||||||
name
|
|
||||||
end
|
|
||||||
|
|
||||||
if path
|
|
||||||
opts = parse_image_tag_options(tag)
|
|
||||||
|
|
||||||
containered = false
|
|
||||||
|
|
||||||
classes = [] # applied to whatever the outermost container is
|
|
||||||
attrs = [] # applied to the image
|
|
||||||
|
|
||||||
align = opts['align']
|
|
||||||
if opts['float']
|
|
||||||
containered = true
|
|
||||||
align ||= 'left'
|
|
||||||
if %w{left right}.include?(align)
|
|
||||||
classes << "float-#{align}"
|
|
||||||
end
|
|
||||||
elsif %w{top texttop middle absmiddle bottom absbottom baseline}.include?(align)
|
|
||||||
attrs << %{align="#{align}"}
|
|
||||||
elsif align
|
|
||||||
if %w{left center right}.include?(align)
|
|
||||||
containered = true
|
|
||||||
classes << "align-#{align}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if width = opts['width']
|
|
||||||
if width =~ /^\d+(\.\d+)?(em|px)$/
|
|
||||||
attrs << %{width="#{width}"}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if height = opts['height']
|
|
||||||
if height =~ /^\d+(\.\d+)?(em|px)$/
|
|
||||||
attrs << %{height="#{height}"}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if alt = opts['alt']
|
|
||||||
attrs << %{alt="#{alt}"}
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_string = attrs.size > 0 ? attrs.join(' ') + ' ' : ''
|
|
||||||
|
|
||||||
if opts['frame'] || containered
|
|
||||||
classes << 'frame' if opts['frame']
|
|
||||||
%{<span class="#{classes.join(' ')}">} +
|
|
||||||
%{<span>} +
|
|
||||||
%{<img src="#{path}" #{attr_string}/>} +
|
|
||||||
(alt ? %{<span>#{alt}</span>} : '') +
|
|
||||||
%{</span>} +
|
|
||||||
%{</span>}
|
|
||||||
else
|
|
||||||
%{<img src="#{path}" #{attr_string}/>}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse any options present on the image tag and extract them into a
|
|
||||||
# Hash of option names and values.
|
|
||||||
#
|
|
||||||
# tag - The String tag contents (the stuff inside the double brackets).
|
|
||||||
#
|
|
||||||
# Returns the options Hash:
|
|
||||||
# key - The String option name.
|
|
||||||
# val - The String option value or true if it is a binary option.
|
|
||||||
def parse_image_tag_options(tag)
|
|
||||||
tag.split('|')[1..-1].inject({}) do |memo, attr|
|
|
||||||
parts = attr.split('=').map { |x| x.strip }
|
|
||||||
memo[parts[0]] = (parts.size == 1 ? true : parts[1])
|
|
||||||
memo
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Attempt to process the tag as a file link tag.
|
|
||||||
#
|
|
||||||
# tag - The String tag contents (the stuff inside the double
|
|
||||||
# brackets).
|
|
||||||
#
|
|
||||||
# Returns the String HTML if the tag is a valid file link tag or nil
|
|
||||||
# if it is not.
|
|
||||||
def process_file_link_tag(tag)
|
|
||||||
parts = tag.split('|')
|
|
||||||
return if parts.size.zero?
|
|
||||||
|
|
||||||
name = parts[0].strip
|
|
||||||
path = parts[1] && parts[1].strip
|
|
||||||
path = if path && file = find_file(path)
|
|
||||||
::File.join @wiki.base_path, file.path
|
|
||||||
elsif path =~ %r{^https?://}
|
|
||||||
path
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
if name && path && file
|
|
||||||
%{<a href="#{::File.join @wiki.base_path, file.path}">#{name}</a>}
|
|
||||||
elsif name && path
|
|
||||||
%{<a href="#{path}">#{name}</a>}
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Attempt to process the tag as a page link tag.
|
|
||||||
#
|
|
||||||
# tag - The String tag contents (the stuff inside the double
|
|
||||||
# brackets).
|
|
||||||
#
|
|
||||||
# Returns the String HTML if the tag is a valid page link tag or nil
|
|
||||||
# if it is not.
|
|
||||||
def process_page_link_tag(tag)
|
|
||||||
parts = tag.split('|')
|
|
||||||
parts.reverse! if @format == :mediawiki
|
|
||||||
|
|
||||||
name, page_name = *parts.compact.map(&:strip)
|
|
||||||
cname = @wiki.page_class.cname(page_name || name)
|
|
||||||
|
|
||||||
if name =~ %r{^https?://} && page_name.nil?
|
|
||||||
%{<a href="#{name}">#{name}</a>}
|
|
||||||
else
|
|
||||||
presence = "absent"
|
|
||||||
link_name = cname
|
|
||||||
page, extra = find_page_from_name(cname)
|
|
||||||
if page
|
|
||||||
link_name = @wiki.page_class.cname(page.name)
|
|
||||||
presence = "present"
|
|
||||||
end
|
|
||||||
link = ::File.join(@wiki.base_path, page ? page.escaped_url_path : CGI.escape(link_name))
|
|
||||||
|
|
||||||
# //page is invalid
|
|
||||||
# strip all duplicate forward slashes using helpers.rb trim_leading_slash
|
|
||||||
# //page => /page
|
|
||||||
link = trim_leading_slash link
|
|
||||||
|
|
||||||
%{<a class="internal #{presence}" href="#{link}#{extra}">#{name}</a>}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# Process the special table of contents tag [[_TOC_]]
|
|
||||||
#
|
|
||||||
# data - The String data (with placeholders).
|
|
||||||
#
|
|
||||||
# Returns the marked up String data.
|
|
||||||
def process_toc_tags(data)
|
|
||||||
data.gsub!("[[_TOC_]]") do
|
|
||||||
@toc.nil? ? '' : @toc
|
|
||||||
end
|
|
||||||
data
|
|
||||||
end
|
|
||||||
|
|
||||||
# Find the given file in the repo.
|
|
||||||
#
|
|
||||||
# name - The String absolute or relative path of the file.
|
|
||||||
#
|
|
||||||
# Returns the Gollum::File or nil if none was found.
|
|
||||||
def find_file(name, version=@version)
|
|
||||||
if name =~ /^\//
|
|
||||||
@wiki.file(name[1..-1], version)
|
|
||||||
else
|
|
||||||
path = @dir == '.' ? name : ::File.join(@dir, name)
|
|
||||||
@wiki.file(path, version)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Find a page from a given cname. If the page has an anchor (#) and has
|
|
||||||
# no match, strip the anchor and try again.
|
|
||||||
#
|
|
||||||
# cname - The String canonical page name including path.
|
|
||||||
#
|
|
||||||
# Returns a Gollum::Page instance if a page is found, or an Array of
|
|
||||||
# [Gollum::Page, String extra] if a page without the extra anchor data
|
|
||||||
# is found.
|
|
||||||
def find_page_from_name(cname)
|
|
||||||
slash = cname.rindex('/')
|
|
||||||
|
|
||||||
unless slash.nil?
|
|
||||||
name = cname[slash+1..-1]
|
|
||||||
path = cname[0..slash]
|
|
||||||
page = @wiki.paged(name, path)
|
|
||||||
else
|
|
||||||
page = @wiki.paged(cname, '/')
|
|
||||||
end
|
|
||||||
|
|
||||||
if page
|
|
||||||
return page
|
|
||||||
end
|
|
||||||
if pos = cname.index('#')
|
|
||||||
[@wiki.page(cname[0...pos]), cname[pos..-1]]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#########################################################################
|
|
||||||
#
|
|
||||||
# Gitcode - fetch code from github search path and replace the contents
|
|
||||||
# to a code-block that gets run the next parse.
|
|
||||||
# Acceptable formats:
|
|
||||||
# ```language:local-file.ext```
|
|
||||||
# ```language:/abs/other-file.ext```
|
|
||||||
# ```language:github/gollum/master/somefile.txt```
|
|
||||||
#
|
|
||||||
#########################################################################
|
|
||||||
|
|
||||||
def extract_gitcode data
|
|
||||||
data.gsub /^[ \t]*``` ?([^:\n\r]+):([^`\n\r]+)```/ do
|
|
||||||
contents = ''
|
|
||||||
# Use empty string if $2 is nil.
|
|
||||||
uri = $2 || ''
|
|
||||||
# Detect local file.
|
|
||||||
if uri[0..6] != 'github/'
|
|
||||||
if file = self.find_file(uri, @wiki.ref)
|
|
||||||
contents = file.raw_data
|
|
||||||
else
|
|
||||||
# How do we communicate a render error?
|
|
||||||
next "File not found: #{Rack::Utils::escape_html(uri)}"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
contents = Gollum::Gitcode.new(uri).contents
|
|
||||||
end
|
|
||||||
|
|
||||||
"```#{$1}\n#{contents}\n```\n"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#########################################################################
|
|
||||||
#
|
|
||||||
# Code
|
|
||||||
#
|
|
||||||
#########################################################################
|
|
||||||
|
|
||||||
# Extract all code blocks into the codemap and replace with placeholders.
|
|
||||||
#
|
|
||||||
# data - The raw String data.
|
|
||||||
#
|
|
||||||
# Returns the placeholder'd String data.
|
|
||||||
def extract_code(data)
|
|
||||||
data.gsub!(/^([ \t]*)(~~~+) ?([^\r\n]+)?\r?\n(.+?)\r?\n\1(~~~+)[ \t\r]*$/m) do
|
|
||||||
m_indent = $1
|
|
||||||
m_start = $2 # ~~~
|
|
||||||
m_lang = $3
|
|
||||||
m_code = $4
|
|
||||||
m_end = $5 # ~~~
|
|
||||||
|
|
||||||
# start and finish tilde fence must be the same length
|
|
||||||
return '' if m_start.length != m_end.length
|
|
||||||
|
|
||||||
lang = m_lang ? m_lang.strip : nil
|
|
||||||
id = Digest::SHA1.hexdigest("#{lang}.#{m_code}")
|
|
||||||
cached = check_cache(:code, id)
|
|
||||||
|
|
||||||
# extract lang from { .ruby } or { #stuff .ruby .indent }
|
|
||||||
# see http://johnmacfarlane.net/pandoc/README.html#delimited-code-blocks
|
|
||||||
|
|
||||||
if lang
|
|
||||||
lang = lang.match(/\.([^}\s]+)/)
|
|
||||||
lang = lang[1] unless lang.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
@codemap[id] = cached ?
|
|
||||||
{ :output => cached } :
|
|
||||||
{ :lang => lang, :code => m_code, :indent => m_indent }
|
|
||||||
|
|
||||||
"#{m_indent}#{id}" # print the SHA1 ID with the proper indentation
|
|
||||||
end
|
|
||||||
|
|
||||||
data.gsub!(/^([ \t]*)``` ?([^\r\n]+)?\r?\n(.+?)\r?\n\1```[ \t]*\r?$/m) do
|
|
||||||
lang = $2 ? $2.strip : nil
|
|
||||||
id = Digest::SHA1.hexdigest("#{lang}.#{$3}")
|
|
||||||
cached = check_cache(:code, id)
|
|
||||||
@codemap[id] = cached ?
|
|
||||||
{ :output => cached } :
|
|
||||||
{ :lang => lang, :code => $3, :indent => $1 }
|
|
||||||
"#{$1}#{id}" # print the SHA1 ID with the proper indentation
|
|
||||||
end
|
|
||||||
data
|
|
||||||
end
|
|
||||||
|
|
||||||
# Remove the leading space from a code block. Leading space
|
|
||||||
# is only removed if every single line in the block has leading
|
|
||||||
# whitespace.
|
|
||||||
#
|
|
||||||
# code - The code block to remove spaces from
|
|
||||||
# regex - A regex to match whitespace
|
|
||||||
def remove_leading_space(code, regex)
|
|
||||||
if code.lines.all? { |line| line =~ /\A\r?\n\Z/ || line =~ regex }
|
|
||||||
code.gsub!(regex) do
|
|
||||||
''
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Process all code from the codemap and replace the placeholders with the
|
|
||||||
# final HTML.
|
|
||||||
#
|
|
||||||
# data - The String data (with placeholders).
|
|
||||||
# encoding - Encoding Constant or String.
|
|
||||||
#
|
|
||||||
# Returns the marked up String data.
|
|
||||||
def process_code(data, encoding = nil)
|
|
||||||
return data if data.nil? || data.size.zero? || @codemap.size.zero?
|
|
||||||
|
|
||||||
blocks = []
|
|
||||||
@codemap.each do |id, spec|
|
|
||||||
next if spec[:output] # cached
|
|
||||||
|
|
||||||
code = spec[:code]
|
|
||||||
|
|
||||||
remove_leading_space(code, /^#{spec[:indent]}/m)
|
|
||||||
remove_leading_space(code, /^( |\t)/m)
|
|
||||||
|
|
||||||
blocks << [spec[:lang], code]
|
|
||||||
end
|
|
||||||
|
|
||||||
highlighted = []
|
|
||||||
blocks.each do |lang, code|
|
|
||||||
encoding ||= 'utf-8'
|
|
||||||
begin
|
|
||||||
# must set startinline to true for php to be highlighted without <?
|
|
||||||
# http://pygments.org/docs/lexers/
|
|
||||||
hl_code = Pygments.highlight(code, :lexer => lang, :options => {:encoding => encoding.to_s, :startinline => true})
|
|
||||||
rescue
|
|
||||||
hl_code = code
|
|
||||||
end
|
|
||||||
highlighted << hl_code
|
|
||||||
end
|
|
||||||
|
|
||||||
@codemap.each do |id, spec|
|
|
||||||
body = spec[:output] || begin
|
|
||||||
if (body = highlighted.shift.to_s).size > 0
|
|
||||||
update_cache(:code, id, body)
|
|
||||||
body
|
|
||||||
else
|
|
||||||
"<pre><code>#{CGI.escapeHTML(spec[:code])}</code></pre>"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
data.gsub!(id) do
|
|
||||||
body
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
data
|
|
||||||
end
|
|
||||||
|
|
||||||
#########################################################################
|
|
||||||
#
|
|
||||||
# Sequence Diagrams
|
|
||||||
#
|
|
||||||
#########################################################################
|
|
||||||
|
|
||||||
# Extract all sequence diagram blocks into the wsdmap and replace with
|
|
||||||
# placeholders.
|
|
||||||
#
|
|
||||||
# data - The raw String data.
|
|
||||||
#
|
|
||||||
# Returns the placeholder'd String data.
|
|
||||||
def extract_wsd(data)
|
|
||||||
data.gsub(/^\{\{\{\{\{\{ ?(.+?)\r?\n(.+?)\r?\n\}\}\}\}\}\}\r?$/m) do
|
|
||||||
id = Digest::SHA1.hexdigest($2)
|
|
||||||
@wsdmap[id] = { :style => $1, :code => $2 }
|
|
||||||
id
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Process all diagrams from the wsdmap and replace the placeholders with
|
|
||||||
# the final HTML.
|
|
||||||
#
|
|
||||||
# data - The String data (with placeholders).
|
|
||||||
#
|
|
||||||
# Returns the marked up String data.
|
|
||||||
def process_wsd(data)
|
|
||||||
@wsdmap.each do |id, spec|
|
|
||||||
style = spec[:style]
|
|
||||||
code = spec[:code]
|
|
||||||
data.gsub!(id) do
|
|
||||||
Gollum::WebSequenceDiagram.new(code, style).to_tag
|
|
||||||
end
|
|
||||||
end
|
|
||||||
data
|
|
||||||
end
|
|
||||||
|
|
||||||
#########################################################################
|
|
||||||
#
|
|
||||||
# Metadata
|
|
||||||
#
|
|
||||||
#########################################################################
|
|
||||||
|
|
||||||
# Extract metadata for data and build metadata table. Metadata
|
|
||||||
# is content found between markers, and must
|
|
||||||
# be a valid YAML mapping.
|
|
||||||
#
|
|
||||||
# Because ri and ruby 1.8.7 are awesome, the markers can't
|
|
||||||
# be included in this documentation without triggering
|
|
||||||
# `Unhandled special: Special: type=17`
|
|
||||||
# Please read the source code for the exact markers
|
|
||||||
#
|
|
||||||
# Returns the String of formatted data with metadata removed.
|
|
||||||
def extract_metadata(data)
|
|
||||||
@metadata ||= {}
|
|
||||||
# The markers are `<!-- ---` and `-->`
|
|
||||||
data.gsub(/\<\!--+\s+---(.*?)--+\>/m) do
|
|
||||||
yaml = @wiki.sanitizer.clean($1)
|
|
||||||
hash = YAML.load(yaml)
|
|
||||||
if Hash === hash
|
|
||||||
@metadata.update(hash)
|
|
||||||
end
|
|
||||||
''
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Hook for getting the formatted value of extracted tag data.
|
|
||||||
#
|
|
||||||
# type - Symbol value identifying what type of data is being extracted.
|
|
||||||
# id - String SHA1 hash of original extracted tag data.
|
|
||||||
#
|
|
||||||
# Returns the String cached formatted data, or nil.
|
|
||||||
def check_cache(type, id)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Hook for caching the formatted value of extracted tag data.
|
|
||||||
#
|
|
||||||
# type - Symbol value identifying what type of data is being extracted.
|
|
||||||
# id - String SHA1 hash of original extracted tag data.
|
|
||||||
# data - The String formatted value to be cached.
|
|
||||||
#
|
|
||||||
# Returns nothing.
|
|
||||||
def update_cache(type, id, data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
MarkupGFM = Markup
|
|
||||||
end
|
|
||||||
@@ -1,510 +0,0 @@
|
|||||||
# ~*~ encoding: utf-8 ~*~
|
|
||||||
module Gollum
|
|
||||||
class Page
|
|
||||||
include Pagination
|
|
||||||
|
|
||||||
Wiki.page_class = self
|
|
||||||
|
|
||||||
VALID_PAGE_RE = /^(.+)\.(md|mkdn?|mdown|markdown|textile|rdoc|org|creole|re?st(\.txt)?|asciidoc|pod|(media)?wiki)$/i
|
|
||||||
FORMAT_NAMES = { :markdown => "Markdown",
|
|
||||||
:textile => "Textile",
|
|
||||||
:rdoc => "RDoc",
|
|
||||||
:org => "Org-mode",
|
|
||||||
:creole => "Creole",
|
|
||||||
:rest => "reStructuredText",
|
|
||||||
:asciidoc => "AsciiDoc",
|
|
||||||
:mediawiki => "MediaWiki",
|
|
||||||
:pod => "Pod" }
|
|
||||||
|
|
||||||
# Sets a Boolean determing whether this page is a historical version.
|
|
||||||
#
|
|
||||||
# Returns nothing.
|
|
||||||
attr_writer :historical
|
|
||||||
|
|
||||||
# Parent page if this is a sub page
|
|
||||||
#
|
|
||||||
# Returns a Page
|
|
||||||
attr_accessor :parent_page
|
|
||||||
|
|
||||||
# Checks if a filename has a valid extension understood by GitHub::Markup.
|
|
||||||
#
|
|
||||||
# filename - String filename, like "Home.md".
|
|
||||||
#
|
|
||||||
# Returns the matching String basename of the file without the extension.
|
|
||||||
def self.valid_filename?(filename)
|
|
||||||
filename && filename.to_s =~ VALID_PAGE_RE && $1
|
|
||||||
end
|
|
||||||
|
|
||||||
# Checks if a filename has a valid extension understood by GitHub::Markup.
|
|
||||||
# Also, checks if the filename has no "_" in the front (such as
|
|
||||||
# _Footer.md).
|
|
||||||
#
|
|
||||||
# filename - String filename, like "Home.md".
|
|
||||||
#
|
|
||||||
# Returns the matching String basename of the file without the extension.
|
|
||||||
def self.valid_page_name?(filename)
|
|
||||||
match = valid_filename?(filename)
|
|
||||||
filename =~ /^_/ ? false : match
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The format of a given filename.
|
|
||||||
#
|
|
||||||
# filename - The String filename.
|
|
||||||
#
|
|
||||||
# Returns the Symbol format of the page. One of:
|
|
||||||
# [ :markdown | :textile | :rdoc | :org | :rest | :asciidoc | :pod |
|
|
||||||
# :roff ]
|
|
||||||
def self.format_for(filename)
|
|
||||||
case filename.to_s
|
|
||||||
when /\.(md|mkdn?|mdown|markdown)$/i
|
|
||||||
:markdown
|
|
||||||
when /\.(textile)$/i
|
|
||||||
:textile
|
|
||||||
when /\.(rdoc)$/i
|
|
||||||
:rdoc
|
|
||||||
when /\.(org)$/i
|
|
||||||
:org
|
|
||||||
when /\.(creole)$/i
|
|
||||||
:creole
|
|
||||||
when /\.(re?st(\.txt)?)$/i
|
|
||||||
:rest
|
|
||||||
when /\.(asciidoc)$/i
|
|
||||||
:asciidoc
|
|
||||||
when /\.(pod)$/i
|
|
||||||
:pod
|
|
||||||
when /\.(\d)$/i
|
|
||||||
:roff
|
|
||||||
when /\.(media)?wiki$/i
|
|
||||||
:mediawiki
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Reusable filter to turn a filename (without path) into a canonical name.
|
|
||||||
# Strips extension, converts dashes to spaces.
|
|
||||||
#
|
|
||||||
# Returns the filtered String.
|
|
||||||
def self.canonicalize_filename(filename)
|
|
||||||
strip_filename(filename).gsub('-', ' ')
|
|
||||||
end
|
|
||||||
|
|
||||||
# Reusable filter to strip extension and path from filename
|
|
||||||
#
|
|
||||||
# filename - The string path or filename to strip
|
|
||||||
#
|
|
||||||
# Returns the stripped String.
|
|
||||||
def self.strip_filename(filename)
|
|
||||||
::File.basename(filename, ::File.extname(filename))
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: Initialize a page.
|
|
||||||
#
|
|
||||||
# wiki - The Gollum::Wiki in question.
|
|
||||||
#
|
|
||||||
# Returns a newly initialized Gollum::Page.
|
|
||||||
def initialize(wiki)
|
|
||||||
@wiki = wiki
|
|
||||||
@blob = @header = @footer = @sidebar = nil
|
|
||||||
@doc = nil
|
|
||||||
@parent_page = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The on-disk filename of the page including extension.
|
|
||||||
#
|
|
||||||
# Returns the String name.
|
|
||||||
def filename
|
|
||||||
@blob && @blob.name
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The on-disk filename of the page with extension stripped.
|
|
||||||
#
|
|
||||||
# Returns the String name.
|
|
||||||
def filename_stripped
|
|
||||||
self.class.strip_filename(filename)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The canonical page name without extension, and dashes converted
|
|
||||||
# to spaces.
|
|
||||||
#
|
|
||||||
# Returns the String name.
|
|
||||||
def name
|
|
||||||
self.class.canonicalize_filename(filename)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The title will be constructed from the
|
|
||||||
# filename by stripping the extension and replacing any dashes with
|
|
||||||
# spaces.
|
|
||||||
#
|
|
||||||
# Returns the fully sanitized String title.
|
|
||||||
def title
|
|
||||||
Sanitize.clean(name).strip
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: Determines if this is a sub-page
|
|
||||||
# Sub-pages have filenames beginning with an underscore
|
|
||||||
#
|
|
||||||
# Returns true or false.
|
|
||||||
def sub_page
|
|
||||||
filename =~ /^_/
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The path of the page within the repo.
|
|
||||||
#
|
|
||||||
# Returns the String path.
|
|
||||||
attr_reader :path
|
|
||||||
|
|
||||||
# Public: The url path required to reach this page within the repo.
|
|
||||||
#
|
|
||||||
# Returns the String url_path
|
|
||||||
def url_path
|
|
||||||
path = if self.path.include?('/')
|
|
||||||
self.path.sub(/\/[^\/]+$/, '/')
|
|
||||||
else
|
|
||||||
''
|
|
||||||
end
|
|
||||||
|
|
||||||
path << Page.cname(self.name, '-', '-')
|
|
||||||
path
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: Defines title for page.rb
|
|
||||||
#
|
|
||||||
# Returns the String title
|
|
||||||
def url_path_title
|
|
||||||
metadata_title || url_path.gsub("-", " ")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: Metadata title
|
|
||||||
#
|
|
||||||
# Set with <!-- --- title: New Title --> in page content
|
|
||||||
#
|
|
||||||
# Returns the String title or nil if not defined
|
|
||||||
def metadata_title
|
|
||||||
if metadata
|
|
||||||
title = metadata['title']
|
|
||||||
return title unless title.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The url_path, but CGI escaped.
|
|
||||||
#
|
|
||||||
# Returns the String url_path
|
|
||||||
def escaped_url_path
|
|
||||||
CGI.escape(self.url_path).gsub('%2F','/')
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The raw contents of the page.
|
|
||||||
#
|
|
||||||
# Returns the String data.
|
|
||||||
def raw_data
|
|
||||||
@blob && @blob.data
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: A text data encoded in specified encoding.
|
|
||||||
#
|
|
||||||
# encoding - An Encoding or nil
|
|
||||||
#
|
|
||||||
# Returns a character encoding aware String.
|
|
||||||
def text_data(encoding=nil)
|
|
||||||
if raw_data.respond_to?(:encoding)
|
|
||||||
raw_data.force_encoding(encoding || Encoding::UTF_8)
|
|
||||||
else
|
|
||||||
raw_data
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The formatted contents of the page.
|
|
||||||
#
|
|
||||||
# encoding - Encoding Constant or String.
|
|
||||||
#
|
|
||||||
# Returns the String data.
|
|
||||||
def formatted_data(encoding = nil, &block)
|
|
||||||
@blob && markup_class.render(historical?, encoding) do |doc|
|
|
||||||
@doc = doc
|
|
||||||
yield doc if block_given?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The table of contents of the page.
|
|
||||||
#
|
|
||||||
# formatted_data - page already marked up in html.
|
|
||||||
#
|
|
||||||
# Returns the String data.
|
|
||||||
def toc_data()
|
|
||||||
return @parent_page.toc_data if @parent_page and @sub_page
|
|
||||||
formatted_data if markup_class.toc == nil
|
|
||||||
markup_class.toc
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: Embedded metadata.
|
|
||||||
#
|
|
||||||
# Returns Hash of metadata.
|
|
||||||
def metadata()
|
|
||||||
formatted_data if markup_class.metadata == nil
|
|
||||||
markup_class.metadata
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The format of the page.
|
|
||||||
#
|
|
||||||
# Returns the Symbol format of the page. One of:
|
|
||||||
# [ :markdown | :textile | :rdoc | :org | :rest | :asciidoc | :pod |
|
|
||||||
# :roff ]
|
|
||||||
def format
|
|
||||||
self.class.format_for(@blob.name)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Gets the Gollum::Markup instance that will render this page's content.
|
|
||||||
#
|
|
||||||
# Returns a Gollum::Markup instance.
|
|
||||||
def markup_class
|
|
||||||
@markup_class ||= @wiki.markup_classes[format].new(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The current version of the page.
|
|
||||||
#
|
|
||||||
# Returns the Grit::Commit.
|
|
||||||
attr_reader :version
|
|
||||||
|
|
||||||
# Public: All of the versions that have touched the Page.
|
|
||||||
#
|
|
||||||
# options - The options Hash:
|
|
||||||
# :page - The Integer page number (default: 1).
|
|
||||||
# :per_page - The Integer max count of items to return.
|
|
||||||
# :follow - Follow's a file across renames, but falls back
|
|
||||||
# to a slower Grit native call. (default: false)
|
|
||||||
#
|
|
||||||
# Returns an Array of Grit::Commit.
|
|
||||||
def versions(options = {})
|
|
||||||
if options[:follow]
|
|
||||||
options[:pretty] = 'raw'
|
|
||||||
options.delete :max_count
|
|
||||||
options.delete :skip
|
|
||||||
log = @wiki.repo.git.native "log", options, @wiki.ref, "--", @path
|
|
||||||
Grit::Commit.list_from_string(@wiki.repo, log)
|
|
||||||
else
|
|
||||||
@wiki.repo.log(@wiki.ref, @path, log_pagination_options(options))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The first 7 characters of the current version.
|
|
||||||
#
|
|
||||||
# Returns the first 7 characters of the current version.
|
|
||||||
def version_short
|
|
||||||
version.to_s[0,7]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The header Page.
|
|
||||||
#
|
|
||||||
# Returns the header Page or nil if none exists.
|
|
||||||
def header
|
|
||||||
@header ||= find_sub_page(:header)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The footer Page.
|
|
||||||
#
|
|
||||||
# Returns the footer Page or nil if none exists.
|
|
||||||
def footer
|
|
||||||
@footer ||= find_sub_page(:footer)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Public: The sidebar Page.
|
|
||||||
#
|
|
||||||
# Returns the sidebar Page or nil if none exists.
|
|
||||||
def sidebar
|
|
||||||
@sidebar ||= find_sub_page(:sidebar)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Gets a Boolean determining whether this page is a historical version.
|
|
||||||
# Historical pages are pulled using exact SHA hashes and format all links
|
|
||||||
# with rel="nofollow"
|
|
||||||
#
|
|
||||||
# Returns true if the page is pulled from a named branch or tag, or false.
|
|
||||||
def historical?
|
|
||||||
!!@historical
|
|
||||||
end
|
|
||||||
|
|
||||||
#########################################################################
|
|
||||||
#
|
|
||||||
# Class Methods
|
|
||||||
#
|
|
||||||
#########################################################################
|
|
||||||
|
|
||||||
# Convert a human page name into a canonical page name.
|
|
||||||
#
|
|
||||||
# name - The String human page name.
|
|
||||||
# char_white_sub - Substitution for whitespace
|
|
||||||
# char_other_sub - Substitution for other special chars
|
|
||||||
#
|
|
||||||
# Examples
|
|
||||||
#
|
|
||||||
# Page.cname("Bilbo Baggins")
|
|
||||||
# # => 'Bilbo-Baggins'
|
|
||||||
#
|
|
||||||
# Page.cname("Bilbo Baggins",'_')
|
|
||||||
# # => 'Bilbo_Baggins'
|
|
||||||
#
|
|
||||||
# Returns the String canonical name.
|
|
||||||
def self.cname(name, char_white_sub = '-', char_other_sub = '-')
|
|
||||||
name.respond_to?(:gsub) ?
|
|
||||||
name.gsub(%r{\s},char_white_sub).gsub(%r{[<>+]}, char_other_sub) :
|
|
||||||
''
|
|
||||||
end
|
|
||||||
|
|
||||||
# Convert a format Symbol into an extension String.
|
|
||||||
#
|
|
||||||
# format - The format Symbol.
|
|
||||||
#
|
|
||||||
# Returns the String extension (no leading period).
|
|
||||||
def self.format_to_ext(format)
|
|
||||||
case format
|
|
||||||
when :markdown then 'md'
|
|
||||||
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'
|
|
||||||
when :mediawiki then 'mediawiki'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#########################################################################
|
|
||||||
#
|
|
||||||
# Internal Methods
|
|
||||||
#
|
|
||||||
#########################################################################
|
|
||||||
|
|
||||||
# The underlying wiki repo.
|
|
||||||
#
|
|
||||||
# Returns the Gollum::Wiki containing the page.
|
|
||||||
attr_reader :wiki
|
|
||||||
|
|
||||||
# Set the Grit::Commit version of the page.
|
|
||||||
#
|
|
||||||
# Returns nothing.
|
|
||||||
attr_writer :version
|
|
||||||
|
|
||||||
# Find a page in the given Gollum repo.
|
|
||||||
#
|
|
||||||
# name - The human or canonical String page name to find.
|
|
||||||
# version - The String version ID to find.
|
|
||||||
#
|
|
||||||
# Returns a Gollum::Page or nil if the page could not be found.
|
|
||||||
def find(name, version, dir = nil, exact = false)
|
|
||||||
map = @wiki.tree_map_for(version.to_s)
|
|
||||||
if page = find_page_in_tree(map, name, dir, exact)
|
|
||||||
page.version = version.is_a?(Grit::Commit) ?
|
|
||||||
version : @wiki.commit_for(version)
|
|
||||||
page.historical = page.version.to_s == version.to_s
|
|
||||||
page
|
|
||||||
end
|
|
||||||
rescue Grit::GitRuby::Repository::NoSuchShaFound
|
|
||||||
end
|
|
||||||
|
|
||||||
# Find a page in a given tree.
|
|
||||||
#
|
|
||||||
# map - The Array tree map from Wiki#tree_map.
|
|
||||||
# name - The canonical String page name.
|
|
||||||
# checked_dir - Optional String of the directory a matching page needs
|
|
||||||
# to be in. The string should
|
|
||||||
#
|
|
||||||
# Returns a Gollum::Page or nil if the page could not be found.
|
|
||||||
def find_page_in_tree(map, name, checked_dir = nil, exact = false)
|
|
||||||
return nil if !map || name.to_s.empty?
|
|
||||||
if checked_dir = BlobEntry.normalize_dir(checked_dir)
|
|
||||||
checked_dir.downcase!
|
|
||||||
end
|
|
||||||
|
|
||||||
checked_dir = '' if exact && checked_dir.nil?
|
|
||||||
|
|
||||||
map.each do |entry|
|
|
||||||
next if entry.name.to_s.empty?
|
|
||||||
next unless checked_dir.nil? || entry.dir.downcase == checked_dir
|
|
||||||
next unless page_match(name, entry.name)
|
|
||||||
return entry.page(@wiki, @version)
|
|
||||||
end
|
|
||||||
|
|
||||||
return nil # nothing was found
|
|
||||||
end
|
|
||||||
|
|
||||||
# Populate the Page with information from the Blob.
|
|
||||||
#
|
|
||||||
# blob - The Grit::Blob that contains the info.
|
|
||||||
# path - The String directory path of the page file.
|
|
||||||
#
|
|
||||||
# Returns the populated Gollum::Page.
|
|
||||||
def populate(blob, path=nil)
|
|
||||||
@blob = blob
|
|
||||||
@path = "#{path}/#{blob.name}"[1..-1]
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
# The full directory path for the given tree.
|
|
||||||
#
|
|
||||||
# treemap - The Hash treemap containing parentage information.
|
|
||||||
# tree - The Grit::Tree for which to compute the path.
|
|
||||||
#
|
|
||||||
# Returns the String path.
|
|
||||||
def tree_path(treemap, tree)
|
|
||||||
if ptree = treemap[tree]
|
|
||||||
tree_path(treemap, ptree) + '/' + tree.name
|
|
||||||
else
|
|
||||||
''
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Compare the canonicalized versions of the two names.
|
|
||||||
#
|
|
||||||
# name - The human or canonical String page name.
|
|
||||||
# filename - the String filename on disk (including extension).
|
|
||||||
#
|
|
||||||
# Returns a Boolean.
|
|
||||||
def page_match(name, filename)
|
|
||||||
if match = self.class.valid_filename?(filename)
|
|
||||||
@wiki.ws_subs.each do |sub|
|
|
||||||
return true if Page.cname(name).downcase == Page.cname(match, sub).downcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
# Loads a sub page. Sub page names (footers, headers, sidebars) are prefixed with
|
|
||||||
# an underscore to distinguish them from other Pages. If there is not one within
|
|
||||||
# the current directory, starts walking up the directory tree to try and find one
|
|
||||||
# within parent directories.
|
|
||||||
#
|
|
||||||
# name - String page name.
|
|
||||||
#
|
|
||||||
# Returns the Page or nil if none exists.
|
|
||||||
def find_sub_page(name)
|
|
||||||
return nil unless self.version
|
|
||||||
return nil if self.filename =~ /^_/
|
|
||||||
name = "_#{name.to_s.capitalize}"
|
|
||||||
return nil if page_match(name, self.filename)
|
|
||||||
|
|
||||||
dirs = self.path.split('/')
|
|
||||||
dirs.pop
|
|
||||||
map = @wiki.tree_map_for(@wiki.ref, true)
|
|
||||||
while !dirs.empty?
|
|
||||||
if page = find_page_in_tree(map, name, dirs.join('/'))
|
|
||||||
page.parent_page = self
|
|
||||||
return page
|
|
||||||
end
|
|
||||||
dirs.pop
|
|
||||||
end
|
|
||||||
|
|
||||||
if page = find_page_in_tree(map, name, '')
|
|
||||||
page.parent_page = self
|
|
||||||
end
|
|
||||||
page
|
|
||||||
end
|
|
||||||
|
|
||||||
def inspect
|
|
||||||
%(#<#{self.class.name}:#{object_id} #{name} (#{format}) @wiki=#{@wiki.repo.path.inspect}>)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
# ~*~ encoding: utf-8 ~*~
|
|
||||||
module Gollum
|
|
||||||
module Pagination
|
|
||||||
def self.included(klass)
|
|
||||||
klass.extend ClassMethods
|
|
||||||
class << klass
|
|
||||||
# Default Integer max count of items to return in git commands.
|
|
||||||
attr_accessor :per_page
|
|
||||||
end
|
|
||||||
klass.per_page = 30
|
|
||||||
end
|
|
||||||
|
|
||||||
module ClassMethods
|
|
||||||
# Turns a page number into an offset number for the git skip option.
|
|
||||||
#
|
|
||||||
# page - Integer page number.
|
|
||||||
#
|
|
||||||
# Returns an Integer.
|
|
||||||
def page_to_skip(page)
|
|
||||||
([1, page.to_i].max - 1) * per_page
|
|
||||||
end
|
|
||||||
|
|
||||||
# Fills in git-specific options for the log command using simple
|
|
||||||
# pagination options.
|
|
||||||
#
|
|
||||||
# options - Hash of options:
|
|
||||||
# page - Optional Integer page number (default: 1)
|
|
||||||
# per_page - Optional Integer max count of items to return.
|
|
||||||
# Defaults to #per_class class method.
|
|
||||||
#
|
|
||||||
# Returns Hash with :max_count and :skip keys.
|
|
||||||
def log_pagination_options(options = {})
|
|
||||||
skip = page_to_skip(options.delete(:page))
|
|
||||||
options[:max_count] = [options.delete(:per_page).to_i, per_page].max
|
|
||||||
options[:skip] = skip if skip > 0
|
|
||||||
options
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Turns a page number into an offset number for the git skip option.
|
|
||||||
#
|
|
||||||
# page - Integer page number.
|
|
||||||
#
|
|
||||||
# Returns an Integer.
|
|
||||||
def page_to_skip(page)
|
|
||||||
self.class.page_to_skip(page)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Fills in git-specific options for the log command using simple
|
|
||||||
# pagination options.
|
|
||||||
#
|
|
||||||
# options - Hash of options:
|
|
||||||
# page - Optional Integer page number (default: 1)
|
|
||||||
# per_page - Optional Integer max count of items to return.
|
|
||||||
# Defaults to #per_class class method.
|
|
||||||
#
|
|
||||||
# Returns Hash with :max_count and :skip keys.
|
|
||||||
def log_pagination_options(options = {})
|
|
||||||
self.class.log_pagination_options(options)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -80,13 +80,23 @@
|
|||||||
line-height: 1.6em;
|
line-height: 1.6em;
|
||||||
margin: 0.3em 0 0 0;
|
margin: 0.3em 0 0 0;
|
||||||
padding: 0.3em 0.5em;
|
padding: 0.3em 0.5em;
|
||||||
width: 96.5%;
|
width: 94%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#gollum-dialog-dialog-body fieldset .field input.code {
|
#gollum-dialog-dialog-body fieldset .field input.code {
|
||||||
font-family: 'Monaco', 'Courier New', Courier, monospace;
|
font-family: 'Monaco', 'Courier New', Courier, monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#gollum-dialog-dialog-body fieldset .field span.context {
|
||||||
|
font-size: .9em;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
#gollum-dialog-dialog-body fieldset .field span.context span.path {
|
||||||
|
font-family: 'Monaco', 'Courier New', Courier, monospace;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#gollum-dialog-dialog-body fieldset .field:last-child {
|
#gollum-dialog-dialog-body fieldset .field:last-child {
|
||||||
margin: 0 0 1em 0;
|
margin: 0 0 1em 0;
|
||||||
}
|
}
|
||||||
@@ -138,4 +148,4 @@
|
|||||||
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#599bdc', endColorstr='#3072b3');
|
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#599bdc', endColorstr='#3072b3');
|
||||||
background: -webkit-gradient(linear, left top, left bottom, from(#599bdc), to(#3072b3));
|
background: -webkit-gradient(linear, left top, left bottom, from(#599bdc), to(#3072b3));
|
||||||
background: -moz-linear-gradient(top, #599bdc, #3072b3);
|
background: -moz-linear-gradient(top, #599bdc, #3072b3);
|
||||||
}
|
}
|
||||||
@@ -243,7 +243,7 @@ a#function-help:hover span { background-position: -405px -28px; }
|
|||||||
background: #fff;
|
background: #fff;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
font-family: Consolas, "Liberation Mono", Courier, monospace;
|
||||||
line-height: 1.4em;
|
line-height: 1.4em;
|
||||||
margin: 1em 0 0.4em;
|
margin: 1em 0 0.4em;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
@@ -74,6 +74,12 @@ a:hover, a:visited {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* @section body */
|
/* @section body */
|
||||||
|
|
||||||
|
.has-leftbar #wiki-body {
|
||||||
|
float: right;
|
||||||
|
clear: right;
|
||||||
|
}
|
||||||
|
|
||||||
#wiki-body {
|
#wiki-body {
|
||||||
display: block;
|
display: block;
|
||||||
float: left;
|
float: left;
|
||||||
@@ -83,7 +89,7 @@ a:hover, a:visited {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-rightbar #wiki-body {
|
.has-sidebar #wiki-body {
|
||||||
width: 68%;
|
width: 68%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +99,7 @@ a:hover, a:visited {
|
|||||||
border: 1px solid #DDD;
|
border: 1px solid #DDD;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
padding: 0px 5px;
|
padding: 0px 5px;
|
||||||
float:left;
|
float: left;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
min-width: 33%;
|
min-width: 33%;
|
||||||
|
|
||||||
@@ -105,12 +111,19 @@ a:hover, a:visited {
|
|||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @section rightbar */
|
/* @section sidebar */
|
||||||
#wiki-rightbar {
|
.has-leftbar #wiki-sidebar {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.has-rightbar #wiki-sidebar {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#wiki-sidebar {
|
||||||
background-color: #f7f7f7;
|
background-color: #f7f7f7;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
float: right;
|
|
||||||
padding: 7px;
|
padding: 7px;
|
||||||
width: 25%;
|
width: 25%;
|
||||||
color: #555;
|
color: #555;
|
||||||
@@ -120,15 +133,15 @@ a:hover, a:visited {
|
|||||||
-webkit-border-radius: 0.5em;
|
-webkit-border-radius: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#wiki-rightbar p {
|
#wiki-sidebar p {
|
||||||
margin: 13px 0 0;
|
margin: 13px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#wiki-rightbar > p:first-child {
|
#wiki-sidebar > p:first-child {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#wiki-rightbar p.parent {
|
#wiki-sidebar p.parent {
|
||||||
border-bottom: 1px solid #bbb;
|
border-bottom: 1px solid #bbb;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 0 0 0.5em 0;
|
margin: 0 0 0.5em 0;
|
||||||
@@ -137,7 +150,7 @@ a:hover, a:visited {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Back arrow */
|
/* Back arrow */
|
||||||
#wiki-rightbar p.parent:before {
|
#wiki-sidebar p.parent:before {
|
||||||
color: #666;
|
color: #666;
|
||||||
content: "← ";
|
content: "← ";
|
||||||
}
|
}
|
||||||
@@ -149,7 +162,7 @@ a:hover, a:visited {
|
|||||||
margin: 2em 0 5em;
|
margin: 2em 0 5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-rightbar #wiki-footer {
|
.has-sidebar #wiki-footer {
|
||||||
width: 70%;
|
width: 70%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,3 +729,6 @@ ul.actions {
|
|||||||
padding: 0.25em;
|
padding: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clearfloats {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
@@ -124,7 +124,8 @@ a.absent {
|
|||||||
.markdown-body ol,
|
.markdown-body ol,
|
||||||
.markdown-body dl,
|
.markdown-body dl,
|
||||||
.markdown-body table,
|
.markdown-body table,
|
||||||
.markdown-body pre {
|
.markdown-body pre,
|
||||||
|
.markdown-body hr {
|
||||||
margin: 0px 0;
|
margin: 0px 0;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 939 B After Width: | Height: | Size: 939 B |
|
Before Width: | Height: | Size: 177 B After Width: | Height: | Size: 177 B |
|
Before Width: | Height: | Size: 271 B After Width: | Height: | Size: 271 B |
|
Before Width: | Height: | Size: 433 B After Width: | Height: | Size: 433 B |
|
Before Width: | Height: | Size: 462 B After Width: | Height: | Size: 462 B |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 376 B After Width: | Height: | Size: 376 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
@@ -38,7 +38,9 @@
|
|||||||
$.GollumEditor.Placeholder.add($('#gollum-editor-edit-summary input'));
|
$.GollumEditor.Placeholder.add($('#gollum-editor-edit-summary input'));
|
||||||
$('#gollum-editor form[name="gollum-editor"]').submit(function( e ) {
|
$('#gollum-editor form[name="gollum-editor"]').submit(function( e ) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$.GollumEditor.Placeholder.clearAll();
|
// Do not clear default place holder text
|
||||||
|
// Updated home (markdown)
|
||||||
|
// $.GollumEditor.Placeholder.clearAll();
|
||||||
debug('submitting');
|
debug('submitting');
|
||||||
$(this).unbind('submit');
|
$(this).unbind('submit');
|
||||||
$(this).submit();
|
$(this).submit();
|
||||||
@@ -37,11 +37,14 @@
|
|||||||
fieldMarkup += '<div class="field">';
|
fieldMarkup += '<div class="field">';
|
||||||
switch ( fieldArray[i].type ) {
|
switch ( fieldArray[i].type ) {
|
||||||
|
|
||||||
// only text is supported for now
|
|
||||||
case 'text':
|
case 'text':
|
||||||
fieldMarkup += Dialog.createFieldText( fieldArray[i] );
|
fieldMarkup += Dialog.createFieldText( fieldArray[i] );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'file':
|
||||||
|
fieldMarkup += Dialog.createFieldFile( fieldArray[i] );
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -60,7 +63,7 @@
|
|||||||
if ( fieldAttributes.name ) {
|
if ( fieldAttributes.name ) {
|
||||||
html += '<label';
|
html += '<label';
|
||||||
if ( fieldAttributes.id ) {
|
if ( fieldAttributes.id ) {
|
||||||
html += ' for="' + fieldAttributes.name + '"';
|
html += ' for="gollum-dialog-dialog-generated-field-' + fieldAttributes.id + '"';
|
||||||
}
|
}
|
||||||
html += '>' + fieldAttributes.name + '</label>';
|
html += '>' + fieldAttributes.name + '</label>';
|
||||||
}
|
}
|
||||||
@@ -79,6 +82,30 @@
|
|||||||
fieldAttributes.id + '">';
|
fieldAttributes.id + '">';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( fieldAttributes.context ){
|
||||||
|
html += '<span class="context">' + fieldAttributes.context + '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return html;
|
||||||
|
},
|
||||||
|
|
||||||
|
createFieldFile: function( fieldAttributes ) {
|
||||||
|
// Not actually a field, but an embedded form.
|
||||||
|
var html = '';
|
||||||
|
|
||||||
|
var id = fieldAttributes.id || 'upload';
|
||||||
|
var name = fieldAttributes.name || 'file';
|
||||||
|
var action = fieldAttributes.action || '/uploadFile';
|
||||||
|
|
||||||
|
html += '<form method=post enctype="multipart/form-data" ' +
|
||||||
|
'action="' + action + '" ' + 'id="' + id + '">';
|
||||||
|
html += '<input type=file name="' + name + '">';
|
||||||
|
html += '</form>';
|
||||||
|
|
||||||
|
if( fieldAttributes.context ){
|
||||||
|
html += '<span class="context">' + fieldAttributes.context + '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
return html;
|
return html;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1,10 +1,47 @@
|
|||||||
|
// Helpers
|
||||||
|
function pageName(){
|
||||||
|
// "my/dir/file" => "file"
|
||||||
|
return typeof(pageFullPath) == 'undefined' ? undefined : pageFullPath.split('/').pop();
|
||||||
|
}
|
||||||
|
function pagePath(){
|
||||||
|
// "my/dir/file" => "my/dir"
|
||||||
|
return typeof(pageFullPath) == 'undefined' ? undefined : pageFullPath.split('/').slice(0,-1).join('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic HTML escape function
|
||||||
|
function htmlEscape( str ) {
|
||||||
|
// The (slower) alternative is: return $('<div/>').text(str).html();
|
||||||
|
// http://stackoverflow.com/questions/1219860/javascript-jquery-html-encoding/7124052#7124052
|
||||||
|
return String(str)
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a page name and a current path, returns a fully qualified path.
|
||||||
|
function abspath(path, name){
|
||||||
|
// Make sure the given path starts at the root.
|
||||||
|
if(name[0] != '/'){
|
||||||
|
name = '/' + name;
|
||||||
|
if (path) {
|
||||||
|
name = '/' + path + name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var name_parts = name.split('/');
|
||||||
|
var newPath = name_parts.slice(0, -1).join('/');
|
||||||
|
var newName = name_parts.pop();
|
||||||
|
// return array of [path, name]
|
||||||
|
return [newPath, newName];
|
||||||
|
}
|
||||||
|
|
||||||
// ua
|
// ua
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('#delete-link').click( function(e) {
|
$('#delete-link').click( function(e) {
|
||||||
var ok = confirm($(this).data('confirm'));
|
var ok = confirm($(this).data('confirm'));
|
||||||
if ( ok ) {
|
if ( ok ) {
|
||||||
var loc = window.location;
|
var loc = baseUrl + '/delete/' + pageFullPath;
|
||||||
loc = baseUrl + '/delete' + loc.pathname.replace(baseUrl,'');
|
|
||||||
window.location = loc;
|
window.location = loc;
|
||||||
}
|
}
|
||||||
// Don't navigate on cancel.
|
// Don't navigate on cancel.
|
||||||
@@ -108,16 +145,37 @@ $(document).ready(function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($('#minibutton-upload-page').length) {
|
||||||
|
$('#minibutton-upload-page').parent().removeClass('jaws');
|
||||||
|
$('#minibutton-upload-page').click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
$.GollumDialog.init({
|
||||||
|
title: 'Upload File',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'file',
|
||||||
|
context: 'Your uploaded file will be accessible at /uploads/[filename]'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
OK: function( res ) {
|
||||||
|
$('#upload').submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if ($('#minibutton-rename-page').length) {
|
if ($('#minibutton-rename-page').length) {
|
||||||
$('#minibutton-rename-page').removeClass('jaws');
|
$('#minibutton-rename-page').parent().removeClass('jaws');
|
||||||
$('#minibutton-rename-page').click(function(e) {
|
$('#minibutton-rename-page').click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
// Path name without the leading slash.
|
var path = pagePath();
|
||||||
var pathname = window.location.pathname.substr(1);
|
var oldName = pageName();
|
||||||
var slashIndex = pathname.lastIndexOf('/');
|
var context_blurb =
|
||||||
var oldName = pathname.substr(slashIndex + 1)
|
"Renamed page will be under " +
|
||||||
var path = pathname.substr(0, slashIndex);
|
"<span class='path'>" + htmlEscape('/' + path) + "</span>" +
|
||||||
|
" unless an absolute path is given."
|
||||||
|
|
||||||
$.GollumDialog.init({
|
$.GollumDialog.init({
|
||||||
title: 'Rename Page',
|
title: 'Rename Page',
|
||||||
@@ -126,7 +184,8 @@ $(document).ready(function() {
|
|||||||
id: 'name',
|
id: 'name',
|
||||||
name: 'Rename to',
|
name: 'Rename to',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
defaultValue: oldName || ''
|
defaultValue: oldName || '',
|
||||||
|
context: context_blurb
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
OK: function( res ) {
|
OK: function( res ) {
|
||||||
@@ -134,26 +193,44 @@ $(document).ready(function() {
|
|||||||
if ( res['name'] ) {
|
if ( res['name'] ) {
|
||||||
newName = res['name'];
|
newName = res['name'];
|
||||||
}
|
}
|
||||||
|
var name_parts = abspath(path, newName);
|
||||||
|
var newPath = name_parts[0];
|
||||||
|
|
||||||
var msg = 'Renamed ' + oldName + ' to ' + newName;
|
var msg = '/' + path == newPath ? 'Renamed ' + oldName + ' to ' + newName
|
||||||
jQuery.ajax( {
|
: 'Renamed ' + oldName + ' to ' + name_parts.join('/');
|
||||||
type: 'POST',
|
// Fill in the rename form
|
||||||
url: baseUrl + '/edit/' + oldName,
|
// This is preferable to AJAX so that we automatically follow the 302 response.
|
||||||
data: { path: path, rename: newName, page: oldName, message: msg },
|
var rename_form = $("form[name=rename]");
|
||||||
success: function() {
|
rename_form.children("input[name=rename]").val(name_parts.join('/'));
|
||||||
window.location = baseUrl + '/' + encodeURIComponent(newName);
|
rename_form.children("input[name=message]").val(msg);
|
||||||
}
|
rename_form.submit();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($('#minibutton-new-page').length) {
|
if ($('#minibutton-new-page').length) {
|
||||||
$('#minibutton-new-page').removeClass('jaws');
|
$('#minibutton-new-page').parent().removeClass('jaws');
|
||||||
$('#minibutton-new-page').click(function(e) {
|
$('#minibutton-new-page').click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
var path = pagePath();
|
||||||
|
if( path === undefined && $('#file-browser').length != 0 ){
|
||||||
|
// In the pages view, pageFullPath isn't defined.
|
||||||
|
// The new button will still expect a value however.
|
||||||
|
// So we try to figure one out from window.location
|
||||||
|
path = baseUrl == '' ? window.location.pathname.substr(1)
|
||||||
|
: window.location.pathname.substr(baseUrl.length + 1);
|
||||||
|
// Remove the page viewer part of the url.
|
||||||
|
path = path.replace(/^pages\/?/,'')
|
||||||
|
// For consistency remove the trailing /
|
||||||
|
path = path.replace(/\/$/,'')
|
||||||
|
}
|
||||||
|
var context_blurb =
|
||||||
|
"Page will be created under " +
|
||||||
|
"<span class='path'>" + htmlEscape('/' + path) + "</span>" +
|
||||||
|
" unless an absolute path is given."
|
||||||
|
|
||||||
$.GollumDialog.init({
|
$.GollumDialog.init({
|
||||||
title: 'Create New Page',
|
title: 'Create New Page',
|
||||||
fields: [
|
fields: [
|
||||||
@@ -161,7 +238,8 @@ $(document).ready(function() {
|
|||||||
id: 'name',
|
id: 'name',
|
||||||
name: 'Page Name',
|
name: 'Page Name',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
defaultValue: ''
|
defaultValue: '',
|
||||||
|
context: context_blurb
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
OK: function( res ) {
|
OK: function( res ) {
|
||||||
@@ -169,7 +247,13 @@ $(document).ready(function() {
|
|||||||
if ( res['name'] ) {
|
if ( res['name'] ) {
|
||||||
name = res['name'];
|
name = res['name'];
|
||||||
}
|
}
|
||||||
window.location = baseUrl + '/' + encodeURIComponent(name);
|
var name_encoded = [];
|
||||||
|
var name_parts = abspath(path, name).join('/').split('/');
|
||||||
|
// Split and encode each component individually.
|
||||||
|
for( var i=0; i < name_parts.length; i++ ){
|
||||||
|
name_encoded.push(encodeURIComponent(name_parts[i]));
|
||||||
|
}
|
||||||
|
window.location = baseUrl + name_encoded.join('/');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Before Width: | Height: | Size: 525 B After Width: | Height: | Size: 525 B |
|
Before Width: | Height: | Size: 630 B After Width: | Height: | Size: 630 B |
|
Before Width: | Height: | Size: 919 B After Width: | Height: | Size: 919 B |
|
Before Width: | Height: | Size: 235 B After Width: | Height: | Size: 235 B |
|
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 278 B |
|
Before Width: | Height: | Size: 759 B After Width: | Height: | Size: 759 B |
|
Before Width: | Height: | Size: 290 B After Width: | Height: | Size: 290 B |