Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 049db3eb69 | |||
| 395bf26a4b | |||
| d2be3a2347 | |||
| f0b49bc175 | |||
| d66a46f044 | |||
| ce85301e70 | |||
| b0a1f8a004 | |||
| 10ae969139 | |||
| 738d6f6ec4 | |||
| 98cb39347d | |||
| a1406da44a | |||
| 0d71655aa3 | |||
| ee512bdad5 | |||
| 738f8ed462 | |||
| c52ad667da | |||
| 9e722c5033 | |||
| 9c2f8dfeba | |||
| 8e35688b17 | |||
| 860e8b2ebd | |||
| 0d2ab11604 | |||
| ddc7dba0a2 | |||
| bc3503f374 | |||
| 2dfe103687 | |||
| 95d35d38da | |||
| 81c90e55a7 | |||
| 3f0b61081b | |||
| ecc317886a | |||
| 4b2dc8e5c0 | |||
| 6f870501a0 | |||
| f30058f4ee | |||
| 82ce013cab | |||
| 0c36cdf5ba | |||
| 6159fcd4a2 | |||
| 8f7793f461 | |||
| 589b4bce39 | |||
| 9c574fd760 | |||
| 46c22a8b87 | |||
| 7e379cfab1 | |||
| 93d3d10453 | |||
| 98a0006c86 |
@@ -1,12 +1,22 @@
|
|||||||
name: Deploy docker
|
name: Deploy docker
|
||||||
on: [push]
|
on:
|
||||||
env:
|
push:
|
||||||
DEPLOY_NAME: gollumwiki/gollum:latest
|
branches:
|
||||||
|
- master
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ github.ref == 'refs/heads/master' }}
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: Set deploy name to master
|
||||||
|
if: github.ref == 'refs/heads/master'
|
||||||
|
run: |
|
||||||
|
echo "DEPLOY_NAME=gollumwiki/gollum:master" >> $GITHUB_ENV
|
||||||
|
- name: Set deploy name to release version
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
run: |
|
||||||
|
echo "DEPLOY_NAME=gollumwiki/gollum:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||||
- name: Check Out Repo
|
- name: Check Out Repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Login
|
- name: Login
|
||||||
@@ -35,5 +45,6 @@ jobs:
|
|||||||
tags: ${{ env.DEPLOY_NAME }}
|
tags: ${{ env.DEPLOY_NAME }}
|
||||||
cache-from: type=local,src=/tmp/.buildx-cache
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||||
|
platforms: linux/amd64, linux/arm64
|
||||||
- name: Image digest
|
- name: Image digest
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
|
|||||||
@@ -34,5 +34,5 @@ jobs:
|
|||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
- name: docker state
|
- name: docker state
|
||||||
run: docker image ls
|
run: docker image ls
|
||||||
- name: Run tests
|
- name: Run gollum as test
|
||||||
run: docker run -e CI=true -w /app --entrypoint bundle ${{ env.CI_IMAGE }} exec rake
|
run: docker run -e CI=true ${{ env.CI_IMAGE }} --irb
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ github.ref }}
|
tag_name: ${{ github.ref_name }}
|
||||||
release_name: Release ${{ github.ref }}
|
release_name: Release ${{ github.ref_name }}
|
||||||
draft: false
|
draft: true
|
||||||
prerelease: false
|
prerelease: false
|
||||||
|
body_path: "LATEST_CHANGES.md"
|
||||||
|
|||||||
+50
-11
@@ -1,29 +1,68 @@
|
|||||||
name: Ruby Build
|
name: Ruby Build
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
jruby_build:
|
||||||
|
name: JRuby (${{ matrix.ruby }})
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
ruby: [2.4.0, 2.6.0, 3.0.0, jruby-9.2.18.0]
|
ruby: [jruby-9.3.2.0]
|
||||||
steps:
|
steps:
|
||||||
- run: echo "The job was automatically triggered by a ${{ github.event_name }} event."
|
|
||||||
- run: echo "This job is now running on a ${{ runner.os }} server hosted by GitHub!"
|
|
||||||
- run: echo "The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
|
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- run: echo "The ${{ github.repository }} repository has been cloned to the runner."
|
|
||||||
- run: echo "The workflow is now ready to test your code on the runner."
|
|
||||||
- name: List files in the repository
|
- name: List files in the repository
|
||||||
run: |
|
run: |
|
||||||
ls ${{ github.workspace }}
|
ls ${{ github.workspace }}
|
||||||
- uses: actions/setup-java@v2
|
- name: Set up Java
|
||||||
|
uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'adopt'
|
||||||
java-version: '11'
|
java-version: '11'
|
||||||
- uses: ruby/setup-ruby@v1
|
- name: Set up Ruby
|
||||||
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: ${{ matrix.ruby }}
|
ruby-version: ${{ matrix.ruby }}
|
||||||
bundler-cache: true
|
bundler-cache: true
|
||||||
- name: exec rake
|
- name: Run tests
|
||||||
run: bundle exec rake
|
run: bundle exec rake
|
||||||
|
mri_build:
|
||||||
|
name: Ruby (${{ matrix.ruby }})
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
ruby: ['2.6', '2.7', '3.0', '3.1']
|
||||||
|
steps:
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: List files in the repository
|
||||||
|
run: |
|
||||||
|
ls ${{ github.workspace }}
|
||||||
|
- name: Set up Ruby
|
||||||
|
uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
ruby-version: ${{ matrix.ruby }}
|
||||||
|
bundler-cache: true
|
||||||
|
- name: Run tests
|
||||||
|
run: bundle exec rake
|
||||||
|
selenium:
|
||||||
|
name: Selenium on MRI
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Install Chromedriver
|
||||||
|
uses: nanasess/setup-chromedriver@v1
|
||||||
|
- run: |
|
||||||
|
export DISPLAY=:99
|
||||||
|
chromedriver --url-base=/wd/hub &
|
||||||
|
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional
|
||||||
|
- name: List files in the repository
|
||||||
|
run: |
|
||||||
|
ls ${{ github.workspace }}
|
||||||
|
- name: Set up Ruby
|
||||||
|
uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
ruby-version: '3.1'
|
||||||
|
bundler-cache: true
|
||||||
|
- name: Run tests
|
||||||
|
run: bundle exec rake test:capybara
|
||||||
|
|||||||
+94
-9
@@ -29,14 +29,85 @@ Lastly, please **consider helping out** by opening a Pull Request!
|
|||||||
|
|
||||||
You can triage issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to gollum on CodeTriage](https://www.codetriage.com/gollum/gollum).
|
You can triage issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to gollum on CodeTriage](https://www.codetriage.com/gollum/gollum).
|
||||||
|
|
||||||
|
## Set up your development environment
|
||||||
|
|
||||||
|
If you want to hack on Gollum, you'll need to set up a development
|
||||||
|
environment.
|
||||||
|
|
||||||
|
To get started, you'll need:
|
||||||
|
|
||||||
|
- A recent version of [Git][git]
|
||||||
|
- A recent version of [Ruby][rubylang].
|
||||||
|
- A recent version of [Node JS][nodejs].
|
||||||
|
|
||||||
|
Refer to their installation instructions. Installation methods differ depending
|
||||||
|
on your operating system.
|
||||||
|
|
||||||
|
Once you have those:
|
||||||
|
|
||||||
|
- Install Bundler, the Ruby package manager. In a terminal:
|
||||||
|
```sh
|
||||||
|
gem install bundler
|
||||||
|
```
|
||||||
|
- Install Yarn, a JavaScript package manager. [See Yarn's install
|
||||||
|
guide][yarn-install].
|
||||||
|
|
||||||
|
Now, you can start setting up Gollum to run locally:
|
||||||
|
|
||||||
|
1. Clone the git repository. In a terminal:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/gollum/gollum.git
|
||||||
|
```
|
||||||
|
2. Change directory into the cloned project:
|
||||||
|
```sh
|
||||||
|
cd gollum
|
||||||
|
```
|
||||||
|
3. Bundle the project's Ruby dependencies using Bundler:
|
||||||
|
```sh
|
||||||
|
[sudo] bundle install
|
||||||
|
```
|
||||||
|
4. Install the project's JavaScript dependencies using Yarn:
|
||||||
|
```sh
|
||||||
|
yarn install
|
||||||
|
```
|
||||||
|
If all went well, you should now be able to run the test suite using the
|
||||||
|
following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bundle exec rake
|
||||||
|
```
|
||||||
|
|
||||||
|
If you already have a Gollum wiki, you can also browse it via your local version
|
||||||
|
of Gollum:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bundle exec gollum <path/to/my/wiki/root>
|
||||||
|
```
|
||||||
|
|
||||||
|
Or you can clone an example wiki and browse that:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone test/examples/lotr.git ~/lotr-wiki
|
||||||
|
bundle exec gollum ~/lotr-wiki
|
||||||
|
```
|
||||||
|
|
||||||
|
With this, you're ready to start contributing and open your first [pull
|
||||||
|
request](#opening-a-pull-request).
|
||||||
|
|
||||||
|
[git]: https://git-scm.com/downloads
|
||||||
|
[nodejs]: https://nodejs.org
|
||||||
|
[rubylang]: https://www.ruby-lang.org
|
||||||
|
[yarn-install]: https://yarnpkg.com/getting-started/install
|
||||||
|
|
||||||
## Opening a Pull Request
|
## Opening a Pull Request
|
||||||
|
|
||||||
Pull Requests fixing bugs, implementing new features, or updating documentation and dependencies are all very welcome! If you would like to help out with the project, you can pick an open issue from the issue tracker. We're more than happy to help you get started! Here's how you can proceed:
|
Pull Requests fixing bugs, implementing new features, or updating documentation and dependencies are all very welcome! If you would like to help out with the project, you can pick an open issue from the issue tracker. We're more than happy to help you get started! Here's how you can proceed:
|
||||||
|
|
||||||
1. Fork and clone Gollum.
|
1. Fork and clone Gollum. See [Set up your development
|
||||||
|
environment](#set-up-your-development-environment).
|
||||||
2. Create a thoughtfully named topic branch to contain your changes.
|
2. Create a thoughtfully named topic branch to contain your changes.
|
||||||
3. If you haven't installed dependencies yet, navigate to your clone and execute:
|
3. If you haven't installed dependencies yet, navigate to your clone and execute:
|
||||||
```
|
```
|
||||||
[sudo] bundle install
|
[sudo] bundle install
|
||||||
```
|
```
|
||||||
@@ -47,23 +118,32 @@ Pull Requests fixing bugs, implementing new features, or updating documentation
|
|||||||
8. Push the branch to your fork on GitHub.
|
8. Push the branch to your fork on GitHub.
|
||||||
9. Create a pull request for Gollum.
|
9. Create a pull request for Gollum.
|
||||||
|
|
||||||
**Notes:**
|
Do not change Gollum's version number, we will do that on our own.
|
||||||
* Do not change Gollum's version numbers, we will do that on our own.
|
|
||||||
|
|
||||||
### Running tests
|
### Running tests
|
||||||
|
|
||||||
1. Install [Bundler](http://bundler.io/).
|
1. Install [Bundler](http://bundler.io/).
|
||||||
2. Navigate to the cloned source of Gollum.
|
2. Navigate to the cloned source of Gollum.
|
||||||
3. Install dependencies:
|
3. Install dependencies:
|
||||||
```
|
```
|
||||||
[sudo] bundle install
|
[sudo] bundle install
|
||||||
```
|
```
|
||||||
4. Run the tests:
|
4. Run the tests:
|
||||||
```
|
```
|
||||||
bundle exec rake test
|
bundle exec rake test
|
||||||
```
|
```
|
||||||
|
|
||||||
To profile slow tests, you can use `bundle exec rake test TESTOPTS="--verbose"`.
|
To profile slow tests, you can use the `--verbose` flag:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bundle exec rake test TESTOPTS="--verbose"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also run a single test file with the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bundle exec ruby <test/test_the_file_i_want_to_run.rb>
|
||||||
|
```
|
||||||
|
|
||||||
### Working with test repositories
|
### Working with test repositories
|
||||||
|
|
||||||
@@ -82,7 +162,12 @@ git push ../lotr.git/ master
|
|||||||
|
|
||||||
## Updating static assets
|
## Updating static assets
|
||||||
|
|
||||||
This is necessary whenever changes have been made to the assets in `lib/gollum/public/gollum/javascript` (mostly SASS, CSS, and JS files), to ensure the changes are also present in the [released](#releasing-the-gem) version of the gem. Steps:
|
This is necessary whenever changes have been made to the assets in
|
||||||
|
`lib/gollum/public/gollum/javascript` (mostly SASS, CSS, and JS files), to
|
||||||
|
ensure the changes are also present in the [released](#releasing-the-gem)
|
||||||
|
version of the gem.
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
|
||||||
1. `git rm -r lib/gollum/public/assets`
|
1. `git rm -r lib/gollum/public/assets`
|
||||||
1. `bundle exec rake precompile`
|
1. `bundle exec rake precompile`
|
||||||
|
|||||||
+17
-5
@@ -1,9 +1,11 @@
|
|||||||
FROM ruby:2.7
|
FROM ruby:2.7-alpine AS builder
|
||||||
ENV DEBIAN_FRONTEND="noninteractive"
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apk add \
|
||||||
libicu-dev \
|
build-base \
|
||||||
cmake
|
cmake \
|
||||||
|
git \
|
||||||
|
icu-dev \
|
||||||
|
openssl-dev
|
||||||
|
|
||||||
COPY Gemfile* /tmp/
|
COPY Gemfile* /tmp/
|
||||||
COPY gollum.gemspec* /tmp/
|
COPY gollum.gemspec* /tmp/
|
||||||
@@ -23,6 +25,16 @@ WORKDIR /app
|
|||||||
COPY . /app
|
COPY . /app
|
||||||
RUN bundle exec rake install
|
RUN bundle exec rake install
|
||||||
|
|
||||||
|
|
||||||
|
FROM ruby:2.7-alpine
|
||||||
|
|
||||||
|
COPY --from=builder /usr/local/bundle/ /usr/local/bundle/
|
||||||
|
|
||||||
|
RUN apk add \
|
||||||
|
bash \
|
||||||
|
git \
|
||||||
|
libc6-compat
|
||||||
|
|
||||||
VOLUME /wiki
|
VOLUME /wiki
|
||||||
WORKDIR /wiki
|
WORKDIR /wiki
|
||||||
COPY docker-run.sh /docker-run.sh
|
COPY docker-run.sh /docker-run.sh
|
||||||
|
|||||||
@@ -1,9 +1,28 @@
|
|||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
if RUBY_PLATFORM == 'java'
|
gem 'warbler', platforms: :jruby
|
||||||
gem 'warbler'
|
|
||||||
|
# FIXME:
|
||||||
|
#
|
||||||
|
# There's an issue in 1.12.5 that causes XHTML elements to be generated badly,
|
||||||
|
# causing Gollum's test suite to fail.[1] The issue has been fixed upstream,
|
||||||
|
# but we're still waiting for a new Nokogiri point release.
|
||||||
|
#
|
||||||
|
# However, 1.12.5 is a security patch, so we don't want end users to use an
|
||||||
|
# older version of Nokogiri. But this is safe to do in our CI environment.
|
||||||
|
#
|
||||||
|
# Once there's a new Nokogiri release, we can remove this dependency and JRuby
|
||||||
|
# CI should pass normally again.
|
||||||
|
#
|
||||||
|
# Note that Nokogiri 1.11+ does not support Ruby v2.4.x anymore. So to make our
|
||||||
|
# current CI workflows pass, we should only try to install this version of
|
||||||
|
# Nokogiri for newer Ruby versions.
|
||||||
|
|
||||||
|
group :test do
|
||||||
|
gem 'selenium-webdriver', require: false
|
||||||
|
gem 'capybara', require: false
|
||||||
end
|
end
|
||||||
|
|
||||||
gemspec
|
gemspec
|
||||||
|
|
||||||
gem 'rake', '~> 13.0'
|
gem 'rake', '~> 13.0'
|
||||||
|
|||||||
+16
-3
@@ -1,12 +1,25 @@
|
|||||||
# 5.2.3 2021-04-18
|
# 5.3.0 / 2022-05-25
|
||||||
|
|
||||||
|
* Feature: allow for overriding only specific Mustache templates/partials (@beporter)
|
||||||
|
* Feature: Add option to show browser's local time (@NikitaIvanovV)
|
||||||
|
* Improvement: presentation on mobile devises (@benjaminwil)
|
||||||
|
* Improvement: Add page context to template filter. #1603 (@tevino)
|
||||||
|
* Fix: restore normalize check on file upload (@manofstick)
|
||||||
|
* Fix mathjax on edit and create pages. #1772 (@fhchl)
|
||||||
|
* Fix utf-8 issues: #1721 #1758 #1801 (@basking2, @dometto)
|
||||||
|
* Fix an IME rendering issue. #1735 (@yy0931)
|
||||||
|
* Fix broken history button when viewing historical deleted file. (@NikitaIvanovV)
|
||||||
|
* Fix: non-ascii characters in page names are not rendered correctly in the preview tab of the "Edit" page. #1739 (@yy0931)
|
||||||
|
* Fix: anchors and header display on JRuby. #1779
|
||||||
|
# 5.2.3 / 2021-04-18
|
||||||
|
|
||||||
* Fix bug preventing page titles from being displayed
|
* Fix bug preventing page titles from being displayed
|
||||||
|
|
||||||
# 5.2.1 2021-02-25
|
# 5.2.1 / 2021-02-25
|
||||||
|
|
||||||
* Fix include call to a missing asset (@benjaminwil). This caused slow first page loads on JRuby.
|
* Fix include call to a missing asset (@benjaminwil). This caused slow first page loads on JRuby.
|
||||||
|
|
||||||
# 5.2 2021-02-24
|
# 5.2 / 2021-02-24
|
||||||
|
|
||||||
* Improved styling and Primer upgrade (@benjaminwil)
|
* Improved styling and Primer upgrade (@benjaminwil)
|
||||||
* Add redirect to rename commit (@ViChyavIn)
|
* Add redirect to rename commit (@ViChyavIn)
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# 5.3.0 / 2022-05-24
|
||||||
|
|
||||||
|
* Feature: allow for overriding only specific Mustache templates/partials (@beporter)
|
||||||
|
* Feature: Add option to show browser's local time (@NikitaIvanovV)
|
||||||
|
* Improvement: presentation on mobile devises (@benjaminwil)
|
||||||
|
* Improvement: Add page context to template filter. #1603 (@tevino)
|
||||||
|
* Fix: restore normalize check on file upload (@manofstick)
|
||||||
|
* Fix mathjax on edit and create pages. #1772 (@fhchl)
|
||||||
|
* Fix utf-8 issues: #1721 #1758 #1801 (@basking2, @dometto)
|
||||||
|
* Fix an IME rendering issue. #1735 (@yy0931)
|
||||||
|
* Fix broken history button when viewing historical deleted file. (@NikitaIvanovV)
|
||||||
|
* Fix: non-ascii characters in page names are not rendered correctly in the preview tab of the "Edit" page. #1739 (@yy0931)
|
||||||
|
* Fix: anchors and header display on JRuby. #1779
|
||||||
@@ -5,21 +5,24 @@ gollum -- A git-based Wiki
|
|||||||

|

|
||||||
[](https://www.codetriage.com/gollum/gollum)
|
[](https://www.codetriage.com/gollum/gollum)
|
||||||
[](https://dometto-cuttingedge.herokuapp.com/github/gollum/gollum/info)
|
[](https://dometto-cuttingedge.herokuapp.com/github/gollum/gollum/info)
|
||||||
|
[](https://hub.docker.com/r/gollumwiki/gollum)
|
||||||
|
|
||||||
|
See the [wiki](https://github.com/gollum/gollum/wiki) for extensive documentation, along with [screenshots](https://github.com/gollum/gollum/wiki/Screenshots) of Gollum's features.
|
||||||
**Gollum version 5.0 is out!** See [here](https://github.com/gollum/gollum/wiki/5.0-release-notes) for a list of changes and new features compared to Gollum version 4.x, and see some [Screenshots](https://github.com/gollum/gollum/wiki/Screenshots) of Gollum's features.
|
|
||||||
|
|
||||||
## DESCRIPTION
|
## DESCRIPTION
|
||||||
|
|
||||||
Gollum is a simple wiki system built on top of Git. A Gollum Wiki is simply a git repository of a specific nature:
|
Gollum is a simple wiki system built on top of Git. A Gollum Wiki is simply a git repository of a specific nature:
|
||||||
|
|
||||||
* A Gollum repository's contents are human-editable text or markup files.
|
* A Gollum repository's contents are human-editable text or markup files.
|
||||||
* Pages may be organized into directories any way you choose.
|
* Pages may be organized into directories any way you choose.
|
||||||
* Other content can also be included, for example images, PDFs and headers/footers for your pages.
|
* Other content can also be included, for example images, PDFs and headers/footers for your pages.
|
||||||
* Gollum pages:
|
* Gollum pages:
|
||||||
* May be written in a variety of [markups](#markups).
|
* May be written in a variety of [markups](#markups).
|
||||||
* Can be edited with your favourite system editor or IDE (changes will be visible after committing) or with the built-in web interface.
|
* Can be edited with your favourite editor (changes will be visible after committing) or with the built-in web interface.
|
||||||
* Can be displayed in all versions, reverted, etc.
|
* Can be displayed in all versions, reverted, etc.
|
||||||
* Gollum strives to be compatible with GitHub wikis (see `--lenient-tag-lookup`)
|
* Gollum strives to be [compatible](https://github.com/gollum/gollum/wiki/5.0-release-notes#compatibility-option) with [GitHub](https://docs.github.com/en/communities/documenting-your-project-with-wikis/about-wikis) and [GitLab](https://docs.gitlab.com/ee/user/project/wiki/#create-or-edit-wiki-pages-locally) wikis.
|
||||||
|
* Just clone your GitHub/GitLab wiki and view and edit it locally!
|
||||||
|
|
||||||
* Gollum supports advanced functionality like:
|
* Gollum supports advanced functionality like:
|
||||||
* [UML diagrams](https://github.com/gollum/gollum/wiki#plantuml-diagrams)
|
* [UML diagrams](https://github.com/gollum/gollum/wiki#plantuml-diagrams)
|
||||||
* [BibTeX and Citation support](https://github.com/gollum/gollum/wiki/BibTeX-and-Citations)
|
* [BibTeX and Citation support](https://github.com/gollum/gollum/wiki/BibTeX-and-Citations)
|
||||||
@@ -32,16 +35,17 @@ Gollum is a simple wiki system built on top of Git. A Gollum Wiki is simply a gi
|
|||||||
|
|
||||||
### SYSTEM REQUIREMENTS
|
### SYSTEM REQUIREMENTS
|
||||||
|
|
||||||
Gollum runs on Unix-like systems using its [adapter](https://github.com/gollum/rugged_adapter) for [rugged](https://github.com/libgit2/rugged) by default. You can also run Gollum on [JRuby](https://github.com/jruby/jruby) via its [adapter](https://github.com/repotag/gollum-lib_rjgit_adapter) for [RJGit](https://github.com/repotag/rjgit/). On Windows, Gollum runs only on JRuby.
|
Gollum runs on Unix-like systems using its default [adapter](https://github.com/gollum/rugged_adapter) for [rugged](https://github.com/libgit2/rugged). You can also run Gollum on [JRuby](https://github.com/jruby/jruby) via its [adapter](https://github.com/repotag/gollum-lib_rjgit_adapter) for [RJGit](https://github.com/repotag/rjgit/). On Windows, Gollum runs only on JRuby.
|
||||||
|
|
||||||
## INSTALLATION
|
## INSTALLATION
|
||||||
|
|
||||||
1. Ruby is best installed either via [RVM](https://rvm.io/) or a package manager of choice.
|
### As a Ruby Gem
|
||||||
2. Gollum is best installed via RubyGems:
|
|
||||||
```
|
|
||||||
[sudo] gem install gollum
|
|
||||||
```
|
|
||||||
|
|
||||||
|
Ruby is best installed either via [RVM](https://rvm.io/) or a package manager of choice. Then simply:
|
||||||
|
```
|
||||||
|
gem install gollum
|
||||||
|
```
|
||||||
|
|
||||||
Installation examples for individual systems can be seen [here](https://github.com/gollum/gollum/wiki/Installation).
|
Installation examples for individual systems can be seen [here](https://github.com/gollum/gollum/wiki/Installation).
|
||||||
|
|
||||||
To run, simply:
|
To run, simply:
|
||||||
@@ -49,24 +53,30 @@ To run, simply:
|
|||||||
1. Run: `gollum /path/to/wiki` where `/path/to/wiki` is an initialized Git repository.
|
1. Run: `gollum /path/to/wiki` where `/path/to/wiki` is an initialized Git repository.
|
||||||
2. Open `http://localhost:4567` in your browser.
|
2. Open `http://localhost:4567` in your browser.
|
||||||
|
|
||||||
|
### Via Docker
|
||||||
|
|
||||||
|
See [here](https://github.com/gollum/gollum/wiki/Gollum-via-Docker) for instructions on how to run Gollum via Docker.
|
||||||
|
|
||||||
|
### Misc
|
||||||
|
|
||||||
See [below](#running-from-source) for information on running Gollum from source, as a Rack app, and more.
|
See [below](#running-from-source) for information on running Gollum from source, as a Rack app, and more.
|
||||||
|
|
||||||
### Markups
|
## MARKUPS
|
||||||
|
|
||||||
Gollum allows using different markup languages on different wiki pages. It presently ships with support for the following markups:
|
Gollum allows using different markup languages on different wiki pages. It presently ships with support for the following markups:
|
||||||
* [Markdown](http://daringfireball.net/projects/markdown/syntax) (see [below](#Markdown-flavors) for more information on Markdown flavors)
|
* [Markdown](http://daringfireball.net/projects/markdown/syntax) (see [below](#Markdown-flavors) for more information on Markdown flavors)
|
||||||
* [RDoc](http://rdoc.sourceforge.net/)
|
* [RDoc](http://rdoc.sourceforge.net/)
|
||||||
|
|
||||||
You can easily activate support for other markups by installing additional renderers (any that are supported by [github-markup](https://github.com/github/markup)):
|
You can easily activate support for other markups by installing additional renderers (any that are supported by [github-markup](https://github.com/github/markup)):
|
||||||
* [AsciiDoc](http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/) -- `[sudo] gem install asciidoctor`
|
* [AsciiDoc](http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/) -- `gem install asciidoctor`
|
||||||
* [Creole](http://www.wikicreole.org/wiki/CheatSheet) -- `[sudo] gem install creole`
|
* [Creole](http://www.wikicreole.org/wiki/CheatSheet) -- `gem install creole`
|
||||||
* [MediaWiki](http://www.mediawiki.org/wiki/Help:Formatting) -- `[sudo] gem install wikicloth`
|
* [MediaWiki](http://www.mediawiki.org/wiki/Help:Formatting) -- `gem install wikicloth`
|
||||||
* [Org](http://orgmode.org/worg/dev/org-syntax.html) -- `[sudo] gem install org-ruby`
|
* [Org](http://orgmode.org/worg/dev/org-syntax.html) -- `gem install org-ruby`
|
||||||
* [Pod](http://perldoc.perl.org/perlpod.html) -- requires Perl >= 5.10 (the `perl` command must be available on your command line)
|
* [Pod](http://perldoc.perl.org/perlpod.html) -- requires Perl >= 5.10 (the `perl` command must be available on your command line)
|
||||||
* Lower versions should install `Pod::Simple` from CPAN.
|
* Lower versions should install `Pod::Simple` from CPAN.
|
||||||
* [ReStructuredText](http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html) -- requires python >= 2 (the `python2` command must be available on your command line)
|
* [ReStructuredText](http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html) -- requires python >= 3
|
||||||
* Note that Gollum will also need you to install `docutils` for your Python 2.
|
* Note that Gollum will also need you to install `docutils` for python
|
||||||
* [Textile](http://redcloth.org/hobix.com/textile/quick.html) -- `[sudo] gem install RedCloth`
|
* [Textile](http://redcloth.org/hobix.com/textile/quick.html) -- `gem install RedCloth`
|
||||||
|
|
||||||
### Markdown flavors
|
### Markdown flavors
|
||||||
|
|
||||||
@@ -90,10 +100,6 @@ Gollum can also be run with any [rack-compatible web server](https://github.com/
|
|||||||
|
|
||||||
Gollum can also be run alongside a CAS (Central Authentication Service) SSO (single sign-on) server. With a bit of tweaking, this adds basic user-support to Gollum. To see an example and an explanation, navigate [over here](https://github.com/gollum/gollum/wiki/Gollum-via-Rack-and-CAS-SSO).
|
Gollum can also be run alongside a CAS (Central Authentication Service) SSO (single sign-on) server. With a bit of tweaking, this adds basic user-support to Gollum. To see an example and an explanation, navigate [over here](https://github.com/gollum/gollum/wiki/Gollum-via-Rack-and-CAS-SSO).
|
||||||
|
|
||||||
### Docker
|
|
||||||
|
|
||||||
Gollum can also be run via [Docker](https://www.docker.com/). More on that [over here](https://github.com/gollum/gollum/wiki/Gollum-via-Docker).
|
|
||||||
|
|
||||||
### Service
|
### Service
|
||||||
|
|
||||||
Gollum can also be run as a service. More on that [over here](https://github.com/gollum/gollum/wiki/Gollum-as-a-service).
|
Gollum can also be run as a service. More on that [over here](https://github.com/gollum/gollum/wiki/Gollum-as-a-service).
|
||||||
@@ -106,7 +112,7 @@ Gollum comes with the following command line options:
|
|||||||
| ----------------- | --------- | ----------- |
|
| ----------------- | --------- | ----------- |
|
||||||
| --host | [HOST] | Specify the hostname or IP address to listen on. Default: '0.0.0.0'.<sup>1</sup> |
|
| --host | [HOST] | Specify the hostname or IP address to listen on. Default: '0.0.0.0'.<sup>1</sup> |
|
||||||
| --port | [PORT] | Specify the port to bind Gollum with. Default: `4567`. |
|
| --port | [PORT] | Specify the port to bind Gollum with. Default: `4567`. |
|
||||||
| --config | [FILE] | Specify path to Gollum's configuration file. |
|
| --config | [FILE] | Specify path to Gollum's [configuration file](#Config-file). |
|
||||||
| --ref | [REF] | Specify the git branch to serve. Default: `master`. |
|
| --ref | [REF] | Specify the git branch to serve. Default: `master`. |
|
||||||
| --bare | none | Tell Gollum that the git repository should be treated as bare. |
|
| --bare | none | Tell Gollum that the git repository should be treated as bare. |
|
||||||
| --adapter | [ADAPTER] | Launch Gollum using a specific git adapter. Default: `rugged`.<sup>2</sup> |
|
| --adapter | [ADAPTER] | Launch Gollum using a specific git adapter. Default: `rugged`.<sup>2</sup> |
|
||||||
@@ -117,6 +123,7 @@ Gollum comes with the following command line options:
|
|||||||
| --css | none | Tell Gollum to inject custom CSS into each page. Uses `custom.css` from wiki root.<sup>3</sup> |
|
| --css | none | Tell Gollum to inject custom CSS into each page. Uses `custom.css` from wiki root.<sup>3</sup> |
|
||||||
| --js | none | Tell Gollum to inject custom JS into each page. Uses `custom.js` from wiki root.<sup>3</sup> |
|
| --js | none | Tell Gollum to inject custom JS into each page. Uses `custom.js` from wiki root.<sup>3</sup> |
|
||||||
| --no-edit | none | Disable the feature of editing pages. |
|
| --no-edit | none | Disable the feature of editing pages. |
|
||||||
|
| --local-time | none | Use the browser's local timezone instead of the server's for displaying dates. Default: false.
|
||||||
| --follow-renames, --no-follow-renames | none | Follow pages across renames in the History view. Default: true.
|
| --follow-renames, --no-follow-renames | none | Follow pages across renames in the History view. Default: true.
|
||||||
| --allow-uploads | [MODE] | Enable file uploads. If set to `dir`, Gollum will store all uploads in the `/uploads/` directory in repository root. If set to `page`, Gollum will store each upload at the currently edited page.<sup>4</sup> |
|
| --allow-uploads | [MODE] | Enable file uploads. If set to `dir`, Gollum will store all uploads in the `/uploads/` directory in repository root. If set to `page`, Gollum will store each upload at the currently edited page.<sup>4</sup> |
|
||||||
| --mathjax | none | Enables MathJax (renders mathematical equations). By default, uses the `TeX-AMS-MML_HTMLorMML` config with the `autoload-all` extension.<sup>5</sup> |
|
| --mathjax | none | Enables MathJax (renders mathematical equations). By default, uses the `TeX-AMS-MML_HTMLorMML` config with the `autoload-all` extension.<sup>5</sup> |
|
||||||
@@ -129,6 +136,7 @@ Gollum comes with the following command line options:
|
|||||||
| --template-dir | [PATH] | Specify custom mustache template directory. Only overrides templates that exist in this directory. |
|
| --template-dir | [PATH] | Specify custom mustache template directory. Only overrides templates that exist in this directory. |
|
||||||
| --template-page | none | Use _Template in root as a template for new pages. Must be committed. |
|
| --template-page | none | Use _Template in root as a template for new pages. Must be committed. |
|
||||||
| --emoji | none | Parse and interpret emoji tags (e.g. `:heart:`) except when the leading colon is backslashed (e.g. `\:heart:`). |
|
| --emoji | none | Parse and interpret emoji tags (e.g. `:heart:`) except when the leading colon is backslashed (e.g. `\:heart:`). |
|
||||||
|
| --default-keybind | none | Set the default keybinding for the editor. Can be set to `vim`, or `emacs`. |
|
||||||
| --lenient-tag-lookup | none | Internal links resolve case-insensitively, will treat spaces as hyphens, and will match the first page found with a certain filename, anywhere in the repository. Provides compatibility with Gollum 4.x. |
|
| --lenient-tag-lookup | none | Internal links resolve case-insensitively, will treat spaces as hyphens, and will match the first page found with a certain filename, anywhere in the repository. Provides compatibility with Gollum 4.x. |
|
||||||
| --help | none | Display the list of options on the command line. |
|
| --help | none | Display the list of options on the command line. |
|
||||||
| --version | none | Display the current version of Gollum. |
|
| --version | none | Display the current version of Gollum. |
|
||||||
@@ -150,7 +158,3 @@ When `--config` option is used, certain inner parts of Gollum can be customized.
|
|||||||
## CONTRIBUTING
|
## CONTRIBUTING
|
||||||
|
|
||||||
Please consider helping out! See [CONTRIBUTING](CONTRIBUTING.md) for information on how to submit issues, and how to start hacking on gollum.
|
Please consider helping out! See [CONTRIBUTING](CONTRIBUTING.md) for information on how to submit issues, and how to start hacking on gollum.
|
||||||
|
|
||||||
## THANKS TO
|
|
||||||
|
|
||||||
[](https://saucelabs.com)
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
require 'rubygems'
|
require 'rubygems'
|
||||||
require 'rake'
|
require 'rake'
|
||||||
require 'date'
|
require 'date'
|
||||||
|
require 'tempfile'
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
#
|
#
|
||||||
@@ -8,6 +9,10 @@ require 'date'
|
|||||||
#
|
#
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
|
def date
|
||||||
|
Time.now.strftime("%Y-%m-%d")
|
||||||
|
end
|
||||||
|
|
||||||
def name
|
def name
|
||||||
@name ||= Dir['*.gemspec'].first.split('.').first
|
@name ||= Dir['*.gemspec'].first.split('.').first
|
||||||
end
|
end
|
||||||
@@ -17,6 +22,14 @@ def version
|
|||||||
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def latest_changes_file
|
||||||
|
'LATEST_CHANGES.md'
|
||||||
|
end
|
||||||
|
|
||||||
|
def history_file
|
||||||
|
'HISTORY.md'
|
||||||
|
end
|
||||||
|
|
||||||
# assumes x.y.z all digit version
|
# assumes x.y.z all digit version
|
||||||
def next_version
|
def next_version
|
||||||
# x.y.z
|
# x.y.z
|
||||||
@@ -38,14 +51,6 @@ def bump_version
|
|||||||
new_version
|
new_version
|
||||||
end
|
end
|
||||||
|
|
||||||
def date
|
|
||||||
Date.today.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
def rubyforge_project
|
|
||||||
name
|
|
||||||
end
|
|
||||||
|
|
||||||
def gemspec_file
|
def gemspec_file
|
||||||
"#{name}.gemspec"
|
"#{name}.gemspec"
|
||||||
end
|
end
|
||||||
@@ -67,9 +72,21 @@ end
|
|||||||
task :default => :test
|
task :default => :test
|
||||||
|
|
||||||
require 'rake/testtask'
|
require 'rake/testtask'
|
||||||
|
|
||||||
|
namespace :test do
|
||||||
|
Rake::TestTask.new('capybara') do |test|
|
||||||
|
test.libs << 'lib' << 'test' << '.'
|
||||||
|
test.pattern = 'test/integration/**/test_*.rb'
|
||||||
|
test.verbose = true
|
||||||
|
test.warning = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
Rake::TestTask.new(:test) do |test|
|
Rake::TestTask.new(:test) do |test|
|
||||||
test.libs << 'lib' << 'test' << '.'
|
test.libs << 'lib' << 'test' << '.'
|
||||||
test.pattern = 'test/**/test_*.rb'
|
test.test_files = FileList.new('test/**/test_*.rb') do |fl|
|
||||||
|
fl.exclude('test/integration/**/test_*.rb')
|
||||||
|
end
|
||||||
test.verbose = true
|
test.verbose = true
|
||||||
test.warning = false
|
test.warning = false
|
||||||
end
|
end
|
||||||
@@ -114,6 +131,7 @@ task :release => :build do
|
|||||||
puts "You must be on the master branch to release!"
|
puts "You must be on the master branch to release!"
|
||||||
exit!
|
exit!
|
||||||
end
|
end
|
||||||
|
Rake::Task[:changelog].execute
|
||||||
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
||||||
sh "git pull --rebase origin master"
|
sh "git pull --rebase origin master"
|
||||||
sh "git tag v#{version}"
|
sh "git tag v#{version}"
|
||||||
@@ -143,12 +161,9 @@ task :gemspec => :validate do
|
|||||||
spec = File.read(gemspec_file)
|
spec = File.read(gemspec_file)
|
||||||
head, manifest, tail = spec.split(" # = MANIFEST =\n")
|
head, manifest, tail = spec.split(" # = MANIFEST =\n")
|
||||||
|
|
||||||
# replace name version and date
|
# replace name and version
|
||||||
replace_header(head, :name)
|
replace_header(head, :name)
|
||||||
replace_header(head, :version)
|
replace_header(head, :version)
|
||||||
replace_header(head, :date)
|
|
||||||
#comment this out if your rubyforge_project has a different name
|
|
||||||
replace_header(head, :rubyforge_project)
|
|
||||||
|
|
||||||
# determine file list from git ls-files
|
# determine file list from git ls-files
|
||||||
files = `git ls-files`.
|
files = `git ls-files`.
|
||||||
@@ -179,13 +194,71 @@ task :validate do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc 'Build changlog'
|
||||||
|
task :changelog do
|
||||||
|
[latest_changes_file, history_file].each do |f|
|
||||||
|
unless File.exists?(f)
|
||||||
|
puts "#{f} does not exist but is required to build a new release."
|
||||||
|
exit!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
latest_changes = File.open(latest_changes_file)
|
||||||
|
version_pattern = "# #{version}"
|
||||||
|
|
||||||
|
if !`grep "#{version_pattern}" #{history_file}`.empty?
|
||||||
|
puts "#{version} is already described in #{history_file}"
|
||||||
|
exit!
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
unless latest_changes.readline.chomp! =~ %r{#{version_pattern}}
|
||||||
|
puts "#{latest_changes_file} should begin with '#{version_pattern}'"
|
||||||
|
exit!
|
||||||
|
end
|
||||||
|
rescue EOFError
|
||||||
|
puts "#{latest_changes_file} is empty!"
|
||||||
|
exit!
|
||||||
|
end
|
||||||
|
|
||||||
|
body = latest_changes.read
|
||||||
|
body.scan(/\s*#\s+\d\.\d.*/) do |match|
|
||||||
|
puts "#{latest_changes_file} may not contain multiple markdown headers!"
|
||||||
|
exit!
|
||||||
|
end
|
||||||
|
|
||||||
|
temp = Tempfile.new
|
||||||
|
temp.puts("#{version_pattern} / #{date}\n#{body}\n")
|
||||||
|
temp.close
|
||||||
|
`cat #{history_file} >> #{temp.path}`
|
||||||
|
`cat #{temp.path} > #{history_file}`
|
||||||
|
end
|
||||||
|
|
||||||
desc 'Precompile assets'
|
desc 'Precompile assets'
|
||||||
task :precompile do
|
task :precompile do
|
||||||
|
# Attempt to install JavaScript dependencies managed by Yarn via the
|
||||||
|
# `package.json` file in Gollum's project root. If it fails, raise an error
|
||||||
|
# and exit the task early.
|
||||||
|
puts "\n Installing `yarn`-managed JavaScript dependencies... \n\n"
|
||||||
|
system "yarn install"
|
||||||
|
unless $?.success?
|
||||||
|
raise "This task tried to run `yarn install` to get up-to-date " \
|
||||||
|
"JavaScript dependencies before precompilation. But it failed. Please " \
|
||||||
|
"run `yarn install` manually from your shell and resolve any issues. " \
|
||||||
|
"It's possible that you just need to install `yarn` on your system."
|
||||||
|
end
|
||||||
|
|
||||||
require './lib/gollum/app.rb'
|
require './lib/gollum/app.rb'
|
||||||
|
|
||||||
|
# Next, configure the Sprockets asset pipeline and precompile production-
|
||||||
|
# ready assets.
|
||||||
Precious::App.set(:environment, :production)
|
Precious::App.set(:environment, :production)
|
||||||
|
|
||||||
env = Precious::Assets.sprockets
|
env = Precious::Assets.sprockets
|
||||||
path = ENV.fetch('GOLLUM_ASSETS_PATH', ::File.join(File.dirname(__FILE__), 'lib/gollum/public/assets'))
|
path = ENV.fetch 'GOLLUM_ASSETS_PATH',
|
||||||
|
File.join(File.dirname(__FILE__), 'lib/gollum/public/assets')
|
||||||
manifest = Sprockets::Manifest.new(env, path)
|
manifest = Sprockets::Manifest.new(env, path)
|
||||||
|
|
||||||
Sprockets::Helpers.configure do |config|
|
Sprockets::Helpers.configure do |config|
|
||||||
config.environment = env
|
config.environment = env
|
||||||
config.prefix = Precious::Assets::ASSET_URL
|
config.prefix = Precious::Assets::ASSET_URL
|
||||||
@@ -193,6 +266,7 @@ task :precompile do
|
|||||||
config.public_path = path
|
config.public_path = path
|
||||||
config.manifest = manifest
|
config.manifest = manifest
|
||||||
end
|
end
|
||||||
puts "Precompiling assets to #{path}..."
|
|
||||||
|
puts "\n Precompiling assets to #{path}... \n\n"
|
||||||
manifest.compile(Precious::Assets::MANIFEST)
|
manifest.compile(Precious::Assets::MANIFEST)
|
||||||
end
|
end
|
||||||
|
|||||||
+10
-3
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env -S ruby -Eutf-8
|
||||||
|
|
||||||
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ options = {
|
|||||||
}
|
}
|
||||||
wiki_options = {
|
wiki_options = {
|
||||||
:allow_uploads => false,
|
:allow_uploads => false,
|
||||||
:allow_editing => true,
|
:allow_editing => true
|
||||||
}
|
}
|
||||||
|
|
||||||
opts = OptionParser.new do |opts|
|
opts = OptionParser.new do |opts|
|
||||||
@@ -112,6 +112,9 @@ MSG
|
|||||||
opts.on('--no-edit', 'Disable the feature of editing pages.') do
|
opts.on('--no-edit', 'Disable the feature of editing pages.') do
|
||||||
wiki_options[:allow_editing] = false
|
wiki_options[:allow_editing] = false
|
||||||
end
|
end
|
||||||
|
opts.on('--local-time', "Use the browser's local timezone instead of the server's for displaying dates.") do
|
||||||
|
wiki_options[:show_local_time] = true
|
||||||
|
end
|
||||||
opts.on('--follow-renames', 'Follow pages across renames in the History view. Default: true.') do
|
opts.on('--follow-renames', 'Follow pages across renames in the History view. Default: true.') do
|
||||||
wiki_options[:follow_renames] = true
|
wiki_options[:follow_renames] = true
|
||||||
end
|
end
|
||||||
@@ -163,6 +166,10 @@ MSG
|
|||||||
opts.on('--emoji', 'Parse and interpret emoji tags (e.g. :heart:) except when the leading colon is backslashed (e.g. \\:heart:).') do
|
opts.on('--emoji', 'Parse and interpret emoji tags (e.g. :heart:) except when the leading colon is backslashed (e.g. \\:heart:).') do
|
||||||
wiki_options[:emoji] = true
|
wiki_options[:emoji] = true
|
||||||
end
|
end
|
||||||
|
opts.on('--default-keybinding [KEYBINDING]', Gollum::KEYBINDINGS.drop(1), 'Set the default keybinding for the editor. Can be set to \'vim\', or \'emacs\'.') do |keybinding|
|
||||||
|
wiki_options[:default_keybinding] = keybinding.to_s
|
||||||
|
puts wiki_options[:default_keybinding]
|
||||||
|
end
|
||||||
opts.separator ''
|
opts.separator ''
|
||||||
opts.separator ' Common:'
|
opts.separator ' Common:'
|
||||||
|
|
||||||
@@ -206,7 +213,7 @@ begin
|
|||||||
rescue OptionParser::InvalidOption => e
|
rescue OptionParser::InvalidOption => e
|
||||||
puts "gollum: #{e.message}"
|
puts "gollum: #{e.message}"
|
||||||
puts 'gollum: try \'gollum --help\' for more information'
|
puts 'gollum: try \'gollum --help\' for more information'
|
||||||
exit
|
exit 1
|
||||||
end
|
end
|
||||||
|
|
||||||
# --gollum-path wins over ARGV[0]
|
# --gollum-path wins over ARGV[0]
|
||||||
|
|||||||
+40
-28
@@ -11,8 +11,11 @@ migrate_options = {
|
|||||||
:hyphenate => true
|
:hyphenate => true
|
||||||
}
|
}
|
||||||
|
|
||||||
def setting(const)
|
def setting(variable_name)
|
||||||
Object.const_defined?(const.upcase) && Object.const_get(const.upcase)
|
class_variable_name = :"@@#{variable_name.to_s}"
|
||||||
|
|
||||||
|
Object.class_variable_defined?(class_variable_name) &&
|
||||||
|
Object.class_variable_get(class_variable_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
opts = OptionParser.new do |opts|
|
opts = OptionParser.new do |opts|
|
||||||
@@ -25,7 +28,7 @@ It finds and repairs Gollum link tags that no longer work under 5.x for three re
|
|||||||
* 5.x wiki internal links are no longer 'global'.
|
* 5.x wiki internal links are no longer 'global'.
|
||||||
|
|
||||||
* NB: you can use the --lenient-tag-lookup option in gollum >= 5.x to enable 4.x-backwards compatible tags.
|
* NB: you can use the --lenient-tag-lookup option in gollum >= 5.x to enable 4.x-backwards compatible tags.
|
||||||
|
|
||||||
See https://github.com/gollum/gollum/wiki/5.0-release-notes#filename-handling for more information.
|
See https://github.com/gollum/gollum/wiki/5.0-release-notes#filename-handling for more information.
|
||||||
Usage of this script comes without any warranty.
|
Usage of this script comes without any warranty.
|
||||||
|
|
||||||
@@ -38,7 +41,7 @@ You can use the --page-file-dir and --config options as you would normally with
|
|||||||
Requires a non-bare repository. Recommended usage:
|
Requires a non-bare repository. Recommended usage:
|
||||||
|
|
||||||
1. Clone your wiki's repository to create a backup.
|
1. Clone your wiki's repository to create a backup.
|
||||||
2. Run this script on your cloned repo.
|
2. Run this script on your cloned repo.
|
||||||
3. If all looks sane, run the script with the --write option. This will overwrite files in your working directory, but not commit the changes, so you have time to review them.
|
3. If all looks sane, run the script with the --write option. This will overwrite files in your working directory, but not commit the changes, so you have time to review them.
|
||||||
4. Do a 'git diff' to inspect the changes.
|
4. Do a 'git diff' to inspect the changes.
|
||||||
5. Commit the changes if all looks sane, and push/pull them back into your original repo.
|
5. Commit the changes if all looks sane, and push/pull them back into your original repo.
|
||||||
@@ -52,23 +55,23 @@ EOF
|
|||||||
opts.on('--page-file-dir [PATH]', 'Specify the subdirectory for all pages. Default: repository root.') do |path|
|
opts.on('--page-file-dir [PATH]', 'Specify the subdirectory for all pages. Default: repository root.') do |path|
|
||||||
wiki_options[:page_file_dir] = path
|
wiki_options[:page_file_dir] = path
|
||||||
end
|
end
|
||||||
|
|
||||||
opts.on('--prefer-relative-links', 'When specified, will try to replace broken links with relative links (\'[[Foo/Bar]]\' instead of \'[[/Subdir/Foo/Bar]]\') where possible.') do
|
opts.on('--prefer-relative-links', 'When specified, will try to replace broken links with relative links (\'[[Foo/Bar]]\' instead of \'[[/Subdir/Foo/Bar]]\') where possible.') do
|
||||||
migrate_options[:prefer_relative] = true
|
migrate_options[:prefer_relative] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
opts.on('--hyphenate', 'Default. Repair links that use spaces instead of hyphens: [[Bilbo Baggins]] -> [[Bilbo-Baggins]]') do
|
opts.on('--hyphenate', 'Default. Repair links that use spaces instead of hyphens: [[Bilbo Baggins]] -> [[Bilbo-Baggins]]') do
|
||||||
migrate_options[:hyphenate] = true
|
migrate_options[:hyphenate] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
opts.on('--no-hyphenate', 'Turn off the --hyphenate option.') do
|
opts.on('--no-hyphenate', 'Turn off the --hyphenate option.') do
|
||||||
migrate_options[:hyphenate] = false
|
migrate_options[:hyphenate] = false
|
||||||
end
|
end
|
||||||
|
|
||||||
opts.on('--run-silent', 'Don\'t output anything.') do
|
opts.on('--run-silent', 'Don\'t output anything.') do
|
||||||
migrate_options[:run_silent] = true
|
migrate_options[:run_silent] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
opts.on('--write', 'No dry run: actually perform the substitutions.') do
|
opts.on('--write', 'No dry run: actually perform the substitutions.') do
|
||||||
migrate_options[:no_dry_run] = true
|
migrate_options[:no_dry_run] = true
|
||||||
end
|
end
|
||||||
@@ -78,8 +81,11 @@ end
|
|||||||
begin
|
begin
|
||||||
opts.parse!
|
opts.parse!
|
||||||
migrate_options.each do |setting, value|
|
migrate_options.each do |setting, value|
|
||||||
const = setting.to_s.upcase
|
variable_name = :"@@#{setting.to_s}"
|
||||||
Object.const_set(const, value) unless Object.const_defined?(const)
|
|
||||||
|
unless Object.class_variable_defined?(variable_name)
|
||||||
|
Object.class_variable_set(variable_name, value)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
wiki_options[:page_file_dir] = setting(:page_file_dir) ? setting(:page_file_dir) : wiki_options[:page_file_dir] # Allow settings :page_file_dir through PAGE_FILE_DIR constant.
|
wiki_options[:page_file_dir] = setting(:page_file_dir) ? setting(:page_file_dir) : wiki_options[:page_file_dir] # Allow settings :page_file_dir through PAGE_FILE_DIR constant.
|
||||||
rescue OptionParser::InvalidOption
|
rescue OptionParser::InvalidOption
|
||||||
@@ -88,7 +94,7 @@ rescue OptionParser::InvalidOption
|
|||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
|
|
||||||
REPO = ARGV[0] || Dir.pwd
|
wiki_directory = ARGV[0] || Dir.pwd
|
||||||
|
|
||||||
require 'gollum-lib'
|
require 'gollum-lib'
|
||||||
|
|
||||||
@@ -98,7 +104,7 @@ if cfg = options[:config]
|
|||||||
cfg = File.join(Dir.getwd, cfg) unless cfg.slice(0) == File::SEPARATOR
|
cfg = File.join(Dir.getwd, cfg) unless cfg.slice(0) == File::SEPARATOR
|
||||||
require cfg
|
require cfg
|
||||||
end
|
end
|
||||||
|
|
||||||
class Gollum::Filter::CodeMigrator < Gollum::Filter::Code
|
class Gollum::Filter::CodeMigrator < Gollum::Filter::Code
|
||||||
def extract(data)
|
def extract(data)
|
||||||
case @markup.format
|
case @markup.format
|
||||||
@@ -126,7 +132,7 @@ class Gollum::Filter::CodeMigrator < Gollum::Filter::Code
|
|||||||
next '' if m_end.length < m_start.length
|
next '' if m_end.length < m_start.length
|
||||||
lang = m_lang ? m_lang.strip.split.first : nil
|
lang = m_lang ? m_lang.strip.split.first : nil
|
||||||
cache_codeblock($~.to_s)
|
cache_codeblock($~.to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
data.gsub!(/^([ ]{0,3})``` ?([^\r\n]+)?\r?\n(.+?)\r?\n[ ]{0,3}```[ \t]*\r?$/m) do
|
data.gsub!(/^([ ]{0,3})``` ?([^\r\n]+)?\r?\n(.+?)\r?\n[ ]{0,3}```[ \t]*\r?$/m) do
|
||||||
@@ -134,7 +140,7 @@ class Gollum::Filter::CodeMigrator < Gollum::Filter::Code
|
|||||||
end
|
end
|
||||||
data
|
data
|
||||||
end
|
end
|
||||||
|
|
||||||
def process(data)
|
def process(data)
|
||||||
return data if data.nil? || data.size.zero? || @map.size.zero?
|
return data if data.nil? || data.size.zero? || @map.size.zero?
|
||||||
@map.each do |id, block| ## Just put the code blocks back in verbatim
|
@map.each do |id, block| ## Just put the code blocks back in verbatim
|
||||||
@@ -142,23 +148,23 @@ class Gollum::Filter::CodeMigrator < Gollum::Filter::Code
|
|||||||
end
|
end
|
||||||
data
|
data
|
||||||
end
|
end
|
||||||
|
|
||||||
def cache_codeblock(block)
|
def cache_codeblock(block)
|
||||||
id = "#{open_pattern}#{Digest::SHA1.hexdigest(block)}#{close_pattern}"
|
id = "#{open_pattern}#{Digest::SHA1.hexdigest(block)}#{close_pattern}"
|
||||||
@map[id] = block
|
@map[id] = block
|
||||||
id
|
id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class ::Gollum::Filter::TagMigrator < Gollum::Filter::Tags
|
class ::Gollum::Filter::TagMigrator < Gollum::Filter::Tags
|
||||||
def process_tag(tag)
|
def process_tag(tag)
|
||||||
link_part, extra = parse_tag_parts(tag)
|
link_part, extra = parse_tag_parts(tag)
|
||||||
orig_tag = %{[[#{tag}]]}
|
orig_tag = %{[[#{tag}]]}
|
||||||
return orig_tag if link_part.nil?
|
return orig_tag if link_part.nil?
|
||||||
|
|
||||||
img_args = extra ? [extra, link_part] : [link_part]
|
img_args = extra ? [extra, link_part] : [link_part]
|
||||||
mime = MIME::Types.type_for(::File.extname(img_args.first.to_s)).first
|
mime = MIME::Types.type_for(::File.extname(img_args.first.to_s)).first
|
||||||
|
|
||||||
# For any kind of tag other than an internal link: just return the tag.
|
# For any kind of tag other than an internal link: just return the tag.
|
||||||
if tag =~ /^_TOC_/ || link_part =~ /^_$/ || link_part =~ /^#{INCLUDE_TAG}/ || (mime && mime.content_type =~ /^image/) || process_external_link_tag(link_part, extra) || process_file_link_tag(link_part, extra)
|
if tag =~ /^_TOC_/ || link_part =~ /^_$/ || link_part =~ /^#{INCLUDE_TAG}/ || (mime && mime.content_type =~ /^image/) || process_external_link_tag(link_part, extra) || process_file_link_tag(link_part, extra)
|
||||||
return orig_tag
|
return orig_tag
|
||||||
@@ -168,7 +174,7 @@ class ::Gollum::Filter::TagMigrator < Gollum::Filter::Tags
|
|||||||
link = link_part
|
link = link_part
|
||||||
page = find_page_or_file_from_path(link)
|
page = find_page_or_file_from_path(link)
|
||||||
anchor = nil
|
anchor = nil
|
||||||
|
|
||||||
if page.nil? # No match yet, now try finding the page with anchor removed
|
if page.nil? # No match yet, now try finding the page with anchor removed
|
||||||
if pos = link.rindex('#')
|
if pos = link.rindex('#')
|
||||||
anchor = link[pos..-1]
|
anchor = link[pos..-1]
|
||||||
@@ -203,12 +209,12 @@ class ::Gollum::Filter::TagMigrator < Gollum::Filter::Tags
|
|||||||
pick = possibles.first
|
pick = possibles.first
|
||||||
return tag_for_pick(pick, orig_tag, extra, anchor, @markup.page.path)
|
return tag_for_pick(pick, orig_tag, extra, anchor, @markup.page.path)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def tag_for_pick(pick, orig_tag, extra, anchor, linking_page_path)
|
def tag_for_pick(pick, orig_tag, extra, anchor, linking_page_path)
|
||||||
pick = if setting(:prefer_relative)
|
pick = if setting(:prefer_relative)
|
||||||
overlapping_path = Pathname.new(linking_page_path).dirname.to_s
|
overlapping_path = Pathname.new(linking_page_path).dirname.to_s
|
||||||
@@ -220,7 +226,7 @@ class ::Gollum::Filter::TagMigrator < Gollum::Filter::Tags
|
|||||||
end
|
end
|
||||||
new_tag = extra.nil? ? %{[[#{pick}#{anchor}]]} : %{[[#{extra}|#{pick}#{anchor}]]}
|
new_tag = extra.nil? ? %{[[#{pick}#{anchor}]]} : %{[[#{extra}|#{pick}#{anchor}]]}
|
||||||
log(:info, "#{@markup.page.path}: Changing #{orig_tag} -> #{new_tag}")
|
log(:info, "#{@markup.page.path}: Changing #{orig_tag} -> #{new_tag}")
|
||||||
new_tag
|
new_tag
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -232,8 +238,12 @@ end
|
|||||||
|
|
||||||
filter_chain = [:PlainTextMigrator, :CodeMigrator, :TagMigrator]
|
filter_chain = [:PlainTextMigrator, :CodeMigrator, :TagMigrator]
|
||||||
|
|
||||||
wiki = ::Gollum::Wiki.new(REPO, wiki_options.merge({:filter_chain => filter_chain}))
|
wiki = ::Gollum::Wiki.new(wiki_directory, wiki_options.merge({:filter_chain => filter_chain}))
|
||||||
TREE = wiki.tree_list(wiki.ref, true, true).map {|file| ::File.join('/', file.path)}
|
|
||||||
|
Object.class_variable_set(
|
||||||
|
:"@@wiki_tree",
|
||||||
|
wiki.tree_list(wiki.ref, true, true).map {|file| ::File.join('/', file.path)}
|
||||||
|
)
|
||||||
|
|
||||||
def find_linked(link)
|
def find_linked(link)
|
||||||
link.gsub!(' ', '-') if setting(:hyphenate) # Match paths containing dashes instead of spaces
|
link.gsub!(' ', '-') if setting(:hyphenate) # Match paths containing dashes instead of spaces
|
||||||
@@ -243,7 +253,9 @@ def find_linked(link)
|
|||||||
test_path = ::File.extname(link).empty? ? /#{link}\..+/ : link
|
test_path = ::File.extname(link).empty? ? /#{link}\..+/ : link
|
||||||
# Select pages from the wiki whose path =~ 'Foo/Bar/Samwi.*'
|
# Select pages from the wiki whose path =~ 'Foo/Bar/Samwi.*'
|
||||||
# Match case-insenstively to mimic 4.x behavior!
|
# Match case-insenstively to mimic 4.x behavior!
|
||||||
TREE.select {|path| path =~ /^\/(.*\/)?#{test_path}/i}
|
Object.class_variable_get(:"@@wiki_tree").select { |path|
|
||||||
|
path =~ /^\/(.*\/)?#{test_path}/i
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def log(kind, msg = nil)
|
def log(kind, msg = nil)
|
||||||
@@ -268,4 +280,4 @@ wiki.pages.each do |page|
|
|||||||
f.close
|
f.close
|
||||||
end
|
end
|
||||||
log(:none, '====')
|
log(:none, '====')
|
||||||
end
|
end
|
||||||
|
|||||||
+10
-1
@@ -5,5 +5,14 @@ if [ ! -d .git ]; then
|
|||||||
git init
|
git init
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Set git user.name and user.email
|
||||||
|
if [ ${GOLLUM_AUTHOR_USERNAME:+1} ]; then
|
||||||
|
git config user.name "${GOLLUM_AUTHOR_USERNAME}"
|
||||||
|
fi
|
||||||
|
if [ ${GOLLUM_AUTHOR_EMAIL:+1} ]; then
|
||||||
|
git config user.email "${GOLLUM_AUTHOR_EMAIL}"
|
||||||
|
fi
|
||||||
|
|
||||||
# Start gollum service
|
# Start gollum service
|
||||||
gollum --mathjax
|
[[ "$@" != *--mathjax* ]] && echo "WARNING: Mathjax will soon be disabled by default. To explicitly enable it, use --mathjax" >&2
|
||||||
|
exec gollum $@ --mathjax
|
||||||
|
|||||||
+17
-13
@@ -1,12 +1,9 @@
|
|||||||
Gem::Specification.new do |s|
|
Gem::Specification.new do |s|
|
||||||
s.specification_version = 2 if s.respond_to? :specification_version=
|
|
||||||
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
||||||
s.rubygems_version = '1.3.5'
|
s.required_ruby_version = '>= 2.6'
|
||||||
s.required_ruby_version = '>= 1.9'
|
|
||||||
|
|
||||||
s.name = 'gollum'
|
s.name = 'gollum'
|
||||||
s.version = '5.2.3'
|
s.version = '5.3.0'
|
||||||
s.date = '2021-04-18'
|
|
||||||
s.license = 'MIT'
|
s.license = 'MIT'
|
||||||
|
|
||||||
s.summary = 'A simple, Git-powered wiki.'
|
s.summary = 'A simple, Git-powered wiki.'
|
||||||
@@ -23,6 +20,7 @@ Gem::Specification.new do |s|
|
|||||||
s.rdoc_options = ['--charset=UTF-8']
|
s.rdoc_options = ['--charset=UTF-8']
|
||||||
s.extra_rdoc_files = %w[README.md LICENSE]
|
s.extra_rdoc_files = %w[README.md LICENSE]
|
||||||
|
|
||||||
|
s.add_dependency 'rdoc', '~> 6'
|
||||||
s.add_dependency 'gollum-lib', '~> 5.1'
|
s.add_dependency 'gollum-lib', '~> 5.1'
|
||||||
s.add_dependency 'kramdown', '~> 2.3'
|
s.add_dependency 'kramdown', '~> 2.3'
|
||||||
s.add_dependency 'kramdown-parser-gfm', '~> 1.1.0'
|
s.add_dependency 'kramdown-parser-gfm', '~> 1.1.0'
|
||||||
@@ -44,15 +42,16 @@ Gem::Specification.new do |s|
|
|||||||
s.add_development_dependency 'rack-test', '~> 0.6.3'
|
s.add_development_dependency 'rack-test', '~> 0.6.3'
|
||||||
s.add_development_dependency 'shoulda', '~> 3.6.0'
|
s.add_development_dependency 'shoulda', '~> 3.6.0'
|
||||||
s.add_development_dependency 'minitest-reporters', '~> 1.3.6'
|
s.add_development_dependency 'minitest-reporters', '~> 1.3.6'
|
||||||
s.add_development_dependency 'twitter_cldr', '~> 3.2.0'
|
|
||||||
s.add_development_dependency 'mocha', '~> 1.8.0'
|
s.add_development_dependency 'mocha', '~> 1.8.0'
|
||||||
s.add_development_dependency 'test-unit', '~> 3.3.0'
|
s.add_development_dependency 'test-unit', '~> 3.3.0'
|
||||||
|
|
||||||
# = MANIFEST =
|
# = MANIFEST =
|
||||||
s.files = %w[
|
s.files = %w[
|
||||||
CONTRIBUTING.md
|
CONTRIBUTING.md
|
||||||
|
Dockerfile
|
||||||
Gemfile
|
Gemfile
|
||||||
HISTORY.md
|
HISTORY.md
|
||||||
|
LATEST_CHANGES.md
|
||||||
LICENSE
|
LICENSE
|
||||||
README.md
|
README.md
|
||||||
Rakefile
|
Rakefile
|
||||||
@@ -65,20 +64,21 @@ Gem::Specification.new do |s|
|
|||||||
contrib/openrc/init.d/gollum
|
contrib/openrc/init.d/gollum
|
||||||
contrib/systemd/gollum@.service
|
contrib/systemd/gollum@.service
|
||||||
contrib/sysv-debian/init.d/gollum
|
contrib/sysv-debian/init.d/gollum
|
||||||
|
docker-run.sh
|
||||||
gollum.gemspec
|
gollum.gemspec
|
||||||
lib/gollum.rb
|
lib/gollum.rb
|
||||||
lib/gollum/app.rb
|
lib/gollum/app.rb
|
||||||
lib/gollum/assets.rb
|
lib/gollum/assets.rb
|
||||||
lib/gollum/helpers.rb
|
lib/gollum/helpers.rb
|
||||||
lib/gollum/public/assets/.sprockets-manifest-de7bb79aec424e55af1acdcc4237b301.json
|
lib/gollum/public/assets/.sprockets-manifest-160337b312f8e438181baac4aaa37319.json
|
||||||
lib/gollum/public/assets/app-0fd228e26bfbe6fe31a2da268eb0e98e780c1191c1a918adf383377946e9c838.js
|
lib/gollum/public/assets/app-309be032396e783b13a47df58f389b7c8e11c2b2d42640560b874f677c25f6e5.css
|
||||||
lib/gollum/public/assets/app-0fd228e26bfbe6fe31a2da268eb0e98e780c1191c1a918adf383377946e9c838.js.gz
|
lib/gollum/public/assets/app-309be032396e783b13a47df58f389b7c8e11c2b2d42640560b874f677c25f6e5.css.gz
|
||||||
lib/gollum/public/assets/app-ad43ca64b295d8444b10f22ee868f18429268af498f1bc515434878b690e37a2.css
|
lib/gollum/public/assets/app-f05401ee374f0c7f48fc2bc08e30b4f4db705861fd5895ed70998683b383bfb5.js
|
||||||
lib/gollum/public/assets/app-ad43ca64b295d8444b10f22ee868f18429268af498f1bc515434878b690e37a2.css.gz
|
lib/gollum/public/assets/app-f05401ee374f0c7f48fc2bc08e30b4f4db705861fd5895ed70998683b383bfb5.js.gz
|
||||||
lib/gollum/public/assets/criticmarkup-31ae5d3282bbb8e7b7c3c9917e9fb68e3315a6b4a75da6cec48d21b8846905c4.css
|
lib/gollum/public/assets/criticmarkup-31ae5d3282bbb8e7b7c3c9917e9fb68e3315a6b4a75da6cec48d21b8846905c4.css
|
||||||
lib/gollum/public/assets/criticmarkup-31ae5d3282bbb8e7b7c3c9917e9fb68e3315a6b4a75da6cec48d21b8846905c4.css.gz
|
lib/gollum/public/assets/criticmarkup-31ae5d3282bbb8e7b7c3c9917e9fb68e3315a6b4a75da6cec48d21b8846905c4.css.gz
|
||||||
lib/gollum/public/assets/editor-db10c8351306e92f1926ba225d0cd9c8e886482b3b9820a85825ec3abab5f1cf.js
|
lib/gollum/public/assets/editor-9881d0c7ae663293f0e3a7e72729eec7e940fa613185c076709b76d292f5703a.js
|
||||||
lib/gollum/public/assets/editor-db10c8351306e92f1926ba225d0cd9c8e886482b3b9820a85825ec3abab5f1cf.js.gz
|
lib/gollum/public/assets/editor-9881d0c7ae663293f0e3a7e72729eec7e940fa613185c076709b76d292f5703a.js.gz
|
||||||
lib/gollum/public/assets/print-512498c368be0d3fb1ba105dfa84289ae48380ec9fcbef948bd4e23b0b095bfb.css
|
lib/gollum/public/assets/print-512498c368be0d3fb1ba105dfa84289ae48380ec9fcbef948bd4e23b0b095bfb.css
|
||||||
lib/gollum/public/assets/print-512498c368be0d3fb1ba105dfa84289ae48380ec9fcbef948bd4e23b0b095bfb.css.gz
|
lib/gollum/public/assets/print-512498c368be0d3fb1ba105dfa84289ae48380ec9fcbef948bd4e23b0b095bfb.css.gz
|
||||||
lib/gollum/public/gollum/javascript/HOWTO_UPDATE_ACE.md
|
lib/gollum/public/gollum/javascript/HOWTO_UPDATE_ACE.md
|
||||||
@@ -1153,6 +1153,7 @@ Gem::Specification.new do |s|
|
|||||||
lib/gollum/public/gollum/javascript/ace/worker-xquery.js
|
lib/gollum/public/gollum/javascript/ace/worker-xquery.js
|
||||||
lib/gollum/public/gollum/javascript/app.js
|
lib/gollum/public/gollum/javascript/app.js
|
||||||
lib/gollum/public/gollum/javascript/clipboard.min.js
|
lib/gollum/public/gollum/javascript/clipboard.min.js
|
||||||
|
lib/gollum/public/gollum/javascript/date.min.js
|
||||||
lib/gollum/public/gollum/javascript/editor.js
|
lib/gollum/public/gollum/javascript/editor.js
|
||||||
lib/gollum/public/gollum/javascript/editor/gollum.editor.js
|
lib/gollum/public/gollum/javascript/editor/gollum.editor.js
|
||||||
lib/gollum/public/gollum/javascript/editor/langs/asciidoc.js
|
lib/gollum/public/gollum/javascript/editor/langs/asciidoc.js
|
||||||
@@ -1219,9 +1220,11 @@ Gem::Specification.new do |s|
|
|||||||
lib/gollum/views/edit.rb
|
lib/gollum/views/edit.rb
|
||||||
lib/gollum/views/editable.rb
|
lib/gollum/views/editable.rb
|
||||||
lib/gollum/views/error.rb
|
lib/gollum/views/error.rb
|
||||||
|
lib/gollum/views/has_math.rb
|
||||||
lib/gollum/views/has_page.rb
|
lib/gollum/views/has_page.rb
|
||||||
lib/gollum/views/has_user_icons.rb
|
lib/gollum/views/has_user_icons.rb
|
||||||
lib/gollum/views/helpers.rb
|
lib/gollum/views/helpers.rb
|
||||||
|
lib/gollum/views/helpers/locale_helpers.rb
|
||||||
lib/gollum/views/history.rb
|
lib/gollum/views/history.rb
|
||||||
lib/gollum/views/latest_changes.rb
|
lib/gollum/views/latest_changes.rb
|
||||||
lib/gollum/views/layout.rb
|
lib/gollum/views/layout.rb
|
||||||
@@ -1230,6 +1233,7 @@ Gem::Specification.new do |s|
|
|||||||
lib/gollum/views/pagination.rb
|
lib/gollum/views/pagination.rb
|
||||||
lib/gollum/views/rss.rb
|
lib/gollum/views/rss.rb
|
||||||
lib/gollum/views/search.rb
|
lib/gollum/views/search.rb
|
||||||
|
lib/gollum/views/template_cascade.rb
|
||||||
licenses/licenses.txt
|
licenses/licenses.txt
|
||||||
]
|
]
|
||||||
# = MANIFEST =
|
# = MANIFEST =
|
||||||
|
|||||||
+6
-4
@@ -13,8 +13,9 @@ require 'rhino' if RUBY_PLATFORM == 'java'
|
|||||||
require ::File.expand_path('../gollum/uri_encode_component', __FILE__)
|
require ::File.expand_path('../gollum/uri_encode_component', __FILE__)
|
||||||
|
|
||||||
module Gollum
|
module Gollum
|
||||||
VERSION = '5.2.3'
|
VERSION = '5.3.0'
|
||||||
|
KEYBINDINGS = ['default', 'vim', 'emacs']
|
||||||
|
|
||||||
::I18n.available_locales = [:en]
|
::I18n.available_locales = [:en]
|
||||||
::I18n.load_path = Dir[::File.expand_path("lib/gollum/locales") + "/*.yml"]
|
::I18n.load_path = Dir[::File.expand_path("lib/gollum/locales") + "/*.yml"]
|
||||||
|
|
||||||
@@ -29,9 +30,10 @@ module Gollum
|
|||||||
@@filters[pattern] = replacement
|
@@filters[pattern] = replacement
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.apply_filters(data)
|
def self.apply_filters(wiki_page, data)
|
||||||
@@filters.each do |pattern, replacement|
|
@@filters.each do |pattern, replacement|
|
||||||
data.gsub!(pattern, replacement.call)
|
params = replacement.parameters.length == 0 ? nil : wiki_page
|
||||||
|
data.gsub!(pattern, replacement.call(*params))
|
||||||
end
|
end
|
||||||
data
|
data
|
||||||
end
|
end
|
||||||
|
|||||||
+48
-45
@@ -20,6 +20,7 @@ require 'gollum/views/layout'
|
|||||||
require 'gollum/views/editable'
|
require 'gollum/views/editable'
|
||||||
require 'gollum/views/has_page'
|
require 'gollum/views/has_page'
|
||||||
require 'gollum/views/has_user_icons'
|
require 'gollum/views/has_user_icons'
|
||||||
|
require 'gollum/views/has_math'
|
||||||
require 'gollum/views/pagination'
|
require 'gollum/views/pagination'
|
||||||
require 'gollum/views/rss.rb'
|
require 'gollum/views/rss.rb'
|
||||||
require 'gollum/views/template_cascade'
|
require 'gollum/views/template_cascade'
|
||||||
@@ -102,15 +103,14 @@ module Precious
|
|||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
settings.wiki_options[:allow_editing] = settings.wiki_options.fetch(:allow_editing, true)
|
@allow_editing = settings.wiki_options.fetch(:allow_editing, true)
|
||||||
@allow_editing = settings.wiki_options[:allow_editing]
|
|
||||||
@critic_markup = settings.wiki_options[:critic_markup]
|
@critic_markup = settings.wiki_options[:critic_markup]
|
||||||
@redirects_enabled = settings.wiki_options.fetch(:redirects_enabled, true)
|
@redirects_enabled = settings.wiki_options.fetch(:redirects_enabled, true)
|
||||||
@per_page_uploads = settings.wiki_options[:per_page_uploads]
|
@per_page_uploads = settings.wiki_options[:per_page_uploads]
|
||||||
|
@show_local_time = settings.wiki_options.fetch(:show_local_time, false)
|
||||||
|
|
||||||
@wiki_title = settings.wiki_options.fetch(:title, 'Gollum Wiki')
|
@wiki_title = settings.wiki_options.fetch(:title, 'Gollum Wiki')
|
||||||
|
@default_keybinding = settings.wiki_options.fetch(:default_keybinding, 'default')
|
||||||
forbid unless @allow_editing || request.request_method == 'GET'
|
|
||||||
|
|
||||||
if settings.wiki_options[:template_dir]
|
if settings.wiki_options[:template_dir]
|
||||||
Precious::Views::Layout.extend Precious::Views::TemplateCascade
|
Precious::Views::Layout.extend Precious::Views::TemplateCascade
|
||||||
@@ -125,6 +125,7 @@ module Precious
|
|||||||
@css = settings.wiki_options[:css]
|
@css = settings.wiki_options[:css]
|
||||||
@js = settings.wiki_options[:js]
|
@js = settings.wiki_options[:js]
|
||||||
@mathjax_config = settings.wiki_options[:mathjax_config]
|
@mathjax_config = settings.wiki_options[:mathjax_config]
|
||||||
|
@mathjax = settings.wiki_options[:mathjax]
|
||||||
|
|
||||||
@use_static_assets = settings.wiki_options.fetch(:static, settings.environment != :development)
|
@use_static_assets = settings.wiki_options.fetch(:static, settings.environment != :development)
|
||||||
@static_assets_path = settings.wiki_options.fetch(:static_assets_path, ::File.join(File.dirname(__FILE__), 'public/assets'))
|
@static_assets_path = settings.wiki_options.fetch(:static_assets_path, ::File.join(File.dirname(__FILE__), 'public/assets'))
|
||||||
@@ -140,6 +141,8 @@ module Precious
|
|||||||
config.manifest = Sprockets::Manifest.new(settings.sprockets, @static_assets_path)
|
config.manifest = Sprockets::Manifest.new(settings.sprockets, @static_assets_path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
forbid unless @allow_editing || request.request_method == 'GET'
|
||||||
end
|
end
|
||||||
|
|
||||||
get '/' do
|
get '/' do
|
||||||
@@ -176,7 +179,9 @@ module Precious
|
|||||||
content_type :json
|
content_type :json
|
||||||
if page = wiki_page(params[:path]).page
|
if page = wiki_page(params[:path]).page
|
||||||
version = page.last_version
|
version = page.last_version
|
||||||
{:author => version.author.name, :date => version.authored_date}.to_json
|
authored_date = version.authored_date
|
||||||
|
authored_date = authored_date.utc.iso8601 if @show_local_time
|
||||||
|
{:author => version.author.name, :date => authored_date}.to_json
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -217,7 +222,6 @@ module Precious
|
|||||||
if page = wikip.page
|
if page = wikip.page
|
||||||
@page = page
|
@page = page
|
||||||
@content = page.text_data
|
@content = page.text_data
|
||||||
@mathjax = wiki.mathjax
|
|
||||||
@etag = page.sha
|
@etag = page.sha
|
||||||
mustache :edit
|
mustache :edit
|
||||||
else
|
else
|
||||||
@@ -237,22 +241,9 @@ module Precious
|
|||||||
tempfile = params[:file][:tempfile]
|
tempfile = params[:file][:tempfile]
|
||||||
end
|
end
|
||||||
halt 500 unless tempfile.is_a? Tempfile
|
halt 500 unless tempfile.is_a? Tempfile
|
||||||
|
|
||||||
|
dir = wiki.per_page_uploads ? find_per_page_upload_subdir(request.referer, request.host_with_port, wiki.base_path) : 'uploads'
|
||||||
|
|
||||||
if wiki.per_page_uploads
|
|
||||||
dir = request.referer.sub(request.base_url, '')
|
|
||||||
# remove base path if it is set
|
|
||||||
dir.sub!(/^#{wiki.base_path}/, '') if wiki.base_path
|
|
||||||
# remove base_url and gollum/* subpath if necessary
|
|
||||||
dir.sub!(/^\/gollum\/[-\w]+\//, '')
|
|
||||||
# remove file extension
|
|
||||||
dir.sub!(/#{::File.extname(dir)}$/, '')
|
|
||||||
# revert escaped whitespaces
|
|
||||||
dir.gsub!(/%20/, ' ')
|
|
||||||
dir = ::File.join('uploads', dir)
|
|
||||||
else
|
|
||||||
# store all uploads together
|
|
||||||
dir = 'uploads'
|
|
||||||
end
|
|
||||||
halt 500 if dir.include?('..')
|
halt 500 if dir.include?('..')
|
||||||
halt 500 unless Pathname(dir).relative?
|
halt 500 unless Pathname(dir).relative?
|
||||||
|
|
||||||
@@ -270,7 +261,7 @@ module Precious
|
|||||||
options.merge! author
|
options.merge! author
|
||||||
end
|
end
|
||||||
|
|
||||||
normalize = Gollum::Page.valid_extension?(fullname)
|
options[:normalize] = Gollum::Page.valid_extension?(fullname)
|
||||||
|
|
||||||
begin
|
begin
|
||||||
wiki.write_file(reponame, contents, options)
|
wiki.write_file(reponame, contents, options)
|
||||||
@@ -365,7 +356,7 @@ module Precious
|
|||||||
@name = wikip.name
|
@name = wikip.name
|
||||||
@ext = wikip.ext
|
@ext = wikip.ext
|
||||||
@path = wikip.path
|
@path = wikip.path
|
||||||
@template_page = load_template(@path) if settings.wiki_options[:template_page]
|
@template_page = load_template(wikip, @path) if settings.wiki_options[:template_page]
|
||||||
@allow_uploads = wikip.wiki.allow_uploads
|
@allow_uploads = wikip.wiki.allow_uploads
|
||||||
@upload_dest = find_upload_dest(wikip.fullpath)
|
@upload_dest = find_upload_dest(wikip.fullpath)
|
||||||
|
|
||||||
@@ -439,23 +430,18 @@ module Precious
|
|||||||
mustache :page
|
mustache :page
|
||||||
end
|
end
|
||||||
|
|
||||||
|
get %r{
|
||||||
|
/history/ # match any URL beginning with /history/
|
||||||
|
(.+?) # extract the full path (including any directories)
|
||||||
|
/
|
||||||
|
([0-9a-f]{40}) # match SHA
|
||||||
|
}x do |path, version|
|
||||||
|
wiki = wiki_new
|
||||||
|
show_history wiki_page(path, wiki.commit_for(version), wiki)
|
||||||
|
end
|
||||||
|
|
||||||
get '/history/*' do
|
get '/history/*' do
|
||||||
wikip = wiki_page(params[:splat].first)
|
show_history wiki_page(params[:splat].first)
|
||||||
@name = wikip.fullname
|
|
||||||
@page = wikip.page
|
|
||||||
@page_num = [params[:page_num].to_i, 1].max
|
|
||||||
@max_count = settings.wiki_options.fetch(:pagination_count, 10)
|
|
||||||
unless @page.nil?
|
|
||||||
@wiki = @page.wiki
|
|
||||||
@versions = @page.versions(
|
|
||||||
per_page: @max_count,
|
|
||||||
page_num: @page_num,
|
|
||||||
follow: settings.wiki_options.fetch(:follow_renames, true)
|
|
||||||
)
|
|
||||||
mustache :history
|
|
||||||
else
|
|
||||||
redirect to("/")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
get '/latest_changes' do
|
get '/latest_changes' do
|
||||||
@@ -602,6 +588,24 @@ module Precious
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def show_history(wikip)
|
||||||
|
@name = wikip.fullname
|
||||||
|
@page = wikip.page
|
||||||
|
@page_num = [params[:page_num].to_i, 1].max
|
||||||
|
@max_count = settings.wiki_options.fetch(:pagination_count, 10)
|
||||||
|
unless @page.nil?
|
||||||
|
@wiki = @page.wiki
|
||||||
|
@versions = @page.versions(
|
||||||
|
per_page: @max_count,
|
||||||
|
page_num: @page_num,
|
||||||
|
follow: settings.wiki_options.fetch(:follow_renames, true)
|
||||||
|
)
|
||||||
|
mustache :history
|
||||||
|
else
|
||||||
|
redirect to("/")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def show_page_or_file(fullpath)
|
def show_page_or_file(fullpath)
|
||||||
wiki = wiki_new
|
wiki = wiki_new
|
||||||
if page = wiki.page(fullpath)
|
if page = wiki.page(fullpath)
|
||||||
@@ -613,7 +617,6 @@ module Precious
|
|||||||
# Extensions and layout data
|
# Extensions and layout data
|
||||||
@editable = true
|
@editable = true
|
||||||
@toc_content = wiki.universal_toc ? @page.toc_data : nil
|
@toc_content = wiki.universal_toc ? @page.toc_data : nil
|
||||||
@mathjax = wiki.mathjax
|
|
||||||
@h1_title = wiki.h1_title
|
@h1_title = wiki.h1_title
|
||||||
@bar_side = wiki.bar_side
|
@bar_side = wiki.bar_side
|
||||||
@allow_uploads = wiki.allow_uploads
|
@allow_uploads = wiki.allow_uploads
|
||||||
@@ -645,9 +648,9 @@ module Precious
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_template(path)
|
def load_template(wiki_page, path)
|
||||||
template_page = wiki_page(::File.join(path, '_Template')).page || wiki_page('/_Template').page
|
template_page = wiki_page(::File.join(path, '_Template')).page || wiki_page('/_Template').page
|
||||||
template_page ? Gollum::TemplateFilter.apply_filters(template_page.text_data) : nil
|
template_page ? Gollum::TemplateFilter.apply_filters(wiki_page, template_page.text_data) : nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_wiki_page(wiki, page, content, commit, name = nil, format = nil)
|
def update_wiki_page(wiki, page, content, commit, name = nil, format = nil)
|
||||||
@@ -659,9 +662,9 @@ module Precious
|
|||||||
wiki.update_page(page, name, format, content.to_s, commit)
|
wiki.update_page(page, name, format, content.to_s, commit)
|
||||||
end
|
end
|
||||||
|
|
||||||
def wiki_page(path, version = nil)
|
def wiki_page(path, version = nil, wiki = nil)
|
||||||
pathname = (Pathname.new('/') + path).cleanpath
|
pathname = (Pathname.new('/') + path).cleanpath
|
||||||
wiki = wiki_new
|
wiki = wiki_new if wiki.nil?
|
||||||
OpenStruct.new(:wiki => wiki, :page => wiki.page(pathname.to_s, version = version),
|
OpenStruct.new(:wiki => wiki, :page => wiki.page(pathname.to_s, version = version),
|
||||||
:name => pathname.basename.sub_ext('').to_s, :path => pathname.dirname.to_s, :ext => pathname.extname, :fullname => pathname.basename.to_s, :fullpath => pathname.to_s)
|
:name => pathname.basename.sub_ext('').to_s, :path => pathname.dirname.to_s, :ext => pathname.extname, :fullname => pathname.basename.to_s, :fullpath => pathname.to_s)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,8 +7,12 @@ module Precious
|
|||||||
|
|
||||||
def self.sprockets(dir = File.dirname(File.expand_path(__FILE__)))
|
def self.sprockets(dir = File.dirname(File.expand_path(__FILE__)))
|
||||||
env = Sprockets::Environment.new
|
env = Sprockets::Environment.new
|
||||||
env.append_path ::File.join(dir, 'public/gollum/stylesheets/')
|
|
||||||
|
env.append_path ::File.join(dir, '../../node_modules')
|
||||||
|
|
||||||
env.append_path ::File.join(dir, 'public/gollum/javascript')
|
env.append_path ::File.join(dir, 'public/gollum/javascript')
|
||||||
|
env.append_path ::File.join(dir, 'public/gollum/stylesheets/')
|
||||||
|
|
||||||
env.append_path ::File.join(dir, 'public/gollum/images')
|
env.append_path ::File.join(dir, 'public/gollum/images')
|
||||||
env.append_path ::File.join(dir, 'public/gollum/fonts')
|
env.append_path ::File.join(dir, 'public/gollum/fonts')
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,20 @@ module Precious
|
|||||||
module Helpers
|
module Helpers
|
||||||
|
|
||||||
EMOJI_PATHNAME = Pathname.new(Gemojione.images_path).freeze
|
EMOJI_PATHNAME = Pathname.new(Gemojione.images_path).freeze
|
||||||
|
|
||||||
|
def find_per_page_upload_subdir(referer, host_with_port, base_path)
|
||||||
|
base = base_path ? remove_leading_and_trailing_slashes(base_path) : ''
|
||||||
|
dir = referer.match(/^https?:\/\/#{host_with_port}\/#{base}\/?(.*)/)[1]
|
||||||
|
|
||||||
|
# remove gollum/* subpath if necessary
|
||||||
|
dir.sub!(/^gollum\/[-\w]+\//, '')
|
||||||
|
# remove file extension
|
||||||
|
dir.sub!(/#{::File.extname(dir)}$/, '')
|
||||||
|
# revert escaped whitespaces
|
||||||
|
dir.gsub!(/%20/, ' ')
|
||||||
|
|
||||||
|
return ::File.join('uploads', dir)
|
||||||
|
end
|
||||||
|
|
||||||
def sanitize_empty_params(param)
|
def sanitize_empty_params(param)
|
||||||
[nil, ''].include?(param) ? nil : CGI.unescape(param)
|
[nil, ''].include?(param) ? nil : CGI.unescape(param)
|
||||||
@@ -14,6 +28,10 @@ module Precious
|
|||||||
# Check if name already has a format extension, and if so, strip it.
|
# Check if name already has a format extension, and if so, strip it.
|
||||||
Gollum::Page.valid_extension?(name) ? Gollum::Page.strip_filename(name) : name
|
Gollum::Page.valid_extension?(name) ? Gollum::Page.strip_filename(name) : name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remove_leading_and_trailing_slashes(str)
|
||||||
|
str.sub(%r{^(/+)}, '').sub(%r{/+$}, '')
|
||||||
|
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
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
en:
|
||||||
|
pagination:
|
||||||
|
aria:
|
||||||
|
label: Pagination
|
||||||
|
next_page: Next page
|
||||||
|
previous_page: Previous page
|
||||||
|
next: Next
|
||||||
|
previous: Previous
|
||||||
|
precious/views/compare:
|
||||||
|
back_to_page_history: Back to Page History
|
||||||
|
back_to_top: Back to Top
|
||||||
|
comparison_of: Comparison of
|
||||||
|
comparing_versions_of: Comparing versions of
|
||||||
|
comparing_from: "Comparing %{before} to %{after}"
|
||||||
|
revert: Revert Changes
|
||||||
|
precious/views/error:
|
||||||
|
error: Error
|
||||||
|
precious/views/history:
|
||||||
|
browse_in_history_description: Browse the page at this point in the history
|
||||||
|
compare_revisions: Compare Revisions
|
||||||
|
history_for: History for
|
||||||
|
precious/views/latest_changes:
|
||||||
|
title: Latest Changes (Globally)
|
||||||
|
precious/views/layout:
|
||||||
|
title: Home
|
||||||
|
precious/views/overview:
|
||||||
|
back_to_top: Back to Top
|
||||||
|
delete_confirmation: "Are you sure you want to delete %{name}?"
|
||||||
|
no_pages_in: There are no pages in
|
||||||
|
on: "on"
|
||||||
|
title: "Overview of %{ref}"
|
||||||
|
precious/views/search:
|
||||||
|
aria:
|
||||||
|
show_all: Show all hits on this page
|
||||||
|
back_to_top: Back to Top
|
||||||
|
no_results: There are no results for your search
|
||||||
|
search_results_for: Search results for
|
||||||
|
title: "Search results for %{query}"
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"files":{"app-f05401ee374f0c7f48fc2bc08e30b4f4db705861fd5895ed70998683b383bfb5.js":{"logical_path":"app.js","mtime":"2021-07-10T00:40:20+09:00","size":136040,"digest":"f05401ee374f0c7f48fc2bc08e30b4f4db705861fd5895ed70998683b383bfb5","integrity":"sha256-8FQB7jdPDH9I/CvAjjC09NtwWGH9WJXtcJmGg7ODv7U="},"editor-9881d0c7ae663293f0e3a7e72729eec7e940fa613185c076709b76d292f5703a.js":{"logical_path":"editor.js","mtime":"2021-07-10T00:42:29+09:00","size":744886,"digest":"9881d0c7ae663293f0e3a7e72729eec7e940fa613185c076709b76d292f5703a","integrity":"sha256-mIHQx65mMpPw46fnJynux+lA+mExhcB2cJt20pL1cDo="},"app-cb122b4c17500faa5e013cb43334fafcf2dd7d72f694b06d9616f8b33fefb694.css":{"logical_path":"app.css","mtime":"2021-07-10T00:39:36+09:00","size":396625,"digest":"cb122b4c17500faa5e013cb43334fafcf2dd7d72f694b06d9616f8b33fefb694","integrity":"sha256-yxIrTBdQD6peATy0MzT6/PLdfXL2lLBtlhb4sz/vtpQ="},"criticmarkup-31ae5d3282bbb8e7b7c3c9917e9fb68e3315a6b4a75da6cec48d21b8846905c4.css":{"logical_path":"criticmarkup.css","mtime":"2021-07-08T05:19:03+09:00","size":646,"digest":"31ae5d3282bbb8e7b7c3c9917e9fb68e3315a6b4a75da6cec48d21b8846905c4","integrity":"sha256-Ma5dMoK7uOe3w8mRfp+2jjMVprSnXabOxI0huIRpBcQ="},"print-512498c368be0d3fb1ba105dfa84289ae48380ec9fcbef948bd4e23b0b095bfb.css":{"logical_path":"print.css","mtime":"2021-07-08T05:19:03+09:00","size":75,"digest":"512498c368be0d3fb1ba105dfa84289ae48380ec9fcbef948bd4e23b0b095bfb","integrity":"sha256-USSYw2i+DT+xuhBd+oQomuSDgOyfy++Ui9TiOwsJW/s="}},"assets":{"app.js":"app-f05401ee374f0c7f48fc2bc08e30b4f4db705861fd5895ed70998683b383bfb5.js","editor.js":"editor-9881d0c7ae663293f0e3a7e72729eec7e940fa613185c076709b76d292f5703a.js","app.css":"app-cb122b4c17500faa5e013cb43334fafcf2dd7d72f694b06d9616f8b33fefb694.css","criticmarkup.css":"criticmarkup-31ae5d3282bbb8e7b7c3c9917e9fb68e3315a6b4a75da6cec48d21b8846905c4.css","print.css":"print-512498c368be0d3fb1ba105dfa84289ae48380ec9fcbef948bd4e23b0b095bfb.css"}}
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"files":{"app-6bef6b19014c6620eab4daf7bc581f9d43fff778bdc78aa9fe53aaa2c927c8cc.js":{"logical_path":"app.js","mtime":"2022-06-03T19:51:43-07:00","size":188397,"digest":"6bef6b19014c6620eab4daf7bc581f9d43fff778bdc78aa9fe53aaa2c927c8cc","integrity":"sha256-a+9rGQFMZiDqtNr3vFgfnUP/93i9x4qp/lOqosknyMw="},"editor-ebdf534a0063fe3b05a7e7daaf7aa40b78fab9863142b161d88f32a3f035378a.js":{"logical_path":"editor.js","mtime":"2022-06-03T19:51:43-07:00","size":745160,"digest":"ebdf534a0063fe3b05a7e7daaf7aa40b78fab9863142b161d88f32a3f035378a","integrity":"sha256-699TSgBj/jsFp+far3qkC3j6uYYxQrFh2I8yo/A1N4o="},"app-309be032396e783b13a47df58f389b7c8e11c2b2d42640560b874f677c25f6e5.css":{"logical_path":"app.css","mtime":"2022-06-03T19:51:43-07:00","size":396731,"digest":"309be032396e783b13a47df58f389b7c8e11c2b2d42640560b874f677c25f6e5","integrity":"sha256-MJvgMjlueDsTpH31jzibfI4RwrLUJkBWC4dPZ3wl9uU="},"criticmarkup-31ae5d3282bbb8e7b7c3c9917e9fb68e3315a6b4a75da6cec48d21b8846905c4.css":{"logical_path":"criticmarkup.css","mtime":"2021-02-24T23:16:14-08:00","size":646,"digest":"31ae5d3282bbb8e7b7c3c9917e9fb68e3315a6b4a75da6cec48d21b8846905c4","integrity":"sha256-Ma5dMoK7uOe3w8mRfp+2jjMVprSnXabOxI0huIRpBcQ="},"print-512498c368be0d3fb1ba105dfa84289ae48380ec9fcbef948bd4e23b0b095bfb.css":{"logical_path":"print.css","mtime":"2021-02-24T23:16:14-08:00","size":75,"digest":"512498c368be0d3fb1ba105dfa84289ae48380ec9fcbef948bd4e23b0b095bfb","integrity":"sha256-USSYw2i+DT+xuhBd+oQomuSDgOyfy++Ui9TiOwsJW/s="}},"assets":{"app.js":"app-6bef6b19014c6620eab4daf7bc581f9d43fff778bdc78aa9fe53aaa2c927c8cc.js","editor.js":"editor-ebdf534a0063fe3b05a7e7daaf7aa40b78fab9863142b161d88f32a3f035378a.js","app.css":"app-309be032396e783b13a47df58f389b7c8e11c2b2d42640560b874f677c25f6e5.css","criticmarkup.css":"criticmarkup-31ae5d3282bbb8e7b7c3c9917e9fb68e3315a6b4a75da6cec48d21b8846905c4.css","print.css":"print-512498c368be0d3fb1ba105dfa84289ae48380ec9fcbef948bd4e23b0b095bfb.css"}}
|
||||||
+1
-1
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
+6
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
-5
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
BIN
Binary file not shown.
+3
-3
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -1,6 +1,10 @@
|
|||||||
|
// Require vendor assets from installed Node modules.
|
||||||
|
//= require mousetrap/mousetrap.min
|
||||||
|
|
||||||
|
// Require application assets.
|
||||||
//= require jquery-1.7.2.min
|
//= require jquery-1.7.2.min
|
||||||
//= require identicon
|
//= require identicon
|
||||||
//= require mousetrap.min
|
//= require date.min
|
||||||
//= require clipboard.min
|
//= require clipboard.min
|
||||||
//= require gollum
|
//= require gollum
|
||||||
//= require gollum.dialog
|
//= require gollum.dialog
|
||||||
|
|||||||
+123
@@ -0,0 +1,123 @@
|
|||||||
|
/**
|
||||||
|
* @overview datejs
|
||||||
|
* @version 1.0.0-rc3
|
||||||
|
* @author Gregory Wild-Smith <gregory@wild-smith.com>
|
||||||
|
* @copyright 2015 Gregory Wild-Smith
|
||||||
|
* @license MIT
|
||||||
|
* @homepage https://github.com/abritinthebay/datejs
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
2015 Gregory Wild-Smith
|
||||||
|
@license MIT
|
||||||
|
@homepage https://github.com/abritinthebay/datejs
|
||||||
|
*/
|
||||||
|
(function(){var h=Date,f=Date.CultureStrings?Date.CultureStrings.lang:null,d={},c={getFromKey:function(a,b){var e;e=Date.CultureStrings&&Date.CultureStrings[b]&&Date.CultureStrings[b][a]?Date.CultureStrings[b][a]:c.buildFromDefault(a);"/"===a.charAt(0)&&(e=c.buildFromRegex(a,b));return e},getFromObjectValues:function(a,b){var e,g={};for(e in a)a.hasOwnProperty(e)&&(g[e]=c.getFromKey(a[e],b));return g},getFromObjectKeys:function(a,b){var e,g={};for(e in a)a.hasOwnProperty(e)&&(g[c.getFromKey(e,b)]=
|
||||||
|
a[e]);return g},getFromArray:function(a,b){for(var e=[],g=0;g<a.length;g++)g in a&&(e[g]=c.getFromKey(a[g],b));return e},buildFromDefault:function(a){var b,e,g;switch(a){case "name":b="en-US";break;case "englishName":b="English (United States)";break;case "nativeName":b="English (United States)";break;case "twoDigitYearMax":b=2049;break;case "firstDayOfWeek":b=0;break;default:if(b=a,g=a.split("_"),e=g.length,1<e&&"/"!==a.charAt(0)&&(a=g[e-1].toLowerCase(),"initial"===a||"abbr"===a))b=g[0]}return b},
|
||||||
|
buildFromRegex:function(a,b){return Date.CultureStrings&&Date.CultureStrings[b]&&Date.CultureStrings[b][a]?new RegExp(Date.CultureStrings[b][a],"i"):new RegExp(a.replace(RegExp("/","g"),""),"i")}},a=function(a,b){var e=b?b:f;d[a]=a;return"object"===typeof a?a instanceof Array?c.getFromArray(a,e):c.getFromObjectKeys(a,e):c.getFromKey(a,e)},b=function(a){a=Date.Config.i18n+a+".js";var b=document.getElementsByTagName("head")[0]||document.documentElement,e=document.createElement("script");e.src=a;var g=
|
||||||
|
{done:function(){}};e.onload=e.onreadystatechange=function(){this.readyState&&"loaded"!==this.readyState&&"complete"!==this.readyState||(g.done(),b.removeChild(e))};setTimeout(function(){b.insertBefore(e,b.firstChild)},0);return{done:function(a){g.done=function(){a&&setTimeout(a,0)}}}},e={buildFromMethodHash:function(a){for(var b in a)a.hasOwnProperty(b)&&(a[b]=e[a[b]]());return a},timeZoneDST:function(){return a({CHADT:"+1345",NZDT:"+1300",AEDT:"+1100",ACDT:"+1030",AZST:"+0500",IRDT:"+0430",EEST:"+0300",
|
||||||
|
CEST:"+0200",BST:"+0100",PMDT:"-0200",ADT:"-0300",NDT:"-0230",EDT:"-0400",CDT:"-0500",MDT:"-0600",PDT:"-0700",AKDT:"-0800",HADT:"-0900"})},timeZoneStandard:function(){return a({LINT:"+1400",TOT:"+1300",CHAST:"+1245",NZST:"+1200",NFT:"+1130",SBT:"+1100",AEST:"+1000",ACST:"+0930",JST:"+0900",CWST:"+0845",CT:"+0800",ICT:"+0700",MMT:"+0630",BST:"+0600",NPT:"+0545",IST:"+0530",PKT:"+0500",AFT:"+0430",MSK:"+0400",IRST:"+0330",FET:"+0300",EET:"+0200",CET:"+0100",GMT:"+0000",UTC:"+0000",CVT:"-0100",GST:"-0200",
|
||||||
|
BRT:"-0300",NST:"-0330",AST:"-0400",EST:"-0500",CST:"-0600",MST:"-0700",PST:"-0800",AKST:"-0900",MIT:"-0930",HST:"-1000",SST:"-1100",BIT:"-1200"})},timeZones:function(a){var b;a.timezones=[];for(b in a.abbreviatedTimeZoneStandard)a.abbreviatedTimeZoneStandard.hasOwnProperty(b)&&a.timezones.push({name:b,offset:a.abbreviatedTimeZoneStandard[b]});for(b in a.abbreviatedTimeZoneDST)a.abbreviatedTimeZoneDST.hasOwnProperty(b)&&a.timezones.push({name:b,offset:a.abbreviatedTimeZoneDST[b],dst:!0});return a.timezones},
|
||||||
|
days:function(){return a("Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "))},dayAbbr:function(){return a("Sun Mon Tue Wed Thu Fri Sat".split(" "))},dayShortNames:function(){return a("Su Mo Tu We Th Fr Sa".split(" "))},dayFirstLetters:function(){return a("S_Sun_Initial M_Mon_Initial T_Tues_Initial W_Wed_Initial T_Thu_Initial F_Fri_Initial S_Sat_Initial".split(" "))},months:function(){return a("January February March April May June July August September October November December".split(" "))},
|
||||||
|
monthAbbr:function(){return a("Jan_Abbr Feb_Abbr Mar_Abbr Apr_Abbr May_Abbr Jun_Abbr Jul_Abbr Aug_Abbr Sep_Abbr Oct_Abbr Nov_Abbr Dec_Abbr".split(" "))},formatPatterns:function(){return c.getFromObjectValues({shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},
|
||||||
|
Date.i18n.currentLanguage())},regex:function(){return c.getFromObjectValues({inTheMorning:"/( in the )(morn(ing)?)\\b/",thisMorning:"/(this )(morn(ing)?)\\b/",amThisMorning:"/(\b\\d(am)? )(this )(morn(ing)?)/",inTheEvening:"/( in the )(even(ing)?)\\b/",thisEvening:"/(this )(even(ing)?)\\b/",pmThisEvening:"/(\b\\d(pm)? )(this )(even(ing)?)/",jan:"/jan(uary)?/",feb:"/feb(ruary)?/",mar:"/mar(ch)?/",apr:"/apr(il)?/",may:"/may/",jun:"/jun(e)?/",jul:"/jul(y)?/",aug:"/aug(ust)?/",sep:"/sep(t(ember)?)?/",
|
||||||
|
oct:"/oct(ober)?/",nov:"/nov(ember)?/",dec:"/dec(ember)?/",sun:"/^su(n(day)?)?/",mon:"/^mo(n(day)?)?/",tue:"/^tu(e(s(day)?)?)?/",wed:"/^we(d(nesday)?)?/",thu:"/^th(u(r(s(day)?)?)?)?/",fri:"/fr(i(day)?)?/",sat:"/^sa(t(urday)?)?/",future:"/^next/",past:"/^last|past|prev(ious)?/",add:"/^(\\+|aft(er)?|from|hence)/",subtract:"/^(\\-|bef(ore)?|ago)/",yesterday:"/^yes(terday)?/",today:"/^t(od(ay)?)?/",tomorrow:"/^tom(orrow)?/",now:"/^n(ow)?/",millisecond:"/^ms|milli(second)?s?/",second:"/^sec(ond)?s?/",
|
||||||
|
minute:"/^mn|min(ute)?s?/",hour:"/^h(our)?s?/",week:"/^w(eek)?s?/",month:"/^m(onth)?s?/",day:"/^d(ay)?s?/",year:"/^y(ear)?s?/",shortMeridian:"/^(a|p)/",longMeridian:"/^(a\\.?m?\\.?|p\\.?m?\\.?)/",timezone:"/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt|utc)/",ordinalSuffix:"/^\\s*(st|nd|rd|th)/",timeContext:"/^\\s*(\\:|a(?!u|p)|p)/"},Date.i18n.currentLanguage())}},g=function(){var a=c.getFromObjectValues({name:"name",englishName:"englishName",nativeName:"nativeName",
|
||||||
|
amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:"firstDayOfWeek",twoDigitYearMax:"twoDigitYearMax",dateElementOrder:"mdy"},Date.i18n.currentLanguage()),b=e.buildFromMethodHash({dayNames:"days",abbreviatedDayNames:"dayAbbr",shortestDayNames:"dayShortNames",firstLetterDayNames:"dayFirstLetters",monthNames:"months",abbreviatedMonthNames:"monthAbbr",formatPatterns:"formatPatterns",regexPatterns:"regex",abbreviatedTimeZoneDST:"timeZoneDST",abbreviatedTimeZoneStandard:"timeZoneStandard"}),g;for(g in b)b.hasOwnProperty(g)&&
|
||||||
|
(a[g]=b[g]);e.timeZones(a);return a};h.i18n={__:function(m,b){return a(m,b)},currentLanguage:function(){return f||"en-US"},setLanguage:function(a,e,c){var d=!1;if(e||"en-US"===a||Date.CultureStrings&&Date.CultureStrings[a])f=a,Date.CultureStrings=Date.CultureStrings||{},Date.CultureStrings.lang=a,Date.CultureInfo=new g;else if(!Date.CultureStrings||!Date.CultureStrings[a])if("undefined"!==typeof exports&&this.exports!==exports)try{require("../i18n/"+a+".js"),f=a,Date.CultureStrings.lang=a,Date.CultureInfo=
|
||||||
|
new g}catch(p){throw Error("The DateJS IETF language tag '"+a+"' could not be loaded by Node. It likely does not exist.");}else if(Date.Config&&Date.Config.i18n)d=!0,b(a).done(function(){f=a;Date.CultureStrings=Date.CultureStrings||{};Date.CultureStrings.lang=a;Date.CultureInfo=new g;h.Parsing.Normalizer.buildReplaceData();h.Grammar&&h.Grammar.buildGrammarFormats();c&&setTimeout(c,0)});else return Date.console.error("The DateJS IETF language tag '"+a+"' is not available and has not been loaded."),
|
||||||
|
!1;h.Parsing.Normalizer.buildReplaceData();h.Grammar&&h.Grammar.buildGrammarFormats();!d&&c&&setTimeout(c,0)},getLoggedKeys:function(){return d},updateCultureInfo:function(){Date.CultureInfo=new g}};h.i18n.updateCultureInfo()})();
|
||||||
|
(function(){var h=Date,f=h.prototype,d=function(a,b){b||(b=2);return("000"+a).slice(-1*b)};h.console="undefined"!==typeof window&&"undefined"!==typeof window.console&&"undefined"!==typeof window.console.log?console:{log:function(){},error:function(){}};h.Config=h.Config||{};h.initOverloads=function(){h.now?h._now||(h._now=h.now):h._now=function(){return(new Date).getTime()};h.now=function(a){return a?h.present():h._now()};f.toISOString||(f.toISOString=function(){return this.getUTCFullYear()+"-"+d(this.getUTCMonth()+
|
||||||
|
1)+"-"+d(this.getUTCDate())+"T"+d(this.getUTCHours())+":"+d(this.getUTCMinutes())+":"+d(this.getUTCSeconds())+"."+String((this.getUTCMilliseconds()/1E3).toFixed(3)).slice(2,5)+"Z"});void 0===f._toString&&(f._toString=f.toString)};h.initOverloads();h.today=function(){return(new Date).clearTime()};h.present=function(){return new Date};h.compare=function(a,b){if(isNaN(a)||isNaN(b))throw Error(a+" - "+b);if(a instanceof Date&&b instanceof Date)return a<b?-1:a>b?1:0;throw new TypeError(a+" - "+b);};h.equals=
|
||||||
|
function(a,b){return 0===a.compareTo(b)};h.getDayName=function(a){return Date.CultureInfo.dayNames[a]};h.getDayNumberFromName=function(a){var b=Date.CultureInfo.dayNames,e=Date.CultureInfo.abbreviatedDayNames,g=Date.CultureInfo.shortestDayNames;a=a.toLowerCase();for(var m=0;m<b.length;m++)if(b[m].toLowerCase()===a||e[m].toLowerCase()===a||g[m].toLowerCase()===a)return m;return-1};h.getMonthNumberFromName=function(a){var b=Date.CultureInfo.monthNames,e=Date.CultureInfo.abbreviatedMonthNames;a=a.toLowerCase();
|
||||||
|
for(var g=0;g<b.length;g++)if(b[g].toLowerCase()===a||e[g].toLowerCase()===a)return g;return-1};h.getMonthName=function(a){return Date.CultureInfo.monthNames[a]};h.isLeapYear=function(a){return 0===a%4&&0!==a%100||0===a%400};h.getDaysInMonth=function(a,b){!b&&h.validateMonth(a)&&(b=a,a=Date.today().getFullYear());return[31,h.isLeapYear(a)?29:28,31,30,31,30,31,31,30,31,30,31][b]};f.getDaysInMonth=function(){return h.getDaysInMonth(this.getFullYear(),this.getMonth())};h.getTimezoneAbbreviation=function(a,
|
||||||
|
b){var e,g=b?Date.CultureInfo.abbreviatedTimeZoneDST:Date.CultureInfo.abbreviatedTimeZoneStandard;for(e in g)if(g.hasOwnProperty(e)&&g[e]===a)return e;return null};h.getTimezoneOffset=function(a,b){var e,g=[],m=Date.CultureInfo.timezones;a||(a=(new Date).getTimezone());for(e=0;e<m.length;e++)m[e].name===a.toUpperCase()&&g.push(e);if(!m[g[0]])return null;if(1!==g.length&&b)for(e=0;e<g.length;e++){if(m[g[e]].dst)return m[g[e]].offset}else return m[g[0]].offset};h.getQuarter=function(a){a=a||new Date;
|
||||||
|
return[1,2,3,4][Math.floor(a.getMonth()/3)]};h.getDaysLeftInQuarter=function(a){a=a||new Date;var b=new Date(a);b.setMonth(b.getMonth()+3-b.getMonth()%3,0);return Math.floor((b-a)/864E5)};var c=function(a,b,e,g){if("undefined"===typeof a)return!1;if("number"!==typeof a)throw new TypeError(a+" is not a Number.");return a<b||a>e?!1:!0};h.validateMillisecond=function(a){return c(a,0,999,"millisecond")};h.validateSecond=function(a){return c(a,0,59,"second")};h.validateMinute=function(a){return c(a,0,
|
||||||
|
59,"minute")};h.validateHour=function(a){return c(a,0,23,"hour")};h.validateDay=function(a,b,e){return void 0===b||null===b||void 0===e||null===e?!1:c(a,1,h.getDaysInMonth(b,e),"day")};h.validateWeek=function(a){return c(a,0,53,"week")};h.validateMonth=function(a){return c(a,0,11,"month")};h.validateYear=function(a){return c(a,-271822,275760,"year")};h.validateTimezone=function(a){return 1==={ACDT:1,ACST:1,ACT:1,ADT:1,AEDT:1,AEST:1,AFT:1,AKDT:1,AKST:1,AMST:1,AMT:1,ART:1,AST:1,AWDT:1,AWST:1,AZOST:1,
|
||||||
|
AZT:1,BDT:1,BIOT:1,BIT:1,BOT:1,BRT:1,BST:1,BTT:1,CAT:1,CCT:1,CDT:1,CEDT:1,CEST:1,CET:1,CHADT:1,CHAST:1,CHOT:1,ChST:1,CHUT:1,CIST:1,CIT:1,CKT:1,CLST:1,CLT:1,COST:1,COT:1,CST:1,CT:1,CVT:1,CWST:1,CXT:1,DAVT:1,DDUT:1,DFT:1,EASST:1,EAST:1,EAT:1,ECT:1,EDT:1,EEDT:1,EEST:1,EET:1,EGST:1,EGT:1,EIT:1,EST:1,FET:1,FJT:1,FKST:1,FKT:1,FNT:1,GALT:1,GAMT:1,GET:1,GFT:1,GILT:1,GIT:1,GMT:1,GST:1,GYT:1,HADT:1,HAEC:1,HAST:1,HKT:1,HMT:1,HOVT:1,HST:1,ICT:1,IDT:1,IOT:1,IRDT:1,IRKT:1,IRST:1,IST:1,JST:1,KGT:1,KOST:1,KRAT:1,
|
||||||
|
KST:1,LHST:1,LINT:1,MAGT:1,MART:1,MAWT:1,MDT:1,MET:1,MEST:1,MHT:1,MIST:1,MIT:1,MMT:1,MSK:1,MST:1,MUT:1,MVT:1,MYT:1,NCT:1,NDT:1,NFT:1,NPT:1,NST:1,NT:1,NUT:1,NZDT:1,NZST:1,OMST:1,ORAT:1,PDT:1,PET:1,PETT:1,PGT:1,PHOT:1,PHT:1,PKT:1,PMDT:1,PMST:1,PONT:1,PST:1,PYST:1,PYT:1,RET:1,ROTT:1,SAKT:1,SAMT:1,SAST:1,SBT:1,SCT:1,SGT:1,SLST:1,SRT:1,SST:1,SYOT:1,TAHT:1,THA:1,TFT:1,TJT:1,TKT:1,TLT:1,TMT:1,TOT:1,TVT:1,UCT:1,ULAT:1,UTC:1,UYST:1,UYT:1,UZT:1,VET:1,VLAT:1,VOLT:1,VOST:1,VUT:1,WAKT:1,WAST:1,WAT:1,WEDT:1,WEST:1,
|
||||||
|
WET:1,WST:1,YAKT:1,YEKT:1,Z:1}[a]};h.validateTimezoneOffset=function(a){return-841<a&&721>a}})();
|
||||||
|
(function(){var h=Date,f=h.prototype,d=function(a,b){b||(b=2);return("000"+a).slice(-1*b)},c=function(a){var b={},e=this,g,c;c=function(b,g,c){if("day"===b){b=void 0!==a.month?a.month:e.getMonth();var d=void 0!==a.year?a.year:e.getFullYear();return h[g](c,d,b)}return h[g](c)};for(g in a)if(Object.prototype.hasOwnProperty.call(a,g)){var d="validate"+g.charAt(0).toUpperCase()+g.slice(1);h[d]&&null!==a[g]&&c(g,d,a[g])&&(b[g]=a[g])}return b};f.clearTime=function(){this.setHours(0);this.setMinutes(0);
|
||||||
|
this.setSeconds(0);this.setMilliseconds(0);return this};f.setTimeToNow=function(){var a=new Date;this.setHours(a.getHours());this.setMinutes(a.getMinutes());this.setSeconds(a.getSeconds());this.setMilliseconds(a.getMilliseconds());return this};f.clone=function(){return new Date(this.getTime())};f.compareTo=function(a){return Date.compare(this,a)};f.equals=function(a){return Date.equals(this,void 0!==a?a:new Date)};f.between=function(a,b){return this.getTime()>=a.getTime()&&this.getTime()<=b.getTime()};
|
||||||
|
f.isAfter=function(a){return 1===this.compareTo(a||new Date)};f.isBefore=function(a){return-1===this.compareTo(a||new Date)};f.isToday=f.isSameDay=function(a){return this.clone().clearTime().equals((a||new Date).clone().clearTime())};f.addMilliseconds=function(a){if(!a)return this;this.setTime(this.getTime()+1*a);return this};f.addSeconds=function(a){return a?this.addMilliseconds(1E3*a):this};f.addMinutes=function(a){return a?this.addMilliseconds(6E4*a):this};f.addHours=function(a){return a?this.addMilliseconds(36E5*
|
||||||
|
a):this};f.addDays=function(a){if(!a)return this;this.setDate(this.getDate()+1*a);return this};f.addWeekdays=function(a){if(!a)return this;var b=this.getDay(),e=Math.ceil(Math.abs(a)/7);(0===b||6===b)&&0<a&&(this.next().monday(),this.addDays(-1),b=this.getDay());if(0>a){for(;0>a;)this.addDays(-1),b=this.getDay(),0!==b&&6!==b&&a++;return this}if(5<a||6-b<=a)a+=2*e;return this.addDays(a)};f.addWeeks=function(a){return a?this.addDays(7*a):this};f.addMonths=function(a){if(!a)return this;var b=this.getDate();
|
||||||
|
this.setDate(1);this.setMonth(this.getMonth()+1*a);this.setDate(Math.min(b,h.getDaysInMonth(this.getFullYear(),this.getMonth())));return this};f.addQuarters=function(a){return a?this.addMonths(3*a):this};f.addYears=function(a){return a?this.addMonths(12*a):this};f.add=function(a){if("number"===typeof a)return this._orient=a,this;a.day&&0!==a.day-this.getDate()&&this.setDate(a.day);a.milliseconds&&this.addMilliseconds(a.milliseconds);a.seconds&&this.addSeconds(a.seconds);a.minutes&&this.addMinutes(a.minutes);
|
||||||
|
a.hours&&this.addHours(a.hours);a.weeks&&this.addWeeks(a.weeks);a.months&&this.addMonths(a.months);a.years&&this.addYears(a.years);a.days&&this.addDays(a.days);return this};f.getWeek=function(a){var b=new Date(this.valueOf());a?(b.addMinutes(b.getTimezoneOffset()),a=b.clone()):a=this;a=(a.getDay()+6)%7;b.setDate(b.getDate()-a+3);a=b.valueOf();b.setMonth(0,1);4!==b.getDay()&&b.setMonth(0,1+(4-b.getDay()+7)%7);return 1+Math.ceil((a-b)/6048E5)};f.getISOWeek=function(){return d(this.getWeek(!0))};f.setWeek=
|
||||||
|
function(a){return 0===a-this.getWeek()?1!==this.getDay()?this.moveToDayOfWeek(1,1<this.getDay()?-1:1):this:this.moveToDayOfWeek(1,1<this.getDay()?-1:1).addWeeks(a-this.getWeek())};f.setQuarter=function(a){a=Math.abs(3*(a-1)+1);return this.setMonth(a,1)};f.getQuarter=function(){return Date.getQuarter(this)};f.getDaysLeftInQuarter=function(){return Date.getDaysLeftInQuarter(this)};f.moveToNthOccurrence=function(a,b){if("Weekday"===a){if(0<b)this.moveToFirstDayOfMonth(),this.is().weekday()&&--b;else if(0>
|
||||||
|
b)this.moveToLastDayOfMonth(),this.is().weekday()&&(b+=1);else return this;return this.addWeekdays(b)}var e=0;if(0<b)e=b-1;else if(-1===b)return this.moveToLastDayOfMonth(),this.getDay()!==a&&this.moveToDayOfWeek(a,-1),this;return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(a,1).addWeeks(e)};var a=function(a,b,e){return function(g,c){var d=(g-this[a]()+e*(c||1))%e;return this[b](0===d?d+e*(c||1):d)}};f.moveToDayOfWeek=a("getDay","addDays",7);f.moveToMonth=a("getMonth","addMonths",12);
|
||||||
|
f.getOrdinate=function(){var a=this.getDate();return b(a)};f.getOrdinalNumber=function(){return Math.ceil((this.clone().clearTime()-new Date(this.getFullYear(),0,1))/864E5)+1};f.getTimezone=function(){return h.getTimezoneAbbreviation(this.getUTCOffset(),this.isDaylightSavingTime())};f.setTimezoneOffset=function(a){var b=this.getTimezoneOffset();return(a=-6*Number(a)/10)||0===a?this.addMinutes(a-b):this};f.setTimezone=function(a){return this.setTimezoneOffset(h.getTimezoneOffset(a))};f.hasDaylightSavingTime=
|
||||||
|
function(){return Date.today().set({month:0,day:1}).getTimezoneOffset()!==Date.today().set({month:6,day:1}).getTimezoneOffset()};f.isDaylightSavingTime=function(){return Date.today().set({month:0,day:1}).getTimezoneOffset()!==this.getTimezoneOffset()};f.getUTCOffset=function(a){a=-10*(a||this.getTimezoneOffset())/6;if(0>a)return a=(a-1E4).toString(),a.charAt(0)+a.substr(2);a=(a+1E4).toString();return"+"+a.substr(1)};f.getElapsed=function(a){return(a||new Date)-this};f.set=function(a){a=c.call(this,
|
||||||
|
a);for(var b in a)if(Object.prototype.hasOwnProperty.call(a,b)){var e=b.charAt(0).toUpperCase()+b.slice(1),g,d;"week"!==b&&"month"!==b&&"timezone"!==b&&"timezoneOffset"!==b&&(e+="s");g="add"+e;d="get"+e;"month"===b?g+="s":"year"===b&&(d="getFullYear");if("day"!==b&&"timezone"!==b&&"timezoneOffset"!==b&&"week"!==b&&"hour"!==b)this[g](a[b]-this[d]());else if("timezone"===b||"timezoneOffset"===b||"week"===b||"hour"===b)this["set"+e](a[b])}a.day&&this.addDays(a.day-this.getDate());return this};f.moveToFirstDayOfMonth=
|
||||||
|
function(){return this.set({day:1})};f.moveToLastDayOfMonth=function(){return this.set({day:h.getDaysInMonth(this.getFullYear(),this.getMonth())})};var b=function(a){switch(1*a){case 1:case 21:case 31:return"st";case 2:case 22:return"nd";case 3:case 23:return"rd";default:return"th"}},e=function(a){var b=Date.CultureInfo.formatPatterns;switch(a){case "d":return this.toString(b.shortDate);case "D":return this.toString(b.longDate);case "F":return this.toString(b.fullDateTime);case "m":return this.toString(b.monthDay);
|
||||||
|
case "r":case "R":return a=this.clone().addMinutes(this.getTimezoneOffset()),a.toString(b.rfc1123)+" GMT";case "s":return this.toString(b.sortableDateTime);case "t":return this.toString(b.shortTime);case "T":return this.toString(b.longTime);case "u":return a=this.clone().addMinutes(this.getTimezoneOffset()),a.toString(b.universalSortableDateTime);case "y":return this.toString(b.yearMonth);default:return!1}},g=function(a){return function(e){if("\\"===e.charAt(0))return e.replace("\\","");switch(e){case "hh":return d(13>
|
||||||
|
a.getHours()?0===a.getHours()?12:a.getHours():a.getHours()-12);case "h":return 13>a.getHours()?0===a.getHours()?12:a.getHours():a.getHours()-12;case "HH":return d(a.getHours());case "H":return a.getHours();case "mm":return d(a.getMinutes());case "m":return a.getMinutes();case "ss":return d(a.getSeconds());case "s":return a.getSeconds();case "yyyy":return d(a.getFullYear(),4);case "yy":return d(a.getFullYear());case "y":return a.getFullYear();case "E":case "dddd":return Date.CultureInfo.dayNames[a.getDay()];
|
||||||
|
case "ddd":return Date.CultureInfo.abbreviatedDayNames[a.getDay()];case "dd":return d(a.getDate());case "d":return a.getDate();case "MMMM":return Date.CultureInfo.monthNames[a.getMonth()];case "MMM":return Date.CultureInfo.abbreviatedMonthNames[a.getMonth()];case "MM":return d(a.getMonth()+1);case "M":return a.getMonth()+1;case "t":return 12>a.getHours()?Date.CultureInfo.amDesignator.substring(0,1):Date.CultureInfo.pmDesignator.substring(0,1);case "tt":return 12>a.getHours()?Date.CultureInfo.amDesignator:
|
||||||
|
Date.CultureInfo.pmDesignator;case "S":return b(a.getDate());case "W":return a.getWeek();case "WW":return a.getISOWeek();case "Q":return"Q"+a.getQuarter();case "q":return String(a.getQuarter());case "z":return a.getTimezone();case "Z":case "X":return Date.getTimezoneOffset(a.getTimezone());case "ZZ":return-60*a.getTimezoneOffset();case "u":return a.getDay();case "L":return h.isLeapYear(a.getFullYear())?1:0;case "B":return"@"+(a.getUTCSeconds()+60*a.getUTCMinutes()+3600*(a.getUTCHours()+1))/86.4;default:return e}}};
|
||||||
|
f.toString=function(a,b){if(!b&&a&&1===a.length&&(output=e.call(this,a)))return output;var c=g(this);return a?a.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g,c).replace(/\[|\]/g,""):this._toString()}})();
|
||||||
|
(function(){var h=Date,f=h.prototype,d=Number.prototype;f._orient=1;f._nth=null;f._is=!1;f._same=!1;f._isSecond=!1;d._dateElement="days";f.next=function(){this._move=!0;this._orient=1;return this};h.next=function(){return h.today().next()};f.last=f.prev=f.previous=function(){this._move=!0;this._orient=-1;return this};h.last=h.prev=h.previous=function(){return h.today().last()};f.is=function(){this._is=!0;return this};f.same=function(){this._same=!0;this._isSecond=!1;return this};f.today=function(){return this.same().day()};
|
||||||
|
f.weekday=function(){return this._nth?m("Weekday").call(this):this._move?this.addWeekdays(this._orient):this._is?(this._is=!1,!this.is().sat()&&!this.is().sun()):!1};f.weekend=function(){return this._is?(this._is=!1,this.is().sat()||this.is().sun()):!1};f.at=function(a){return"string"===typeof a?h.parse(this.toString("d")+" "+a):this.set(a)};d.fromNow=d.after=function(a){var b={};b[this._dateElement]=this;return(a?a.clone():new Date).add(b)};d.ago=d.before=function(a){var b={};b["s"!==this._dateElement[this._dateElement.length-
|
||||||
|
1]?this._dateElement+"s":this._dateElement]=-1*this;return(a?a.clone():new Date).add(b)};var c="sunday monday tuesday wednesday thursday friday saturday".split(/\s/),a="january february march april may june july august september october november december".split(/\s/),b="Millisecond Second Minute Hour Day Week Month Year Quarter Weekday".split(/\s/),e="Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter".split(/\s/),g="final first second third fourth fifth".split(/\s/);f.toObject=function(){for(var a=
|
||||||
|
{},g=0;g<b.length;g++)this["get"+e[g]]&&(a[b[g].toLowerCase()]=this["get"+e[g]]());return a};h.fromObject=function(a){a.week=null;return Date.today().set(a)};var m=function(a){return function(){if(this._is)return this._is=!1,this.getDay()===a;this._move&&(this._move=null);if(null!==this._nth){this._isSecond&&this.addSeconds(-1*this._orient);this._isSecond=!1;var b=this._nth;this._nth=null;var e=this.clone().moveToLastDayOfMonth();this.moveToNthOccurrence(a,b);if(this>e)throw new RangeError(h.getDayName(a)+
|
||||||
|
" does not occur "+b+" times in the month of "+h.getMonthName(e.getMonth())+" "+e.getFullYear()+".");return this}return this.moveToDayOfWeek(a,this._orient)}},k=function(a,b,e){for(var g=0;g<a.length;g++)h[a[g].toUpperCase()]=h[a[g].toUpperCase().substring(0,3)]=g,h[a[g]]=h[a[g].substring(0,3)]=b(g),f[a[g]]=f[a[g].substring(0,3)]=e(g)};k(c,function(a){return function(){var b=h.today(),e=a-b.getDay();0===a&&1===Date.CultureInfo.firstDayOfWeek&&0!==b.getDay()&&(e+=7);return b.addDays(e)}},m);k(a,function(a){return function(){return h.today().set({month:a,
|
||||||
|
day:1})}},function(a){return function(){return this._is?(this._is=!1,this.getMonth()===a):this.moveToMonth(a,this._orient)}});for(var a=function(a){return function(e){if(this._isSecond)return this._isSecond=!1,this;if(this._same){this._same=this._is=!1;var g=this.toObject();e=(e||new Date).toObject();for(var c="",d=a.toLowerCase(),d="s"===d[d.length-1]?d.substring(0,d.length-1):d,f=b.length-1;-1<f;f--){c=b[f].toLowerCase();if(g[c]!==e[c])return!1;if(d===c)break}return!0}"s"!==a.substring(a.length-
|
||||||
|
1)&&(a+="s");this._move&&(this._move=null);return this["add"+a](this._orient)}},k=function(a){return function(){this._dateElement=a;return this}},n=0;n<b.length;n++)c=b[n].toLowerCase(),"weekday"!==c&&(f[c]=f[c+"s"]=a(b[n]),d[c]=d[c+"s"]=k(c+"s"));f._ss=a("Second");d=function(a){return function(b){if(this._same)return this._ss(b);if(b||0===b)return this.moveToNthOccurrence(b,a);this._nth=a;return 2!==a||void 0!==b&&null!==b?this:(this._isSecond=!0,this.addSeconds(this._orient))}};for(c=0;c<g.length;c++)f[g[c]]=
|
||||||
|
0===c?d(-1):d(c)})();
|
||||||
|
(function(){Date.Parsing={Exception:function(a){this.message="Parse error at '"+a.substring(0,10)+" ...'"}};var h=Date.Parsing,f=[0,31,59,90,120,151,181,212,243,273,304,334],d=[0,31,60,91,121,152,182,213,244,274,305,335];h.isLeapYear=function(a){return 0===a%4&&0!==a%100||0===a%400};var c={multiReplace:function(a,b){for(var e in b)if(Object.prototype.hasOwnProperty.call(b,e)){var g;"function"!==typeof b[e]&&(g=b[e]instanceof RegExp?b[e]:new RegExp(b[e],"g"));a=a.replace(g,e)}return a},getDayOfYearFromWeek:function(a){var b;
|
||||||
|
a.weekDay=a.weekDay||0===a.weekDay?a.weekDay:1;b=new Date(a.year,0,4);b=(0===b.getDay()?7:b.getDay())+3;a.dayOfYear=7*a.week+(0===a.weekDay?7:a.weekDay)-b;return a},getDayOfYear:function(a,b){a.dayOfYear||(a=c.getDayOfYearFromWeek(a));for(var e=0;e<=b.length;e++)if(a.dayOfYear<b[e]||e===b.length){a.day=a.day?a.day:a.dayOfYear-b[e-1];break}else a.month=e;return a},adjustForTimeZone:function(a,b){var e;"Z"===a.zone.toUpperCase()||0===a.zone_hours&&0===a.zone_minutes?e=-b.getTimezoneOffset():(e=60*a.zone_hours+
|
||||||
|
(a.zone_minutes||0),"+"===a.zone_sign&&(e*=-1),e-=b.getTimezoneOffset());b.setMinutes(b.getMinutes()+e);return b},setDefaults:function(a){a.year=a.year||Date.today().getFullYear();a.hours=a.hours||0;a.minutes=a.minutes||0;a.seconds=a.seconds||0;a.milliseconds=a.milliseconds||0;if(a.month||!a.week&&!a.dayOfYear)a.month=a.month||0,a.day=a.day||1;return a},dataNum:function(a,b,e,g){var c=1*a;return b?g?a?1*b(a):a:a?b(c):a:e?a&&"undefined"!==typeof a?c:a:a?c:a},timeDataProcess:function(a){var b={},e;
|
||||||
|
for(e in a.data)a.data.hasOwnProperty(e)&&(b[e]=a.ignore[e]?a.data[e]:c.dataNum(a.data[e],a.mods[e],a.explict[e],a.postProcess[e]));a.data.secmins&&(a.data.secmins=60*a.data.secmins.replace(",","."),b.minutes?b.seconds||(b.seconds=a.data.secmins):b.minutes=a.data.secmins,delete a.secmins);return b},buildTimeObjectFromData:function(a){return c.timeDataProcess({data:{year:a[1],month:a[5],day:a[7],week:a[8],dayOfYear:a[10],hours:a[15],zone_hours:a[23],zone_minutes:a[24],zone:a[21],zone_sign:a[22],weekDay:a[9],
|
||||||
|
minutes:a[16],seconds:a[19],milliseconds:a[20],secmins:a[18]},mods:{month:function(a){return a-1},weekDay:function(a){a=Math.abs(a);return 7===a?0:a},minutes:function(a){return a.replace(":","")},seconds:function(a){return Math.floor(1*a.replace(":","").replace(",","."))},milliseconds:function(a){return 1E3*a.replace(",",".")}},postProcess:{minutes:!0,seconds:!0,milliseconds:!0},explict:{zone_hours:!0,zone_minutes:!0},ignore:{zone:!0,zone_sign:!0,secmins:!0}})},addToHash:function(a,b,e){for(var g=
|
||||||
|
b.length,c=0;c<g;c++)a[b[c]]=e[c];return a},combineRegex:function(a,b){return new RegExp("(("+a.source+")\\s("+b.source+"))")},getDateNthString:function(a,b,e){if(a)return Date.today().addDays(e).toString("d");if(b)return Date.today().last()[e]().toString("d")},buildRegexData:function(a){for(var b=[],e=a.length,g=0;g<e;g++)"[object Array]"===Object.prototype.toString.call(a[g])?b.push(this.combineRegex(a[g][0],a[g][1])):b.push(a[g]);return b}};h.processTimeObject=function(a){var b;c.setDefaults(a);
|
||||||
|
b=h.isLeapYear(a.year)?d:f;a.month||!a.week&&!a.dayOfYear?a.dayOfYear=b[a.month]+a.day:c.getDayOfYear(a,b);b=new Date(a.year,a.month,a.day,a.hours,a.minutes,a.seconds,a.milliseconds);a.zone&&c.adjustForTimeZone(a,b);return b};h.ISO={regex:/^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
|
||||||
|
parse:function(a){a=a.match(this.regex);if(!a||!a.length)return null;a=c.buildTimeObjectFromData(a);return a.year&&(a.year||a.month||a.day||a.week||a.dayOfYear)?h.processTimeObject(a):null}};h.Numeric={isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},regex:/\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,parse:function(a){var b,e={},g=Date.CultureInfo.dateElementOrder.split("");if(!this.isNumeric(a)||"+"===a[0]&&"-"===a[0])return null;if(5>a.length&&0>a.indexOf(".")&&0>a.indexOf("/"))return e.year=
|
||||||
|
a,h.processTimeObject(e);a=a.match(this.regex);if(!a||!a.length)return null;for(b=0;b<g.length;b++)switch(g[b]){case "d":e.day=a[b+1];break;case "m":e.month=a[b+1]-1;break;case "y":e.year=a[b+1]}return h.processTimeObject(e)}};h.Normalizer={regexData:function(){var a=Date.CultureInfo.regexPatterns;return c.buildRegexData([a.tomorrow,a.yesterday,[a.past,a.mon],[a.past,a.tue],[a.past,a.wed],[a.past,a.thu],[a.past,a.fri],[a.past,a.sat],[a.past,a.sun]])},basicReplaceHash:function(){var a=Date.CultureInfo.regexPatterns;
|
||||||
|
return{January:a.jan.source,February:a.feb,March:a.mar,April:a.apr,May:a.may,June:a.jun,July:a.jul,August:a.aug,September:a.sep,October:a.oct,November:a.nov,December:a.dec,"":/\bat\b/gi," ":/\s{2,}/,am:a.inTheMorning,"9am":a.thisMorning,pm:a.inTheEvening,"7pm":a.thisEvening}},keys:function(){return[c.getDateNthString(!0,!1,1),c.getDateNthString(!0,!1,-1),c.getDateNthString(!1,!0,"monday"),c.getDateNthString(!1,!0,"tuesday"),c.getDateNthString(!1,!0,"wednesday"),c.getDateNthString(!1,!0,"thursday"),
|
||||||
|
c.getDateNthString(!1,!0,"friday"),c.getDateNthString(!1,!0,"saturday"),c.getDateNthString(!1,!0,"sunday")]},buildRegexFunctions:function(){var a=Date.CultureInfo.regexPatterns,b=Date.i18n.__,b=new RegExp("(\\b\\d\\d?("+b("AM")+"|"+b("PM")+")? )("+a.tomorrow.source.slice(1)+")","i");this.replaceFuncs=[[new RegExp(a.today.source+"(?!\\s*([+-]))\\b"),function(a){return 1<a.length?Date.today().toString("d"):a}],[b,function(a,b){return Date.today().addDays(1).toString("d")+" "+b}],[a.amThisMorning,function(a,
|
||||||
|
b){return b}],[a.pmThisEvening,function(a,b){return b}]]},buildReplaceData:function(){this.buildRegexFunctions();this.replaceHash=c.addToHash(this.basicReplaceHash(),this.keys(),this.regexData())},stringReplaceFuncs:function(a){for(var b=0;b<this.replaceFuncs.length;b++)a=a.replace(this.replaceFuncs[b][0],this.replaceFuncs[b][1]);return a},parse:function(a){a=this.stringReplaceFuncs(a);a=c.multiReplace(a,this.replaceHash);try{var b=a.split(/([\s\-\.\,\/\x27]+)/);3===b.length&&h.Numeric.isNumeric(b[0])&&
|
||||||
|
h.Numeric.isNumeric(b[2])&&4<=b[2].length&&"d"===Date.CultureInfo.dateElementOrder[0]&&(a="1/"+b[0]+"/"+b[2])}catch(e){}return a}};h.Normalizer.buildReplaceData()})();
|
||||||
|
(function(){for(var h=Date.Parsing,f=h.Operators={rtoken:function(a){return function(e){var g=e.match(a);if(g)return[g[0],e.substring(g[0].length)];throw new h.Exception(e);}},token:function(){return function(a){return f.rtoken(new RegExp("^\\s*"+a+"\\s*"))(a)}},stoken:function(a){return f.rtoken(new RegExp("^"+a))},until:function(a){return function(e){for(var g=[],c=null;e.length;){try{c=a.call(this,e)}catch(d){g.push(c[0]);e=c[1];continue}break}return[g,e]}},many:function(a){return function(e){for(var g=
|
||||||
|
[],c=null;e.length;){try{c=a.call(this,e)}catch(d){break}g.push(c[0]);e=c[1]}return[g,e]}},optional:function(a){return function(e){var g=null;try{g=a.call(this,e)}catch(c){return[null,e]}return[g[0],g[1]]}},not:function(a){return function(e){try{a.call(this,e)}catch(g){return[null,e]}throw new h.Exception(e);}},ignore:function(a){return a?function(e){var g=null,g=a.call(this,e);return[null,g[1]]}:null},product:function(){for(var a=arguments[0],e=Array.prototype.slice.call(arguments,1),g=[],c=0;c<
|
||||||
|
a.length;c++)g.push(f.each(a[c],e));return g},cache:function(a){var e={},g=0,c=[],d=Date.Config.CACHE_MAX||1E5,f=null;return function(l){if(g===d)for(var p=0;10>p;p++){var q=c.shift();q&&(delete e[q],g--)}try{f=e[l]=e[l]||a.call(this,l)}catch(s){f=e[l]=s}g++;c.push(l);if(f instanceof h.Exception)throw f;return f}},any:function(){var a=arguments;return function(e){for(var g=null,c=0;c<a.length;c++)if(null!=a[c]){try{g=a[c].call(this,e)}catch(d){g=null}if(g)return g}throw new h.Exception(e);}},each:function(){var a=
|
||||||
|
arguments;return function(e){for(var c=[],d=null,f=0;f<a.length;f++)if(null!=a[f]){try{d=a[f].call(this,e)}catch(n){throw new h.Exception(e);}c.push(d[0]);e=d[1]}return[c,e]}},all:function(){var a=a;return a.each(a.optional(arguments))},sequence:function(a,e,c){e=e||f.rtoken(/^\s*/);c=c||null;return 1===a.length?a[0]:function(d){for(var f=null,n=null,l=[],p=0;p<a.length;p++){try{f=a[p].call(this,d)}catch(q){break}l.push(f[0]);try{n=e.call(this,f[1])}catch(s){n=null;break}d=n[1]}if(!f)throw new h.Exception(d);
|
||||||
|
if(n)throw new h.Exception(n[1]);if(c)try{f=c.call(this,f[1])}catch(u){throw new h.Exception(f[1]);}return[l,f?f[1]:d]}},between:function(a,e,c){c=c||a;var d=f.each(f.ignore(a),e,f.ignore(c));return function(a){a=d.call(this,a);return[[a[0][0],r[0][2]],a[1]]}},list:function(a,e,c){e=e||f.rtoken(/^\s*/);c=c||null;return a instanceof Array?f.each(f.product(a.slice(0,-1),f.ignore(e)),a.slice(-1),f.ignore(c)):f.each(f.many(f.each(a,f.ignore(e))),px,f.ignore(c))},set:function(a,e,c){e=e||f.rtoken(/^\s*/);
|
||||||
|
c=c||null;return function(d){for(var k=null,n=k=null,l=null,p=[[],d],q=!1,s=0;s<a.length;s++){k=n=null;q=1===a.length;try{k=a[s].call(this,d)}catch(u){continue}l=[[k[0]],k[1]];if(0<k[1].length&&!q)try{n=e.call(this,k[1])}catch(v){q=!0}else q=!0;q||0!==n[1].length||(q=!0);if(!q){k=[];for(q=0;q<a.length;q++)s!==q&&k.push(a[q]);k=f.set(k,e).call(this,n[1]);0<k[0].length&&(l[0]=l[0].concat(k[0]),l[1]=k[1])}l[1].length<p[1].length&&(p=l);if(0===p[1].length)break}if(0===p[0].length)return p;if(c){try{n=
|
||||||
|
c.call(this,p[1])}catch(w){throw new h.Exception(p[1]);}p[1]=n[1]}return p}},forward:function(a,e){return function(c){return a[e].call(this,c)}},replace:function(a,e){return function(c){c=a.call(this,c);return[e,c[1]]}},process:function(a,e){return function(c){c=a.call(this,c);return[e.call(this,c[0]),c[1]]}},min:function(a,e){return function(c){var d=e.call(this,c);if(d[0].length<a)throw new h.Exception(c);return d}}},d=function(a){return function(){var e=null,c=[],d;1<arguments.length?e=Array.prototype.slice.call(arguments):
|
||||||
|
arguments[0]instanceof Array&&(e=arguments[0]);if(e){if(d=e.shift(),0<d.length)return e.unshift(d[void 0]),c.push(a.apply(null,e)),e.shift(),c}else return a.apply(null,arguments)}},c="optional not ignore cache".split(/\s/),a=0;a<c.length;a++)f[c[a]]=d(f[c[a]]);d=function(a){return function(){return arguments[0]instanceof Array?a.apply(null,arguments[0]):a.apply(null,arguments)}};c="each any all".split(/\s/);for(a=0;a<c.length;a++)f[c[a]]=d(f[c[a]])})();
|
||||||
|
(function(){var h=Date,f=function(c){for(var a=[],b=0;b<c.length;b++)c[b]instanceof Array?a=a.concat(f(c[b])):c[b]&&a.push(c[b]);return a},d=function(){if(this.meridian&&(this.hour||0===this.hour)){if("a"===this.meridian&&11<this.hour&&Date.Config.strict24hr)throw"Invalid hour and meridian combination";if("p"===this.meridian&&12>this.hour&&Date.Config.strict24hr)throw"Invalid hour and meridian combination";"p"===this.meridian&&12>this.hour?this.hour+=12:"a"===this.meridian&&12===this.hour&&(this.hour=
|
||||||
|
0)}};h.Translator={hour:function(c){return function(){this.hour=Number(c)}},minute:function(c){return function(){this.minute=Number(c)}},second:function(c){return function(){this.second=Number(c)}},secondAndMillisecond:function(c){return function(){var a=c.match(/^([0-5][0-9])\.([0-9]{1,3})/);this.second=Number(a[1]);this.millisecond=Number(a[2])}},meridian:function(c){return function(){this.meridian=c.slice(0,1).toLowerCase()}},timezone:function(c){return function(){var a=c.replace(/[^\d\+\-]/g,
|
||||||
|
"");a.length?this.timezoneOffset=Number(a):this.timezone=c.toLowerCase()}},day:function(c){var a=c[0];return function(){this.day=Number(a.match(/\d+/)[0]);if(1>this.day)throw"invalid day";}},month:function(c){return function(){this.month=3===c.length?"jan feb mar apr may jun jul aug sep oct nov dec".indexOf(c)/4:Number(c)-1;if(0>this.month)throw"invalid month";}},year:function(c){return function(){var a=Number(c);this.year=2<c.length?a:a+(a+2E3<Date.CultureInfo.twoDigitYearMax?2E3:1900)}},rday:function(c){return function(){switch(c){case "yesterday":this.days=
|
||||||
|
-1;break;case "tomorrow":this.days=1;break;case "today":this.days=0;break;case "now":this.days=0,this.now=!0}}},finishExact:function(c){c=c instanceof Array?c:[c];for(var a=0;a<c.length;a++)c[a]&&c[a].call(this);c=new Date;!this.hour&&!this.minute||this.month||this.year||this.day||(this.day=c.getDate());this.year||(this.year=c.getFullYear());this.month||0===this.month||(this.month=c.getMonth());this.day||(this.day=1);this.hour||(this.hour=0);this.minute||(this.minute=0);this.second||(this.second=
|
||||||
|
0);this.millisecond||(this.millisecond=0);d.call(this);if(this.day>h.getDaysInMonth(this.year,this.month))throw new RangeError(this.day+" is not a valid value for days.");c=new Date(this.year,this.month,this.day,this.hour,this.minute,this.second,this.millisecond);100>this.year&&c.setFullYear(this.year);this.timezone?c.set({timezone:this.timezone}):this.timezoneOffset&&c.set({timezoneOffset:this.timezoneOffset});return c},finish:function(c){var a,b,e;c=c instanceof Array?f(c):[c];if(0===c.length)return null;
|
||||||
|
for(a=0;a<c.length;a++)"function"===typeof c[a]&&c[a].call(this);if(!this.now||this.unit||this.operator)c=this.now||-1!=="hour minute second".indexOf(this.unit)?new Date:h.today();else return new Date;a=!!(this.days&&null!==this.days||this.orient||this.operator);b="past"===this.orient||"subtract"===this.operator?-1:1;this.month&&"week"===this.unit&&(this.value=this.month+1,delete this.month,delete this.day);!this.month&&0!==this.month||-1==="year day hour minute second".indexOf(this.unit)||(this.value||
|
||||||
|
(this.value=this.month+1),this.month=null,a=!0);a||!this.weekday||this.day||this.days||(e=Date[this.weekday](),this.day=e.getDate(),this.month||(this.month=e.getMonth()),this.year=e.getFullYear());if(a&&this.weekday&&"month"!==this.unit&&"week"!==this.unit){var g=c;e=b||1;this.unit="day";this.days=(g=h.getDayNumberFromName(this.weekday)-g.getDay())?(g+7*e)%7:7*e}!this.weekday||"week"===this.unit||this.day||this.days||(e=Date[this.weekday](),this.day=e.getDate(),e.getMonth()!==c.getMonth()&&(this.month=
|
||||||
|
e.getMonth()));this.month&&"day"===this.unit&&this.operator&&(this.value||(this.value=this.month+1),this.month=null);null!=this.value&&null!=this.month&&null!=this.year&&(this.day=1*this.value);this.month&&!this.day&&this.value&&(c.set({day:1*this.value}),a||(this.day=1*this.value));this.month||!this.value||"month"!==this.unit||this.now||(this.month=this.value,a=!0);a&&(this.month||0===this.month)&&"year"!==this.unit&&(e=b||1,this.unit="month",this.months=(g=this.month-c.getMonth())?(g+12*e)%12:12*
|
||||||
|
e,this.month=null);this.unit||(this.unit="day");if(!this.value&&this.operator&&null!==this.operator&&this[this.unit+"s"]&&null!==this[this.unit+"s"])this[this.unit+"s"]=this[this.unit+"s"]+("add"===this.operator?1:-1)+(this.value||0)*b;else if(null==this[this.unit+"s"]||null!=this.operator)this.value||(this.value=1),this[this.unit+"s"]=this.value*b;d.call(this);!this.month&&0!==this.month||this.day||(this.day=1);if(!this.orient&&!this.operator&&"week"===this.unit&&this.value&&!this.day&&!this.month)return Date.today().setWeek(this.value);
|
||||||
|
if("week"===this.unit&&this.weeks&&!this.day&&!this.month)return c=Date[void 0!==this.weekday?this.weekday:"today"]().addWeeks(this.weeks),this.now&&c.setTimeToNow(),c;a&&this.timezone&&this.day&&this.days&&(this.day=this.days);a?c.add(this):c.set(this);this.timezone&&(this.timezone=this.timezone.toUpperCase(),a=h.getTimezoneOffset(this.timezone),c.hasDaylightSavingTime()&&(b=h.getTimezoneAbbreviation(a,c.isDaylightSavingTime()),b!==this.timezone&&(c.isDaylightSavingTime()?c.addHours(-1):c.addHours(1))),
|
||||||
|
c.setTimezoneOffset(a));return c}}})();
|
||||||
|
(function(){var h=Date;h.Grammar={};var f=h.Parsing.Operators,d=h.Grammar,c=h.Translator,a;a=function(){return f.each(f.any.apply(null,arguments),f.not(d.ctoken2("timeContext")))};d.datePartDelimiter=f.rtoken(/^([\s\-\.\,\/\x27]+)/);d.timePartDelimiter=f.stoken(":");d.whiteSpace=f.rtoken(/^\s*/);d.generalDelimiter=f.rtoken(/^(([\s\,]|at|@|on)+)/);var b={};d.ctoken=function(a){var c=b[a];if(!c){for(var c=Date.CultureInfo.regexPatterns,e=a.split(/\s+/),d=[],g=0;g<e.length;g++)d.push(f.replace(f.rtoken(c[e[g]]),
|
||||||
|
e[g]));c=b[a]=f.any.apply(null,d)}return c};d.ctoken2=function(a){return f.rtoken(Date.CultureInfo.regexPatterns[a])};var e=function(a,b,c,e){d[a]=e?f.cache(f.process(f.each(f.rtoken(b),f.optional(d.ctoken2(e))),c)):f.cache(f.process(f.rtoken(b),c))},g=function(a,b){return f.cache(f.process(d.ctoken2(a),b))},m={},k=function(a){m[a]=m[a]||d.format(a)[0];return m[a]};d.allformats=function(a){var b=[];if(a instanceof Array)for(var c=0;c<a.length;c++)b.push(k(a[c]));else b.push(k(a));return b};d.formats=
|
||||||
|
function(a){if(a instanceof Array){for(var b=[],c=0;c<a.length;c++)b.push(k(a[c]));return f.any.apply(null,b)}return k(a)};var n={timeFormats:function(){var a,b="h hh H HH m mm s ss ss.s z zz".split(" "),h=[/^(0[0-9]|1[0-2]|[1-9])/,/^(0[0-9]|1[0-2])/,/^([0-1][0-9]|2[0-3]|[0-9])/,/^([0-1][0-9]|2[0-3])/,/^([0-5][0-9]|[0-9])/,/^[0-5][0-9]/,/^([0-5][0-9]|[0-9])/,/^[0-5][0-9]/,/^[0-5][0-9]\.[0-9]{1,3}/,/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/],m=[c.hour,
|
||||||
|
c.hour,c.hour,c.hour,c.minute,c.minute,c.second,c.second,c.secondAndMillisecond,c.timezone,c.timezone];for(a=0;a<b.length;a++)e(b[a],h[a],m[a]);d.hms=f.cache(f.sequence([d.H,d.m,d.s],d.timePartDelimiter));d.t=g("shortMeridian",c.meridian);d.tt=g("longMeridian",c.meridian);d.zzz=g("timezone",c.timezone);d.timeSuffix=f.each(f.ignore(d.whiteSpace),f.set([d.tt,d.zzz]));d.time=f.each(f.optional(f.ignore(f.stoken("T"))),d.hms,d.timeSuffix)},dateFormats:function(){var b=function(){return f.set(arguments,
|
||||||
|
d.datePartDelimiter)},g,h="d dd M MM y yy yyy yyyy".split(" "),m=[/^([0-2]\d|3[0-1]|\d)/,/^([0-2]\d|3[0-1])/,/^(1[0-2]|0\d|\d)/,/^(1[0-2]|0\d)/,/^(\d+)/,/^(\d\d)/,/^(\d\d?\d?\d?)/,/^(\d\d\d\d)/],n=[c.day,c.day,c.month,c.month,c.year,c.year,c.year,c.year],k=["ordinalSuffix","ordinalSuffix"];for(g=0;g<h.length;g++)e(h[g],m[g],n[g],k[g]);d.MMM=d.MMMM=f.cache(f.process(d.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"),c.month));d.ddd=d.dddd=f.cache(f.process(d.ctoken("sun mon tue wed thu fri sat"),
|
||||||
|
function(a){return function(){this.weekday=a}}));d.day=a(d.d,d.dd);d.month=a(d.M,d.MMM);d.year=a(d.yyyy,d.yy);d.mdy=b(d.ddd,d.month,d.day,d.year);d.ymd=b(d.ddd,d.year,d.month,d.day);d.dmy=b(d.ddd,d.day,d.month,d.year);d.date=function(a){return(d[Date.CultureInfo.dateElementOrder]||d.mdy).call(this,a)}},relative:function(){d.orientation=f.process(d.ctoken("past future"),function(a){return function(){this.orient=a}});d.operator=f.process(d.ctoken("add subtract"),function(a){return function(){this.operator=
|
||||||
|
a}});d.rday=f.process(d.ctoken("yesterday tomorrow today now"),c.rday);d.unit=f.process(d.ctoken("second minute hour day week month year"),function(a){return function(){this.unit=a}})}};d.buildGrammarFormats=function(){b={};n.timeFormats();n.dateFormats();n.relative();d.value=f.process(f.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),function(a){return function(){this.value=a.replace(/\D/g,"")}});d.expression=f.set([d.rday,d.operator,d.value,d.unit,d.orientation,d.ddd,d.MMM]);d.format=f.process(f.many(f.any(f.process(f.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
|
||||||
|
function(a){if(d[a])return d[a];throw h.Parsing.Exception(a);}),f.process(f.rtoken(/^[^dMyhHmstz]+/),function(a){return f.ignore(f.stoken(a))}))),function(a){return f.process(f.each.apply(null,a),c.finishExact)});d._start=f.process(f.set([d.date,d.time,d.expression],d.generalDelimiter,d.whiteSpace),c.finish)};d.buildGrammarFormats();d._formats=d.formats('"yyyy-MM-ddTHH:mm:ssZ";yyyy-MM-ddTHH:mm:ss.sz;yyyy-MM-ddTHH:mm:ssZ;yyyy-MM-ddTHH:mm:ssz;yyyy-MM-ddTHH:mm:ss;yyyy-MM-ddTHH:mmZ;yyyy-MM-ddTHH:mmz;yyyy-MM-ddTHH:mm;ddd, MMM dd, yyyy H:mm:ss tt;ddd MMM d yyyy HH:mm:ss zzz;MMddyyyy;ddMMyyyy;Mddyyyy;ddMyyyy;Mdyyyy;dMyyyy;yyyy;Mdyy;dMyy;d'.split(";"));
|
||||||
|
d.start=function(a){try{var b=d._formats.call({},a);if(0===b[1].length)return b}catch(c){}return d._start.call({},a)}})();
|
||||||
|
(function(){var h=Date,f={removeOrds:function(d){return d=(ords=d.match(/\b(\d+)(?:st|nd|rd|th)\b/))&&2===ords.length?d.replace(ords[0],ords[1]):d},grammarParser:function(d){var c=null;try{c=h.Grammar.start.call({},d.replace(/^\s*(\S*(\s+\S+)*)\s*$/,"$1"))}catch(a){return null}return 0===c[1].length?c[0]:null},nativeFallback:function(d){var c;try{return(c=Date._parse(d))||0===c?new Date(c):null}catch(a){return null}}};h._parse||(h._parse=h.parse);h.parse=function(d){var c;if(!d)return null;if(d instanceof
|
||||||
|
Date)return d.clone();4<=d.length&&"0"!==d.charAt(0)&&"+"!==d.charAt(0)&&"-"!==d.charAt(0)&&(c=h.Parsing.ISO.parse(d)||h.Parsing.Numeric.parse(d));if(c instanceof Date&&!isNaN(c.getTime()))return c;d=h.Parsing.Normalizer.parse(f.removeOrds(d));c=f.grammarParser(d);return null!==c?c:f.nativeFallback(d)};Date.getParseFunction=function(d){var c=Date.Grammar.allformats(d);return function(a){for(var b=null,e=0;e<c.length;e++){try{b=c[e].call({},a)}catch(d){continue}if(0===b[1].length)return b[0]}return null}};
|
||||||
|
h.parseExact=function(d,c){return h.getParseFunction(c)(d)}})();
|
||||||
|
(function(){var h=Date,f=h.prototype,d=function(a,b){b||(b=2);return("000"+a).slice(-1*b)},c={d:"dd","%d":"dd",D:"ddd","%a":"ddd",j:"dddd",l:"dddd","%A":"dddd",S:"S",F:"MMMM","%B":"MMMM",m:"MM","%m":"MM",M:"MMM","%b":"MMM","%h":"MMM",n:"M",Y:"yyyy","%Y":"yyyy",y:"yy","%y":"yy",g:"h","%I":"h",G:"H",h:"hh",H:"HH","%H":"HH",i:"mm","%M":"mm",s:"ss","%S":"ss","%r":"hh:mm tt","%R":"H:mm","%T":"H:mm:ss","%X":"t","%x":"d","%e":"d","%D":"MM/dd/yy","%n":"\\n","%t":"\\t",e:"z",T:"z","%z":"z","%Z":"z",Z:"ZZ",
|
||||||
|
N:"u",w:"u","%w":"u",W:"W","%V":"W"},a={substitutes:function(a){return c[a]},interpreted:function(a,b){var c;switch(a){case "%u":return b.getDay()+1;case "z":return b.getOrdinalNumber();case "%j":return d(b.getOrdinalNumber(),3);case "%U":c=b.clone().set({month:0,day:1}).addDays(-1).moveToDayOfWeek(0);var f=b.clone().addDays(1).moveToDayOfWeek(0,-1);return f<c?"00":d((f.getOrdinalNumber()-c.getOrdinalNumber())/7+1);case "%W":return d(b.getWeek());case "t":return h.getDaysInMonth(b.getFullYear(),b.getMonth());
|
||||||
|
case "o":case "%G":return b.setWeek(b.getISOWeek()).toString("yyyy");case "%g":return b._format("%G").slice(-2);case "a":case "%p":return t("tt").toLowerCase();case "A":return t("tt").toUpperCase();case "u":return d(b.getMilliseconds(),3);case "I":return b.isDaylightSavingTime()?1:0;case "O":return b.getUTCOffset();case "P":return c=b.getUTCOffset(),c.substring(0,c.length-2)+":"+c.substring(c.length-2);case "B":return c=new Date,Math.floor((3600*c.getHours()+60*c.getMinutes()+c.getSeconds()+60*(c.getTimezoneOffset()+
|
||||||
|
60))/86.4);case "c":return b.toISOString().replace(/\"/g,"");case "U":return h.strtotime("now");case "%c":return t("d")+" "+t("t");case "%C":return Math.floor(b.getFullYear()/100+1)}},shouldOverrideDefaults:function(a){switch(a){case "%e":return!0;default:return!1}},parse:function(b,c){var d,f=c||new Date;return(d=a.substitutes(b))?d:(d=a.interpreted(b,f))?d:b}};h.normalizeFormat=function(b,c){return b.replace(/(%|\\)?.|%%/g,function(b){return a.parse(b,c)})};h.strftime=function(a,b){return Date.parse(b)._format(a)};
|
||||||
|
h.strtotime=function(a){a=h.parse(a);return Math.round(h.UTC(a.getUTCFullYear(),a.getUTCMonth(),a.getUTCDate(),a.getUTCHours(),a.getUTCMinutes(),a.getUTCSeconds(),a.getUTCMilliseconds())/1E3)};var b=function(b){return function(c){var d=!1;if("\\"===c.charAt(0)||"%%"===c.substring(0,2))return c.replace("\\","").replace("%%","%");d=a.shouldOverrideDefaults(c);if(c=h.normalizeFormat(c,b))return b.toString(c,d)}};f._format=function(a){var c=b(this);return a?a.replace(/(%|\\)?.|%%/g,c):this._toString()};
|
||||||
|
f.format||(f.format=f._format)})();
|
||||||
|
(function(){var h=function(c){return function(){return this[c]}},f=function(c){return function(a){this[c]=a;return this}},d=function(c,a,b,e,f){if(1===arguments.length&&"number"===typeof c){var h=0>c?-1:1,k=Math.abs(c);this.setDays(Math.floor(k/864E5)*h);k%=864E5;this.setHours(Math.floor(k/36E5)*h);k%=36E5;this.setMinutes(Math.floor(k/6E4)*h);k%=6E4;this.setSeconds(Math.floor(k/1E3)*h);this.setMilliseconds(k%1E3*h)}else this.set(c,a,b,e,f);this.getTotalMilliseconds=function(){return 864E5*this.getDays()+
|
||||||
|
36E5*this.getHours()+6E4*this.getMinutes()+1E3*this.getSeconds()};this.compareTo=function(a){var b=new Date(1970,1,1,this.getHours(),this.getMinutes(),this.getSeconds());a=null===a?new Date(1970,1,1,0,0,0):new Date(1970,1,1,a.getHours(),a.getMinutes(),a.getSeconds());return b<a?-1:b>a?1:0};this.equals=function(a){return 0===this.compareTo(a)};this.add=function(a){return null===a?this:this.addSeconds(a.getTotalMilliseconds()/1E3)};this.subtract=function(a){return null===a?this:this.addSeconds(-a.getTotalMilliseconds()/
|
||||||
|
1E3)};this.addDays=function(a){return new d(this.getTotalMilliseconds()+864E5*a)};this.addHours=function(a){return new d(this.getTotalMilliseconds()+36E5*a)};this.addMinutes=function(a){return new d(this.getTotalMilliseconds()+6E4*a)};this.addSeconds=function(a){return new d(this.getTotalMilliseconds()+1E3*a)};this.addMilliseconds=function(a){return new d(this.getTotalMilliseconds()+a)};this.get12HourHour=function(){return 12<this.getHours()?this.getHours()-12:0===this.getHours()?12:this.getHours()};
|
||||||
|
this.getDesignator=function(){return 12>this.getHours()?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator};this.toString=function(a){this._toString=function(){return null!==this.getDays()&&0<this.getDays()?this.getDays()+"."+this.getHours()+":"+this.p(this.getMinutes())+":"+this.p(this.getSeconds()):this.getHours()+":"+this.p(this.getMinutes())+":"+this.p(this.getSeconds())};this.p=function(a){return 2>a.toString().length?"0"+a:a};var b=this;return a?a.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
|
||||||
|
function(a){switch(a){case "d":return b.getDays();case "dd":return b.p(b.getDays());case "H":return b.getHours();case "HH":return b.p(b.getHours());case "h":return b.get12HourHour();case "hh":return b.p(b.get12HourHour());case "m":return b.getMinutes();case "mm":return b.p(b.getMinutes());case "s":return b.getSeconds();case "ss":return b.p(b.getSeconds());case "t":return(12>b.getHours()?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator).substring(0,1);case "tt":return 12>b.getHours()?Date.CultureInfo.amDesignator:
|
||||||
|
Date.CultureInfo.pmDesignator}}):this._toString()};return this};(function(c,a){for(var b=0;b<a.length;b++){var e=a[b],d=e.slice(0,1).toUpperCase()+e.slice(1);c.prototype[e]=0;c.prototype["get"+d]=h(e);c.prototype["set"+d]=f(e)}})(d,"years months days hours minutes seconds milliseconds".split(" ").slice(2));d.prototype.set=function(c,a,b,e,d){this.setDays(c||this.getDays());this.setHours(a||this.getHours());this.setMinutes(b||this.getMinutes());this.setSeconds(e||this.getSeconds());this.setMilliseconds(d||
|
||||||
|
this.getMilliseconds())};Date.prototype.getTimeOfDay=function(){return new d(0,this.getHours(),this.getMinutes(),this.getSeconds(),this.getMilliseconds())};Date.TimeSpan=d;"undefined"!==typeof window&&(window.TimeSpan=d)})();
|
||||||
|
(function(){var h=function(a){return function(){return this[a]}},f=function(a){return function(b){this[a]=b;return this}},d=function(a,b,c,d){function f(){b.addMonths(-a);d.months++;12===d.months&&(d.years++,d.months=0)}if(1===a)for(;b>c;)f();else for(;b<c;)f();d.months--;d.months*=a;d.years*=a},c=function(a,b,c,f,h,k,n){if(7===arguments.length)this.set(a,b,c,f,h,k,n);else if(2===arguments.length&&arguments[0]instanceof Date&&arguments[1]instanceof Date){var l=arguments[0].clone(),p=arguments[1].clone(),
|
||||||
|
q=l>p?1:-1;this.dates={start:arguments[0].clone(),end:arguments[1].clone()};d(q,l,p,this);var s=!1===(l.isDaylightSavingTime()===p.isDaylightSavingTime());s&&1===q?l.addHours(-1):s&&l.addHours(1);l=p-l;0!==l&&(l=new TimeSpan(l),this.set(this.years,this.months,l.getDays(),l.getHours(),l.getMinutes(),l.getSeconds(),l.getMilliseconds()))}return this};(function(a,b){for(var c=0;c<b.length;c++){var d=b[c],m=d.slice(0,1).toUpperCase()+d.slice(1);a.prototype[d]=0;a.prototype["get"+m]=h(d);a.prototype["set"+
|
||||||
|
m]=f(d)}})(c,"years months days hours minutes seconds milliseconds".split(" "));c.prototype.set=function(a,b,c,d,f,h,n){this.setYears(a||this.getYears());this.setMonths(b||this.getMonths());this.setDays(c||this.getDays());this.setHours(d||this.getHours());this.setMinutes(f||this.getMinutes());this.setSeconds(h||this.getSeconds());this.setMilliseconds(n||this.getMilliseconds())};Date.TimePeriod=c;"undefined"!==typeof window&&(window.TimePeriod=c)})();
|
||||||
@@ -55,6 +55,20 @@
|
|||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setEditorKeyboardHandler(mode) {
|
||||||
|
var editor = window.ace_editor;
|
||||||
|
var storage = window.localStorage;
|
||||||
|
storage.setItem('gollum-kbm', mode)
|
||||||
|
if (mode == "default") {
|
||||||
|
editor.setKeyboardHandler();
|
||||||
|
} else if (mode == "vim" || mode == "emacs") {
|
||||||
|
editor.setKeyboardHandler("ace/keyboard/" + mode);
|
||||||
|
} else {
|
||||||
|
editor.setKeyboardHandler();
|
||||||
|
}
|
||||||
|
editor.focus();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* $.GollumEditor
|
* $.GollumEditor
|
||||||
*
|
*
|
||||||
@@ -97,9 +111,22 @@
|
|||||||
});
|
});
|
||||||
$('#gollum-autorecover-msg')[0].hidden = false;
|
$('#gollum-autorecover-msg')[0].hidden = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for user last keybind and ensure ui is correct
|
||||||
|
var storage = window.localStorage;
|
||||||
|
var userDefaultKeybind = storage.getItem('gollum-kbm');
|
||||||
|
if (userDefaultKeybind) {
|
||||||
|
default_keybinding = userDefaultKeybind;
|
||||||
|
}
|
||||||
|
var keybinding = document.getElementById('keybinding')
|
||||||
|
for (var i = 0; i < keybinding.options.length; ++i) {
|
||||||
|
if (keybinding.options[i].text === default_keybinding) {
|
||||||
|
keybinding.options[i].selected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
editor.setTheme("ace/theme/tomorrow");
|
editor.setTheme("ace/theme/tomorrow");
|
||||||
editor.setKeyboardHandler();
|
setEditorKeyboardHandler(default_keybinding);
|
||||||
editor.renderer.setShowGutter(false);
|
editor.renderer.setShowGutter(false);
|
||||||
editor.getSession().setUseWrapMode(true);
|
editor.getSession().setUseWrapMode(true);
|
||||||
editor.getSession().setValue(textarea.val());
|
editor.getSession().setValue(textarea.val());
|
||||||
@@ -151,15 +178,7 @@
|
|||||||
|
|
||||||
$("#keybinding").change(function() {
|
$("#keybinding").change(function() {
|
||||||
var mode = $(this).val();
|
var mode = $(this).val();
|
||||||
var editor = window.ace_editor;
|
setEditorKeyboardHandler(mode)
|
||||||
if (mode == "default") {
|
|
||||||
editor.setKeyboardHandler();
|
|
||||||
} else if (mode == "vim" || mode == "emacs") {
|
|
||||||
editor.setKeyboardHandler("ace/keyboard/" + mode);
|
|
||||||
} else {
|
|
||||||
editor.setKeyboardHandler();
|
|
||||||
}
|
|
||||||
editor.focus();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove any autosaved text when we hit save or cancel
|
// Remove any autosaved text when we hit save or cancel
|
||||||
|
|||||||
@@ -96,6 +96,13 @@ function preparePage () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLocalTime(datetime_string, format) {
|
||||||
|
if (format === undefined) { format = 'Y-m-d %H:%M:%S O'; }
|
||||||
|
|
||||||
|
var date = new Date(datetime_string);
|
||||||
|
return date.format(format);
|
||||||
|
}
|
||||||
|
|
||||||
function flashNotice(type, notice, button_label, button_function, button_type) {
|
function flashNotice(type, notice, button_label, button_function, button_type) {
|
||||||
// accepted types: info, success, warn, error
|
// accepted types: info, success, warn, error
|
||||||
nested_button_html = '';
|
nested_button_html = '';
|
||||||
@@ -155,6 +162,16 @@ $(document).ready(function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set time in local time
|
||||||
|
if (showLocalTime) {
|
||||||
|
$(function() {
|
||||||
|
$('time').each(function() {
|
||||||
|
var datetime = $(this).attr('datetime');
|
||||||
|
var format = $(this).data('format');
|
||||||
|
$(this).html(getLocalTime(datetime, format));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if ($('.minibutton-upload-page').length) {
|
if ($('.minibutton-upload-page').length) {
|
||||||
new ClipboardJS('#ClipboardJSlink');
|
new ClipboardJS('#ClipboardJSlink');
|
||||||
@@ -574,8 +591,9 @@ $(document).ready(function() {
|
|||||||
url: routePath('last_commit_info'),
|
url: routePath('last_commit_info'),
|
||||||
data: {path: $("#page-info-toggle").data('pagepath')},
|
data: {path: $("#page-info-toggle").data('pagepath')},
|
||||||
success: function ( data ) {
|
success: function ( data ) {
|
||||||
|
var date = showLocalTime ? getLocalTime(data.date) : data.date;
|
||||||
$("#last-edit").next(".dotted-spinner").toggleClass('hidden');
|
$("#last-edit").next(".dotted-spinner").toggleClass('hidden');
|
||||||
$("#last-edit-in-progress").html('Last edited by <b>' + data.author + '</b>, ' + data.date);
|
$("#last-edit-in-progress").html('Last edited by <b>' + data.author + '</b>, ' + date);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$("#last-edit").next(".dotted-spinner").toggleClass('hidden')
|
$("#last-edit").next(".dotted-spinner").toggleClass('hidden')
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
/* mousetrap v1.6.1 craig.is/killing/mice */
|
|
||||||
(function(r,v,f){function w(a,b,g){a.addEventListener?a.addEventListener(b,g,!1):a.attachEvent("on"+b,g)}function A(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return p[a.which]?p[a.which]:t[a.which]?t[a.which]:String.fromCharCode(a.which).toLowerCase()}function F(a){var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");return b}function x(a){return"shift"==a||"ctrl"==a||"alt"==a||
|
|
||||||
"meta"==a}function B(a,b){var g,c,d,f=[];g=a;"+"===g?g=["+"]:(g=g.replace(/\+{2}/g,"+plus"),g=g.split("+"));for(d=0;d<g.length;++d)c=g[d],C[c]&&(c=C[c]),b&&"keypress"!=b&&D[c]&&(c=D[c],f.push("shift")),x(c)&&f.push(c);g=c;d=b;if(!d){if(!n){n={};for(var q in p)95<q&&112>q||p.hasOwnProperty(q)&&(n[p[q]]=q)}d=n[g]?"keydown":"keypress"}"keypress"==d&&f.length&&(d="keydown");return{key:c,modifiers:f,action:d}}function E(a,b){return null===a||a===v?!1:a===b?!0:E(a.parentNode,b)}function c(a){function b(a){a=
|
|
||||||
a||{};var b=!1,l;for(l in n)a[l]?b=!0:n[l]=0;b||(y=!1)}function g(a,b,u,e,c,g){var l,m,k=[],f=u.type;if(!h._callbacks[a])return[];"keyup"==f&&x(a)&&(b=[a]);for(l=0;l<h._callbacks[a].length;++l)if(m=h._callbacks[a][l],(e||!m.seq||n[m.seq]==m.level)&&f==m.action){var d;(d="keypress"==f&&!u.metaKey&&!u.ctrlKey)||(d=m.modifiers,d=b.sort().join(",")===d.sort().join(","));d&&(d=e&&m.seq==e&&m.level==g,(!e&&m.combo==c||d)&&h._callbacks[a].splice(l,1),k.push(m))}return k}function f(a,b,c,e){h.stopCallback(b,
|
|
||||||
b.target||b.srcElement,c,e)||!1!==a(b,c)||(b.preventDefault?b.preventDefault():b.returnValue=!1,b.stopPropagation?b.stopPropagation():b.cancelBubble=!0)}function d(a){"number"!==typeof a.which&&(a.which=a.keyCode);var b=A(a);b&&("keyup"==a.type&&z===b?z=!1:h.handleKey(b,F(a),a))}function p(a,c,u,e){function l(c){return function(){y=c;++n[a];clearTimeout(r);r=setTimeout(b,1E3)}}function g(c){f(u,c,a);"keyup"!==e&&(z=A(c));setTimeout(b,10)}for(var d=n[a]=0;d<c.length;++d){var m=d+1===c.length?g:l(e||
|
|
||||||
B(c[d+1]).action);q(c[d],m,e,a,d)}}function q(a,b,c,e,d){h._directMap[a+":"+c]=b;a=a.replace(/\s+/g," ");var f=a.split(" ");1<f.length?p(a,f,b,c):(c=B(a,c),h._callbacks[c.key]=h._callbacks[c.key]||[],g(c.key,c.modifiers,{type:c.action},e,a,d),h._callbacks[c.key][e?"unshift":"push"]({callback:b,modifiers:c.modifiers,action:c.action,seq:e,level:d,combo:a}))}var h=this;a=a||v;if(!(h instanceof c))return new c(a);h.target=a;h._callbacks={};h._directMap={};var n={},r,z=!1,t=!1,y=!1;h._handleKey=function(a,
|
|
||||||
c,d){var e=g(a,c,d),k;c={};var h=0,l=!1;for(k=0;k<e.length;++k)e[k].seq&&(h=Math.max(h,e[k].level));for(k=0;k<e.length;++k)e[k].seq?e[k].level==h&&(l=!0,c[e[k].seq]=1,f(e[k].callback,d,e[k].combo,e[k].seq)):l||f(e[k].callback,d,e[k].combo);e="keypress"==d.type&&t;d.type!=y||x(a)||e||b(c);t=l&&"keydown"==d.type};h._bindMultiple=function(a,b,c){for(var d=0;d<a.length;++d)q(a[d],b,c)};w(a,"keypress",d);w(a,"keydown",d);w(a,"keyup",d)}if(r){var p={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",
|
|
||||||
18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},t={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},D={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},C={option:"alt",command:"meta","return":"enter",
|
|
||||||
escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},n;for(f=1;20>f;++f)p[111+f]="f"+f;for(f=0;9>=f;++f)p[f+96]=f.toString();c.prototype.bind=function(a,b,c){a=a instanceof Array?a:[a];this._bindMultiple.call(this,a,b,c);return this};c.prototype.unbind=function(a,b){return this.bind.call(this,a,function(){},b)};c.prototype.trigger=function(a,b){if(this._directMap[a+":"+b])this._directMap[a+":"+b]({},a);return this};c.prototype.reset=function(){this._callbacks={};
|
|
||||||
this._directMap={};return this};c.prototype.stopCallback=function(a,b){return-1<(" "+b.className+" ").indexOf(" mousetrap ")||E(b,this.target)?!1:"INPUT"==b.tagName||"SELECT"==b.tagName||"TEXTAREA"==b.tagName||b.isContentEditable};c.prototype.handleKey=function(){return this._handleKey.apply(this,arguments)};c.addKeycodes=function(a){for(var b in a)a.hasOwnProperty(b)&&(p[b]=a[b]);n=null};c.init=function(){var a=c(v),b;for(b in a)"_"!==b.charAt(0)&&(c[b]=function(b){return function(){return a[b].apply(a,
|
|
||||||
arguments)}}(b))};c.init();r.Mousetrap=c;"undefined"!==typeof module&&module.exports&&(module.exports=c);"function"===typeof define&&define.amd&&define(function(){return c})}})("undefined"!==typeof window?window:null,"undefined"!==typeof window?document:null);
|
|
||||||
@@ -510,6 +510,14 @@ a {
|
|||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#head .header-title {
|
||||||
|
font-size: 1.5em;
|
||||||
|
|
||||||
|
@include largemobile-breakpoint {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Highlights */
|
/* Highlights */
|
||||||
|
|
||||||
.highlight {
|
.highlight {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<div id="wiki-wrapper" class="compare">
|
<div id="wiki-wrapper" class="compare">
|
||||||
<div id="head">
|
<div id="head">
|
||||||
<h1 class="py-4">{{message}}</h1>
|
<h1 class="header-title text-center text-md-left py-4">
|
||||||
{{author}} commited {{authored_date}}
|
{{message}}
|
||||||
|
</h1>
|
||||||
|
{{author}} commited <time datetime="{{datetime}}">{{authored_date}}</time>
|
||||||
<span class="px-2 float-right">commit <code>{{version}}</code></span>
|
<span class="px-2 float-right">commit <code>{{version}}</code></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,52 +1,87 @@
|
|||||||
<div id="wiki-wrapper" class="compare">
|
<div id="wiki-wrapper" class="compare">
|
||||||
<div id="head">
|
<div id="head">
|
||||||
{{>navbar}}
|
{{>navbar}}
|
||||||
<h1 class="py-4"><span class="f1-light text-gray-light">Comparing versions of</span> {{name}}</h1>
|
|
||||||
</div>
|
<h1 class="header-title text-center text-md-left py-4">
|
||||||
|
<span class="f1-light text-gray-light">
|
||||||
|
{{t.comparing_versions_of}}
|
||||||
|
</span>
|
||||||
|
{{name}}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{#message}}
|
{{#message}}
|
||||||
<p>{{message}}</p>
|
<p>{{message}}</p>
|
||||||
{{/message}}
|
{{/message}}
|
||||||
|
|
||||||
<div id="compare-content">
|
<div id="compare-content">
|
||||||
|
|
||||||
<div class="py-4" id="actions">
|
<div class="py-4" id="actions">
|
||||||
{{#show_revert}}
|
{{#show_revert}}
|
||||||
{{#allow_editing}}
|
{{#allow_editing}}
|
||||||
<form name="gollum-revert" action="{{revert_path}}/{{escaped_url_path}}/{{before}}/{{after}}" method="post" id="gollum-revert-form"></form>
|
<form name="gollum-revert" action="{{revert_path}}/{{escaped_url_path}}/{{before}}/{{after}}" method="post" id="gollum-revert-form"></form>
|
||||||
<span class="pb-4">
|
<span class="pb-4">
|
||||||
<button class="btn btn-sm" type="submit" onclick="$('#gollum-revert-form').submit()">Revert Changes</button>
|
<button
|
||||||
</span>
|
class="btn btn-sm"
|
||||||
{{/allow_editing}}
|
onclick="$('#gollum-revert-form').submit()"
|
||||||
{{/show_revert}}
|
type="submit"
|
||||||
<a href="{{history_path}}/{{escaped_url_path}}" class="btn btn-sm action-page-history">Back to Page History</a>
|
>
|
||||||
</div>
|
{{t.revert}}
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
{{/allow_editing}}
|
||||||
|
{{/show_revert}}
|
||||||
|
|
||||||
<div class="Box data highlight">
|
<a
|
||||||
<div class="Box-header Box--condensed Box-header--gray">{{path}} <span class="px-2 float-right">Comparing {{before}} to {{after}}</span></div>
|
class="btn btn-sm action-page-history"
|
||||||
<table >
|
href="{{history_path}}/{{escaped_url_path}}"
|
||||||
{{#lines}}
|
>
|
||||||
<tr>
|
{{t.back_to_page_history}}
|
||||||
<td class="line_numbers">{{ldln}}</td>
|
</a>
|
||||||
<td class="line_numbers">{{rdln}}</td>
|
</div>
|
||||||
<td>
|
|
||||||
<div class="{{class}} pl-2">{{line}}</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{{/lines}}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="pt-4" id="footer">
|
<div class="Box data highlight">
|
||||||
{{#show_revert}}
|
<div class="Box-header Box--condensed Box-header--gray">
|
||||||
{{#allow_editing}}
|
{{path}}
|
||||||
<span class="pt-4"><button class="btn btn-sm gollum-revert-button" type="submit" onclick="$('#gollum-revert-form').submit()">Revert Changes</button></span>
|
|
||||||
{{/allow_editing}}
|
<span class="px-2 float-right">
|
||||||
{{/show_revert}}
|
{{t.comparing_from}}
|
||||||
<div class="pt-4">
|
</span>
|
||||||
<a href="#">Back to Top</a>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
<table>
|
||||||
|
{{#lines}}
|
||||||
|
<tr>
|
||||||
|
<td class="line_numbers">{{ldln}}</td>
|
||||||
|
<td class="line_numbers">{{rdln}}</td>
|
||||||
|
<td>
|
||||||
|
<div class="{{class}} pl-2">{{line}}</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{/lines}}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pt-4" id="footer">
|
||||||
|
{{#show_revert}}
|
||||||
|
{{#allow_editing}}
|
||||||
|
<span class="pt-4">
|
||||||
|
<button
|
||||||
|
class="btn btn-sm gollum-revert-button"
|
||||||
|
onclick="$('#gollum-revert-form').submit()"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
{{t.revert}}
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
{{/allow_editing}}
|
||||||
|
{{/show_revert}}
|
||||||
|
|
||||||
|
<div class="pt-4">
|
||||||
|
<a href="#">
|
||||||
|
{{t.back_to_top}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
<div id="wiki-wrapper" class="create">
|
<div id="wiki-wrapper" class="create">
|
||||||
<div id="head">
|
<div id="head">
|
||||||
{{>navbar}}
|
{{>navbar}}
|
||||||
<h1 class="py-4">Create New Page</h1>
|
|
||||||
</div>
|
<h1 class="header-title text-center text-md-left py-4">
|
||||||
|
Create New Page
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
<div id="wiki-content" class="create edit">
|
<div id="wiki-content" class="create edit">
|
||||||
<div class="tabnav">
|
<div class="tabnav">
|
||||||
<nav class="tabnav-tabs" aria-label="Toggle edit or preview mode">
|
<nav class="tabnav-tabs" aria-label="Toggle edit or preview mode">
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
<div id="wiki-wrapper" class="edit">
|
<div id="wiki-wrapper" class="edit">
|
||||||
<div id="head">
|
<div id="head">
|
||||||
{{>navbar}}
|
{{>navbar}}
|
||||||
<h1 class="py-4">Editing <strong>{{title}}</strong></h1>
|
|
||||||
</div>
|
<h1 class="header-title text-center text-md-left py-4">
|
||||||
|
Editing <strong>{{title}}</strong>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
<div class="tabnav">
|
<div class="tabnav">
|
||||||
<nav class="tabnav-tabs">
|
<nav class="tabnav-tabs">
|
||||||
<a href="#" id="edit" class="tabnav-tab selected" aria-current="page">
|
<a href="#" id="edit" class="tabnav-tab selected" aria-current="page">
|
||||||
|
|||||||
@@ -51,9 +51,9 @@
|
|||||||
<div id="gollum-editor-format-selector">
|
<div id="gollum-editor-format-selector">
|
||||||
<label for="format">Keybinding</label>
|
<label for="format">Keybinding</label>
|
||||||
<select id="keybinding" name="keybinding" class="form-select input-sm">
|
<select id="keybinding" name="keybinding" class="form-select input-sm">
|
||||||
<option selected="selected">default</option>
|
{{#keybindings}}
|
||||||
<option>vim</option>
|
<option {{#selected}}selected="selected" {{/selected}}value="{{name}}">{{name}}</option>
|
||||||
<option>emacs</option>
|
{{/keybindings}}
|
||||||
</select>
|
</select>
|
||||||
<label for="format">Markup</label>
|
<label for="format">Markup</label>
|
||||||
<select id="wiki_format" name="format" class="form-select input-sm">
|
<select id="wiki_format" name="format" class="form-select input-sm">
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<div id="wiki-wrapper" class="error">
|
<div id="wiki-wrapper" class="error">
|
||||||
<div id="error">
|
<div id="error">
|
||||||
<h1>Error</h1>
|
<h1>{{t.error}}</h1>
|
||||||
<p>
|
<p>
|
||||||
{{message}}
|
{{message}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,38 +1,54 @@
|
|||||||
<div id="wiki-wrapper" class="history">
|
<div id="wiki-wrapper" class="history">
|
||||||
<div id="head">
|
<div id="head">
|
||||||
{{>navbar}}
|
{{>navbar}}
|
||||||
<h1 class="py-4"><span class="f1-light text-gray-light">History for</span> {{name}}</h1>
|
|
||||||
|
<h1 class="header-title text-center text-md-left py-4">
|
||||||
|
<span class="f1-light text-gray-light">
|
||||||
|
{{t.history_for}}
|
||||||
|
</span>
|
||||||
|
{{name}}
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="page-history">
|
<div id="page-history">
|
||||||
|
|
||||||
{{>pagination}}
|
{{>pagination}}
|
||||||
|
|
||||||
<form name="selection-form" id="selection-form" method="get" action="{{compare_path}}/{{escaped_url_path}}"></form>
|
<form name="selection-form" id="selection-form" method="get" action="{{compare_path}}/{{escaped_url_path}}"></form>
|
||||||
|
|
||||||
<div id="page-history-list" class="Box Box--condensed flex-auto">
|
<div id="page-history-list" class="Box Box--condensed flex-auto">
|
||||||
<form id="version-form">
|
<form id="version-form">
|
||||||
<ul>
|
<ul>
|
||||||
{{#versions}}
|
{{#versions}}
|
||||||
<li class="Box-row border-top Box-row--hover-gray d-flex flex-items-center">
|
<li class="Box-row border-top Box-row--hover-gray d-flex flex-items-center">
|
||||||
<span class="pr-2"><input class="checkbox" type="checkbox" name="versions[]" value="{{id}}"></span>
|
<span class="pr-2"><input class="checkbox" type="checkbox" name="versions[]" value="{{id}}"></span>
|
||||||
<span class="float-left col-2" id="user-icons">{{>author_template}}</span>
|
<span class="float-left col-2" id="user-icons">{{>author_template}}</span>
|
||||||
<span class="flex-auto col-1 text-gray-light">{{date}}</span>
|
<time class="flex-auto col-1 text-gray-light" datetime="{{datetime}}" data-format="{{date_format}}">{{date}}</time>
|
||||||
<span class="flex-auto col-5">{{message}}</span>
|
<span class="flex-auto col-5">{{message}}</span>
|
||||||
<span class="pl-4 float-right">
|
<span class="pl-4 float-right">
|
||||||
<a href="{{href}}" class="btn btn-outline text-mono">{{id7}}</a>
|
<a href="{{href}}" class="btn btn-outline text-mono">{{id7}}</a>
|
||||||
<a href="{{href_page}}" title="Browse the page at this point in the history" class="btn btn-outline">{{#octicon}}code{{/octicon}}</a>
|
<a
|
||||||
</span>
|
class="btn btn-outline"
|
||||||
</li>
|
href="{{href_page}}"
|
||||||
{{/versions}}
|
title="{{t.browse_in_history_description}}"
|
||||||
</ul>
|
>
|
||||||
</form>
|
{{#octicon}}code{{/octicon}}
|
||||||
</div>
|
</a>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
{{/versions}}
|
||||||
|
</ul>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="footer">
|
||||||
<div id="footer">
|
<div class="pt-4">
|
||||||
<div class="pt-4">
|
<button
|
||||||
<button class="btn btn-sm action-compare-revision" type="submit">Compare Revisions</button>
|
class="btn btn-sm action-compare-revision"
|
||||||
</div>
|
type="submit"
|
||||||
</div>
|
>
|
||||||
|
{{t.compare_revisions}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
<div id="wiki-wrapper" class="history">
|
<div id="wiki-wrapper" class="history">
|
||||||
<div id="head">
|
<div id="head">
|
||||||
{{>navbar}}
|
{{>navbar}}
|
||||||
<h1 class="py-4">{{title}}</h1>
|
|
||||||
</div>
|
<h1 class="header-title text-center text-md-left py-4">
|
||||||
|
{{title}}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{>pagination}}
|
{{>pagination}}
|
||||||
|
|
||||||
@@ -12,7 +15,7 @@
|
|||||||
{{#versions}}
|
{{#versions}}
|
||||||
<li class="Box-row Box-row--hover-gray border-top d-flex flex-items-center">
|
<li class="Box-row Box-row--hover-gray border-top d-flex flex-items-center">
|
||||||
<span class="float-left col-2" id="user-icons">{{>author_template}}</span>
|
<span class="float-left col-2" id="user-icons">{{>author_template}}</span>
|
||||||
<span class="flex-auto col-1 text-gray-light">{{date}}</span>
|
<time class="flex-auto col-1 text-gray-light" datetime="{{datetime}}" data-format="{{date_format}}">{{date}}</time>
|
||||||
<span class="flex-auto col-5">{{message}}<br/>
|
<span class="flex-auto col-5">{{message}}<br/>
|
||||||
{{#files}}
|
{{#files}}
|
||||||
<span class="flex-auto col-2">{{#renamed}}{{renamed}} -> {{/renamed}}<a href="{{link}}">{{file}}</a></span><br/>
|
<span class="flex-auto col-2">{{#renamed}}{{renamed}} -> {{/renamed}}<a href="{{link}}">{{file}}</a></span><br/>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
<script>
|
<script>
|
||||||
var criticMarkup = '{{critic_markup}}';
|
var criticMarkup = '{{critic_markup}}';
|
||||||
var baseUrl = '{{base_url}}';
|
var baseUrl = '{{base_url}}';
|
||||||
|
var showLocalTime = {{{show_local_time}}};
|
||||||
var uploadDest = 'uploads';
|
var uploadDest = 'uploads';
|
||||||
var perPageUploads = '{{per_page_uploads}}';
|
var perPageUploads = '{{per_page_uploads}}';
|
||||||
if (perPageUploads == 'true') {
|
if (perPageUploads == 'true') {
|
||||||
@@ -30,6 +31,9 @@
|
|||||||
{{#is_create_page}}
|
{{#is_create_page}}
|
||||||
var default_markup = '{{default_markup}}';
|
var default_markup = '{{default_markup}}';
|
||||||
{{/is_create_page}}
|
{{/is_create_page}}
|
||||||
|
{{#has_editor}}
|
||||||
|
var default_keybinding = '{{default_keybinding}}';
|
||||||
|
{{/has_editor}}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{{#sprockets_javascript_tag}}app{{/sprockets_javascript_tag}}
|
{{#sprockets_javascript_tag}}app{{/sprockets_javascript_tag}}
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
<nav class="TableObject actions pt-4 px-2 px-lg-0 overflow-x-scroll">
|
<nav class="TableObject
|
||||||
|
actions
|
||||||
|
border-bottom
|
||||||
|
border-md-0
|
||||||
|
p-2
|
||||||
|
pt-lg-4
|
||||||
|
px-lg-0
|
||||||
|
overflow-x-scroll">
|
||||||
<div class="TableObject-item hide-lg hide-xl">
|
<div class="TableObject-item hide-lg hide-xl">
|
||||||
{{>mobilenav}}
|
{{>mobilenav}}
|
||||||
</div>
|
</div>
|
||||||
@@ -45,7 +52,7 @@
|
|||||||
{{#history}}
|
{{#history}}
|
||||||
<a
|
<a
|
||||||
class="btn BtnGroup-item btn-sm hide-sm hide-md"
|
class="btn BtnGroup-item btn-sm hide-sm hide-md"
|
||||||
href="{{history_path}}/{{escaped_url_path}}"
|
href="{{history_path}}/{{escaped_url_path}}/{{version}}"
|
||||||
id="minibutton-history"
|
id="minibutton-history"
|
||||||
>
|
>
|
||||||
History
|
History
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
<div id="wiki-wrapper" class="results">
|
<div id="wiki-wrapper" class="results">
|
||||||
<div id="head" class="overview">
|
<div id="head" class="overview">
|
||||||
{{>navbar}}
|
{{>navbar}}
|
||||||
<h1 class="py-4">{{title}}</h1>
|
|
||||||
</div>
|
<h1 class="header-title text-center text-md-left py-4">
|
||||||
|
{{title}}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
<div id="overview">
|
<div id="overview">
|
||||||
|
|
||||||
{{#has_results}}
|
{{#has_results}}
|
||||||
@@ -18,25 +21,38 @@
|
|||||||
<span class="pr-2">{{{icon}}}</span>
|
<span class="pr-2">{{{icon}}}</span>
|
||||||
<span><a href="{{url}}">{{name}}</a></span>
|
<span><a href="{{url}}">{{name}}</a></span>
|
||||||
{{#allow_editing}}
|
{{#allow_editing}}
|
||||||
{{#is_file}}<button class="btn btn-sm float-right delete-file" data-file-path="{{file_path}}" data-confirm="Are you sure you want to delete {{name}}?">{{#octicon}}trash{{/octicon}}</button>{{/is_file}}
|
{{#is_file}}
|
||||||
{{/allow_editing}}
|
<button
|
||||||
|
class="btn btn-sm float-right delete-file"
|
||||||
|
data-confirm="{{t.delete_confirmation}}"
|
||||||
|
data-file-path="{{file_path}}"
|
||||||
|
>
|
||||||
|
{{#octicon}}trash{{/octicon}}
|
||||||
|
</button>
|
||||||
|
{{/is_file}}
|
||||||
|
{{/allow_editing}}
|
||||||
</li>
|
</li>
|
||||||
{{/files_folders}}
|
{{/files_folders}}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{{/has_results}}
|
{{/has_results}}
|
||||||
|
|
||||||
{{#no_results}}
|
{{#no_results}}
|
||||||
<p id="no-results">
|
<p id="no-results">
|
||||||
There are no pages in <strong>{{current_path}}</strong> on <strong>{{ref}}</strong>.
|
{{t.no_pages_in}}
|
||||||
|
<strong>{{current_path}}</strong>
|
||||||
|
{{t.on}}
|
||||||
|
<strong>{{ref}}</strong>.
|
||||||
</p>
|
</p>
|
||||||
{{/no_results}}
|
{{/no_results}}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="pt-4" id="footer">
|
<div class="pt-4" id="footer">
|
||||||
<a href="#">Back to Top</a>
|
<a href="#">
|
||||||
|
{{t.back_to_top}}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,23 @@
|
|||||||
<nav class="paginate-container" aria-label="Pagination">
|
<nav class="paginate-container" aria-label="{{tt.pagination.aria.label}}">
|
||||||
<div class="pagination" id="pagination">
|
<div class="pagination" id="pagination">
|
||||||
<a id="prev" href="?page_num={{previous_page}}{{query_string}}" class="previous_page {{^previous_page}}disabled{{/previous_page}}">Previous</span>
|
<a
|
||||||
<a id="next" href="?page_num={{next_page}}{{query_string}}" class="next_page {{^next_page}}disabled{{/next_page}}" rel="next" aria-label="Next Page">Next</a>
|
aria-label="{{td.pagination.aria.previous_page}}"
|
||||||
|
class="previous_page {{^previous_page}}disabled{{/previous_page}}"
|
||||||
|
href="?page_num={{previous_page}}{{query_string}}"
|
||||||
|
id="prev"
|
||||||
|
rel="prev"
|
||||||
|
>
|
||||||
|
{{tt.pagination.previous}}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
aria-label="{{td.pagination.aria.next_page}}"
|
||||||
|
class="next_page {{^next_page}}disabled{{/next_page}}"
|
||||||
|
href="?page_num={{next_page}}{{query_string}}"
|
||||||
|
id="next"
|
||||||
|
rel="next"
|
||||||
|
>
|
||||||
|
{{tt.pagination.next}}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
<div id="wiki-wrapper" class="results">
|
<div id="wiki-wrapper" class="results">
|
||||||
<div id="head">
|
<div id="head">
|
||||||
{{>navbar}}
|
{{>navbar}}
|
||||||
<h1 class="py-4"><span class="f1-light text-gray-light">Search results for</span> {{name}}</h1>
|
|
||||||
|
<h1 class="header-title text-center text-md-left py-4">
|
||||||
|
<span class="f1-light text-gray-light">
|
||||||
|
{{t.search_results_for}}
|
||||||
|
</span>
|
||||||
|
{{name}}
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#has_results}}
|
{{#has_results}}
|
||||||
@@ -15,7 +21,12 @@
|
|||||||
<li class="Box-row Box-row--gray">
|
<li class="Box-row Box-row--gray">
|
||||||
<span class="Counter Counter--gray tooltipped tooltipped-w" aria-label="{{filename_count}} hits in filename - {{count}} hits in content">{{filename_count}} - {{count}}</span>
|
<span class="Counter Counter--gray tooltipped tooltipped-w" aria-label="{{filename_count}} hits in filename - {{count}} hits in content">{{filename_count}} - {{count}}</span>
|
||||||
<span class="text-bold"><a href="{{href}}">{{name}}</a></span>
|
<span class="text-bold"><a href="{{href}}">{{name}}</a></span>
|
||||||
<button class="btn-link tooltipped tooltipped-w float-right toggle-context" aria-label="Show all {{count}} hits in this page">{{#octicon}}search{{/octicon}}</button>
|
<button
|
||||||
|
class="btn-link tooltipped tooltipped-w float-right toggle-context"
|
||||||
|
aria-label="{{t.aria.show_all}}"
|
||||||
|
>
|
||||||
|
{{#octicon}}search{{/octicon}}
|
||||||
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<div class="search-context">
|
<div class="search-context">
|
||||||
@@ -23,7 +34,6 @@
|
|||||||
<li class="Box-row border-0"><span class="text-italic">{{.}}</span></li>
|
<li class="Box-row border-0"><span class="text-italic">{{.}}</span></li>
|
||||||
{{/context}}
|
{{/context}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{/results}}
|
{{/results}}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -31,12 +41,12 @@
|
|||||||
|
|
||||||
{{#no_results}}
|
{{#no_results}}
|
||||||
<p id="no-results">
|
<p id="no-results">
|
||||||
There are no results for your search <strong>{{query}}</strong>.
|
{{t.no_results}} <strong>{{query}}</strong>.
|
||||||
</p>
|
</p>
|
||||||
{{/no_results}}
|
{{/no_results}}
|
||||||
|
|
||||||
<div id="footer" class="mt-4">
|
<div id="footer" class="mt-4">
|
||||||
<a class="btn" href="#">Back to Top</a>
|
<a class="btn" href="#">{{t.back_to_top}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<div id="wiki-content" class="px-2 px-lg-0">
|
<div id="wiki-content" class="px-2 px-lg-0">
|
||||||
<h1 class="pt-4">{{page_header}}</h1>
|
<h1 class="header-title text-center text-md-left pt-4">
|
||||||
|
{{page_header}}
|
||||||
|
</h1>
|
||||||
<div class="breadcrumb">{{{breadcrumb}}}</div>
|
<div class="breadcrumb">{{{breadcrumb}}}</div>
|
||||||
|
|
||||||
<div class="{{#has_header}}has-header{{/has_header}}{{#has_footer}} has-footer{{/has_footer}}{{#has_sidebar}} has-sidebar has-{{bar_side}}bar{{/has_sidebar}}{{#has_toc}} has-toc{{/has_toc}}">
|
<div class="{{#has_header}}has-header{{/has_header}}{{#has_footer}} has-footer{{/has_footer}}{{#has_sidebar}} has-sidebar has-{{bar_side}}bar{{/has_sidebar}}{{#has_toc}} has-toc{{/has_toc}}">
|
||||||
@@ -54,7 +56,7 @@
|
|||||||
{{/preview}}
|
{{/preview}}
|
||||||
{{/historical}}
|
{{/historical}}
|
||||||
{{#historical}}
|
{{#historical}}
|
||||||
<p>This version of the page was edited by <b>{{author}}</b> at {{date}}. <a href="{{full_url_path}}">View the most recent version.</a></p>
|
<p>This version of the page was edited by <b>{{author}}</b> at <time datetime="{{datetime}}" data-format="{{date_format}}">{{date}}</time>. <a href="{{full_url_path}}">View the most recent version.</a></p>
|
||||||
{{/historical}}
|
{{/historical}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ module Precious
|
|||||||
def authored_date
|
def authored_date
|
||||||
@commit.authored_date
|
@commit.authored_date
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def datetime
|
||||||
|
authored_date.utc.iso8601
|
||||||
|
end
|
||||||
|
|
||||||
def message
|
def message
|
||||||
@commit.message
|
@commit.message
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ module Precious
|
|||||||
attr_reader :page, :diff, :versions, :message, :allow_editing
|
attr_reader :page, :diff, :versions, :message, :allow_editing
|
||||||
|
|
||||||
def title
|
def title
|
||||||
"Comparison of #{@page.title}"
|
[t[:comparison_of], @page.title].join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
def before
|
def before
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ module Precious
|
|||||||
module Views
|
module Views
|
||||||
class Create < Layout
|
class Create < Layout
|
||||||
include Editable
|
include Editable
|
||||||
|
include HasMath
|
||||||
|
|
||||||
attr_reader :page, :name
|
attr_reader :page, :name
|
||||||
|
|
||||||
@@ -41,9 +42,9 @@ module Precious
|
|||||||
def content
|
def content
|
||||||
@template_page
|
@template_page
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def find_format
|
def find_format
|
||||||
@found_format ||= (Gollum::Page.format_for("#{@name}#{@ext}") || default_markup)
|
@found_format ||= (Gollum::Page.format_for("#{@name}#{@ext}") || default_markup)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ module Precious
|
|||||||
class Edit < Layout
|
class Edit < Layout
|
||||||
include Editable
|
include Editable
|
||||||
include HasPage
|
include HasPage
|
||||||
|
include HasMath
|
||||||
|
|
||||||
attr_reader :page, :content
|
attr_reader :page, :content
|
||||||
|
|
||||||
@@ -18,10 +19,6 @@ module Precious
|
|||||||
def page_name
|
def page_name
|
||||||
@name
|
@name
|
||||||
end
|
end
|
||||||
|
|
||||||
def mathjax
|
|
||||||
@mathjax
|
|
||||||
end
|
|
||||||
|
|
||||||
def header
|
def header
|
||||||
if @header.nil?
|
if @header.nil?
|
||||||
@@ -67,7 +64,7 @@ module Precious
|
|||||||
def etag
|
def etag
|
||||||
@etag
|
@etag
|
||||||
end
|
end
|
||||||
|
|
||||||
def allow_uploads
|
def allow_uploads
|
||||||
@allow_uploads
|
@allow_uploads
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,6 +4,18 @@ module Precious
|
|||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def default_keybinding
|
||||||
|
@default_keybinding
|
||||||
|
end
|
||||||
|
|
||||||
|
def keybindings
|
||||||
|
Gollum::KEYBINDINGS.map do |kb|
|
||||||
|
{ :name => kb,
|
||||||
|
:selected => default_keybinding == kb
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def formats(selected = @page.format)
|
def formats(selected = @page.format)
|
||||||
Gollum::Markup.formats.map do |key, val|
|
Gollum::Markup.formats.map do |key, val|
|
||||||
{ :name => val[:name],
|
{ :name => val[:name],
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
module Precious
|
||||||
|
module HasMath
|
||||||
|
def mathjax
|
||||||
|
@mathjax
|
||||||
|
end
|
||||||
|
|
||||||
|
def mathjax_config
|
||||||
|
@mathjax_config
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -21,6 +21,13 @@ module Precious
|
|||||||
autofill I18n.t(locale_klass_name)
|
autofill I18n.t(locale_klass_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns all I18n translation strings from the root of an I18n YAML file.
|
||||||
|
# Otherwise, it works exactly like the `#t` method that's also defined in
|
||||||
|
# this file.
|
||||||
|
def tt
|
||||||
|
autofill I18n.t('.')
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Recursively looks up I18n translation values and autofills any YAML
|
# Recursively looks up I18n translation values and autofills any YAML
|
||||||
@@ -42,7 +49,7 @@ module Precious
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fill_argument_content(i18n_key, i18n_value)
|
def fill_argument_content(i18n_key, i18n_value)
|
||||||
i18n_value.gsub!(YAML_VARIABLE_REGEXP) do |argument|
|
i18n_value = i18n_value.gsub(YAML_VARIABLE_REGEXP) do |argument|
|
||||||
method_name = argument.gsub(/[^\w]/, '')
|
method_name = argument.gsub(/[^\w]/, '')
|
||||||
|
|
||||||
next if method_name.nil?
|
next if method_name.nil?
|
||||||
|
|||||||
+17
-12
@@ -1,6 +1,8 @@
|
|||||||
module Precious
|
module Precious
|
||||||
module Views
|
module Views
|
||||||
class History < Layout
|
class History < Layout
|
||||||
|
DATE_FORMAT = '%B %d, %Y'
|
||||||
|
|
||||||
include HasPage
|
include HasPage
|
||||||
include Pagination
|
include Pagination
|
||||||
include HasUserIcons
|
include HasUserIcons
|
||||||
@@ -18,18 +20,21 @@ module Precious
|
|||||||
@versions.map do |v|
|
@versions.map do |v|
|
||||||
i -= 1
|
i -= 1
|
||||||
filename = path_for_version(v.tracked_pathname)
|
filename = path_for_version(v.tracked_pathname)
|
||||||
{ :id => v.id,
|
authored_date = v.authored_date
|
||||||
:id7 => v.id[0..6],
|
{ :id => v.id,
|
||||||
:href => page_route("gollum/commit/#{v.id}"),
|
:id7 => v.id[0..6],
|
||||||
:href_page => page_route("#{filename}/#{v.id}"),
|
:href => page_route("gollum/commit/#{v.id}"),
|
||||||
:num => i,
|
:href_page => page_route("#{filename}/#{v.id}"),
|
||||||
:selected => @page.version.id == v.id,
|
:num => i,
|
||||||
:author => v.author.name.respond_to?(:force_encoding) ? v.author.name.force_encoding('UTF-8') : v.author.name,
|
:selected => @page.version.id == v.id,
|
||||||
:message => v.message.respond_to?(:force_encoding) ? v.message.force_encoding('UTF-8') : v.message,
|
:author => v.author.name.respond_to?(:force_encoding) ? v.author.name.force_encoding('UTF-8') : v.author.name,
|
||||||
:date => v.authored_date.strftime("%B %d, %Y"),
|
:message => v.message.respond_to?(:force_encoding) ? v.message.force_encoding('UTF-8') : v.message,
|
||||||
:user_icon => self.user_icon_code(v.author.email),
|
:date_full => authored_date,
|
||||||
:filename => filename,
|
:date => authored_date.strftime(DATE_FORMAT),
|
||||||
:date_full => v.authored_date,
|
:datetime => authored_date.utc.iso8601,
|
||||||
|
:date_format => DATE_FORMAT,
|
||||||
|
:user_icon => self.user_icon_code(v.author.email),
|
||||||
|
:filename => filename
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,29 +1,34 @@
|
|||||||
module Precious
|
module Precious
|
||||||
module Views
|
module Views
|
||||||
class LatestChanges < Layout
|
class LatestChanges < Layout
|
||||||
|
DATE_FORMAT = '%B %d, %Y'
|
||||||
|
|
||||||
include Pagination
|
include Pagination
|
||||||
include HasUserIcons
|
include HasUserIcons
|
||||||
|
|
||||||
attr_reader :wiki
|
attr_reader :wiki
|
||||||
|
|
||||||
def title
|
def title
|
||||||
"Latest Changes (Globally)"
|
t[:title]
|
||||||
end
|
end
|
||||||
|
|
||||||
def versions
|
def versions
|
||||||
i = @versions.size + 1
|
i = @versions.size + 1
|
||||||
@versions.map do |v|
|
@versions.map do |v|
|
||||||
i -= 1
|
i -= 1
|
||||||
{ :id => v.id,
|
authored_date = v.authored_date
|
||||||
:id7 => v.id[0..6],
|
{ :id => v.id,
|
||||||
:href => page_route("gollum/commit/#{v.id}"),
|
:id7 => v.id[0..6],
|
||||||
:num => i,
|
:href => page_route("gollum/commit/#{v.id}"),
|
||||||
:author => v.author.name.respond_to?(:force_encoding) ? v.author.name.force_encoding('UTF-8') : v.author.name,
|
:num => i,
|
||||||
:message => v.message.respond_to?(:force_encoding) ? v.message.force_encoding('UTF-8') : v.message,
|
:author => v.author.name.respond_to?(:force_encoding) ? v.author.name.force_encoding('UTF-8') : v.author.name,
|
||||||
:date => v.authored_date.strftime("%B %d, %Y"),
|
:message => v.message.respond_to?(:force_encoding) ? v.message.force_encoding('UTF-8') : v.message,
|
||||||
:user_icon => self.user_icon_code(v.author.email),
|
:date_full => authored_date,
|
||||||
:date_full => v.authored_date,
|
:date => authored_date.strftime(DATE_FORMAT),
|
||||||
:files => v.stats.files.map { |f|
|
:datetime => authored_date.utc.iso8601,
|
||||||
|
:date_format => DATE_FORMAT,
|
||||||
|
:user_icon => self.user_icon_code(v.author.email),
|
||||||
|
:files => v.stats.files.map { |f|
|
||||||
new_path = extract_page_dir(f[:new_file])
|
new_path = extract_page_dir(f[:new_file])
|
||||||
{ :file => new_path,
|
{ :file => new_path,
|
||||||
:link => "#{page_route(new_path)}/#{v.id}",
|
:link => "#{page_route(new_path)}/#{v.id}",
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ module Precious
|
|||||||
end
|
end
|
||||||
|
|
||||||
def title
|
def title
|
||||||
"Home"
|
t[:title]
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_path
|
def has_path
|
||||||
@@ -58,32 +58,36 @@ module Precious
|
|||||||
def js # custom js
|
def js # custom js
|
||||||
@js
|
@js
|
||||||
end
|
end
|
||||||
|
|
||||||
def critic_markup
|
def critic_markup
|
||||||
@critic_markup
|
@critic_markup
|
||||||
end
|
end
|
||||||
|
|
||||||
def per_page_uploads
|
def per_page_uploads
|
||||||
@per_page_uploads
|
@per_page_uploads
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show_local_time
|
||||||
|
@show_local_time ? 'true' : 'false'
|
||||||
|
end
|
||||||
|
|
||||||
# Navigation bar
|
# Navigation bar
|
||||||
def search
|
def search
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def history
|
def history
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def overview
|
def overview
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def latest_changes
|
def latest_changes
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ require 'pathname'
|
|||||||
module Precious
|
module Precious
|
||||||
module Views
|
module Views
|
||||||
class Overview < Layout
|
class Overview < Layout
|
||||||
attr_reader :results, :ref, :allow_editing, :newable
|
attr_reader :name, :results, :ref, :allow_editing, :newable
|
||||||
HIDDEN_PATHS = ['.gitkeep']
|
HIDDEN_PATHS = ['.gitkeep']
|
||||||
|
|
||||||
def title
|
def title
|
||||||
"Overview of #{@ref}"
|
t[:title]
|
||||||
end
|
end
|
||||||
|
|
||||||
# def editable
|
# def editable
|
||||||
@@ -38,21 +38,21 @@ module Precious
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def files_folders
|
def files_folders
|
||||||
if has_results
|
if has_results
|
||||||
files_and_folders = []
|
files_and_folders = []
|
||||||
|
|
||||||
@results.each do |result|
|
@results.each do |result|
|
||||||
result_path = result.url_path
|
result_path = result.url_path
|
||||||
result_path = result_path.sub(/^#{Regexp.escape(@path)}\//, '') unless @path.nil?
|
result_path = result_path.sub(/^#{Regexp.escape(@path)}\//, '') unless @path.nil?
|
||||||
if result_path.include?('/')
|
if result_path.include?('/')
|
||||||
# result contains a folder
|
# result contains a folder
|
||||||
folder_name = result_path.split('/').first
|
folder_name = result_path.split('/').first
|
||||||
folder_path = @path ? "#{@path}/#{folder_name}" : folder_name
|
folder_path = @path ? "#{@path}/#{folder_name}" : folder_name
|
||||||
folder_url = "#{overview_path}/#{folder_path}/"
|
folder_url = "#{overview_path}/#{folder_path}/"
|
||||||
files_and_folders << {name: folder_name, icon: rocticon('file-directory'), type: 'dir', url: folder_url, is_file: false}
|
files_and_folders << {name: folder_name, icon: rocticon('file-directory'), type: 'dir', url: folder_url, is_file: false}
|
||||||
elsif !HIDDEN_PATHS.include?(result_path)
|
elsif !HIDDEN_PATHS.include?(result_path)
|
||||||
file_url = page_route(result.escaped_url_path)
|
file_url = page_route(result.escaped_url_path)
|
||||||
files_and_folders << {name: result.filename, icon: rocticon('file'), type: 'file', url: file_url, file_path: result.escaped_url_path, is_file: true}
|
files_and_folders << {name: result.filename, icon: rocticon('file'), type: 'file', url: file_url, file_path: result.escaped_url_path, is_file: true}
|
||||||
end
|
end
|
||||||
@@ -61,7 +61,7 @@ module Precious
|
|||||||
files_and_folders.uniq{|f| f[:name]}.sort_by!{|f| [f[:type], f[:name]]}
|
files_and_folders.uniq{|f| f[:name]}.sort_by!{|f| [f[:type], f[:name]]}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def has_results
|
def has_results
|
||||||
!@results.empty?
|
!@results.empty?
|
||||||
@@ -70,12 +70,12 @@ module Precious
|
|||||||
def no_results
|
def no_results
|
||||||
@results.empty?
|
@results.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def latest_changes
|
def latest_changes
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+23
-18
@@ -2,8 +2,9 @@ module Precious
|
|||||||
module Views
|
module Views
|
||||||
class Page < Layout
|
class Page < Layout
|
||||||
include HasPage
|
include HasPage
|
||||||
|
include HasMath
|
||||||
|
|
||||||
attr_reader :content, :page, :header, :footer, :preview, :historical
|
attr_reader :content, :page, :header, :footer, :preview, :historical, :version
|
||||||
|
|
||||||
VALID_COUNTER_STYLES = ['decimal', 'decimal-leading-zero', 'arabic-indic', 'armenian', 'upper-armenian',
|
VALID_COUNTER_STYLES = ['decimal', 'decimal-leading-zero', 'arabic-indic', 'armenian', 'upper-armenian',
|
||||||
'lower-armenian', 'bengali', 'cambodian', 'khmer', 'cjk-decimal', 'devanagari', 'georgian', 'gujarati', 'gurmukhi',
|
'lower-armenian', 'bengali', 'cambodian', 'khmer', 'cjk-decimal', 'devanagari', 'georgian', 'gujarati', 'gurmukhi',
|
||||||
@@ -47,11 +48,23 @@ module Precious
|
|||||||
return DEFAULT_AUTHOR unless first
|
return DEFAULT_AUTHOR unless first
|
||||||
first.author.name.respond_to?(:force_encoding) ? first.author.name.force_encoding('UTF-8') : first.author.name
|
first.author.name.respond_to?(:force_encoding) ? first.author.name.force_encoding('UTF-8') : first.author.name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def date_full
|
||||||
|
first = @version ? page.version : page.last_version
|
||||||
|
return Time.now unless first
|
||||||
|
first.authored_date
|
||||||
|
end
|
||||||
|
|
||||||
def date
|
def date
|
||||||
first = @version ? page.version : page.last_version
|
date_full.strftime(DATE_FORMAT)
|
||||||
return Time.now.strftime(DATE_FORMAT) unless first
|
end
|
||||||
first.authored_date.strftime(DATE_FORMAT)
|
|
||||||
|
def datetime
|
||||||
|
date_full.utc.iso8601
|
||||||
|
end
|
||||||
|
|
||||||
|
def date_format
|
||||||
|
DATE_FORMAT
|
||||||
end
|
end
|
||||||
|
|
||||||
def noindex
|
def noindex
|
||||||
@@ -61,11 +74,11 @@ module Precious
|
|||||||
def editable
|
def editable
|
||||||
@editable
|
@editable
|
||||||
end
|
end
|
||||||
|
|
||||||
def search
|
def search
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def history
|
def history
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
@@ -73,11 +86,11 @@ module Precious
|
|||||||
def latest_changes
|
def latest_changes
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def overview
|
def overview
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def allow_editing
|
def allow_editing
|
||||||
@allow_editing
|
@allow_editing
|
||||||
end
|
end
|
||||||
@@ -157,14 +170,6 @@ module Precious
|
|||||||
@toc_content
|
@toc_content
|
||||||
end
|
end
|
||||||
|
|
||||||
def mathjax
|
|
||||||
@mathjax
|
|
||||||
end
|
|
||||||
|
|
||||||
def mathjax_config
|
|
||||||
@mathjax_config
|
|
||||||
end
|
|
||||||
|
|
||||||
def use_identicon
|
def use_identicon
|
||||||
@page.wiki.user_icons == 'identicon'
|
@page.wiki.user_icons == 'identicon'
|
||||||
end
|
end
|
||||||
@@ -182,7 +187,7 @@ module Precious
|
|||||||
# Returns Hash.
|
# Returns Hash.
|
||||||
def metadata
|
def metadata
|
||||||
@page.metadata
|
@page.metadata
|
||||||
end
|
end
|
||||||
|
|
||||||
# Access to embedded metadata.
|
# Access to embedded metadata.
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -10,4 +10,4 @@ module Precious
|
|||||||
@page_num == 1 ? nil : (@page_num - 1).to_s
|
@page_num == 1 ? nil : (@page_num - 1).to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+60
-19
@@ -1,43 +1,84 @@
|
|||||||
require 'rss'
|
require 'rss'
|
||||||
|
|
||||||
class RSSView
|
class RSSView
|
||||||
|
|
||||||
include Precious::Views::AppHelpers
|
include Precious::Views::AppHelpers
|
||||||
include Precious::Views::RouteHelpers
|
include Precious::Views::RouteHelpers
|
||||||
|
|
||||||
attr_reader :base_url
|
attr_reader :base_url
|
||||||
|
|
||||||
def initialize(base_url, wiki_title, url, changes)
|
def initialize(base_url, wiki_title, url, changes)
|
||||||
@base_url = base_url
|
@base_url = base_url
|
||||||
@wiki_title = wiki_title
|
@wiki_title = wiki_title
|
||||||
@url = url
|
@url = url
|
||||||
@changes = changes
|
@changes = changes
|
||||||
end
|
end
|
||||||
|
|
||||||
def render
|
def render
|
||||||
latest_changes = "#{@url}#{latest_changes_path}"
|
|
||||||
RSS::Maker.make('2.0') do |maker|
|
RSS::Maker.make('2.0') do |maker|
|
||||||
maker.channel.author = 'Gollum Wiki'
|
maker.channel.author = 'Gollum Wiki'
|
||||||
maker.channel.updated = @changes.first.authored_date
|
|
||||||
maker.channel.title = "#{@wiki_title} Latest Changes"
|
|
||||||
maker.channel.description = "Latest Changes in #{@wiki_title}"
|
maker.channel.description = "Latest Changes in #{@wiki_title}"
|
||||||
maker.channel.link = latest_changes
|
maker.channel.link = latest_changes_url
|
||||||
|
maker.channel.title = "#{@wiki_title} Latest Changes"
|
||||||
|
maker.channel.updated = @changes.first.authored_date
|
||||||
|
|
||||||
@changes.each do |change|
|
@changes.each do |change|
|
||||||
maker.items.new_item do |item|
|
maker.items.new_item do |item|
|
||||||
item.link = latest_changes
|
item.description = feed_item_description(change)
|
||||||
item.title = change.message
|
item.link = latest_changes_url
|
||||||
|
item.title = feed_item_title(change)
|
||||||
item.updated = change.authored_date
|
item.updated = change.authored_date
|
||||||
id = change.id
|
|
||||||
files = change.stats.files.map do |files|
|
|
||||||
[files[:old_file], files[:new_file]].compact.map do |file|
|
|
||||||
f = extract_page_dir(file)
|
|
||||||
"<li><a href=\"#{@url}#{page_route(f)}/#{id}\">#{f}</a></li>"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
item.description = "Commited by: <a href=\"mailto:#{change.author.email}\">#{change.author.name}</a><br/>Commit ID: #{id[0..6]}<br/><br/>Affected files:<ul>#{files.join}</ul>"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end.to_s
|
end.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
private
|
||||||
|
|
||||||
|
def feed_item_commit_body(change)
|
||||||
|
body = change.message.lines[1..-1].join
|
||||||
|
body = body.split(/\n{2}/).map { |paragraph| "<p>#{paragraph}</p>" }.join
|
||||||
|
body.gsub!(/\n/, ' ')
|
||||||
|
body
|
||||||
|
end
|
||||||
|
|
||||||
|
def feed_item_description(change)
|
||||||
|
ERB.new(<<~HTML_PARTIAL)
|
||||||
|
<%= feed_item_commit_body(change) %>
|
||||||
|
Committed by: <a href="mailto:<%= change.author.email %>">
|
||||||
|
<%= change.author.name %>
|
||||||
|
</a><br />
|
||||||
|
Commit ID: <%= change.id[0..6] %><br /><br />
|
||||||
|
<%= feed_item_files(change) %>
|
||||||
|
HTML_PARTIAL
|
||||||
|
.result(binding)
|
||||||
|
end
|
||||||
|
|
||||||
|
def feed_item_files(change)
|
||||||
|
file_list = change.stats.files.map { |change_files|
|
||||||
|
[
|
||||||
|
change_files[:old_file],
|
||||||
|
change_files[:new_file]
|
||||||
|
].compact
|
||||||
|
}
|
||||||
|
|
||||||
|
ERB.new(<<~HTML_PARTIAL)
|
||||||
|
Affected files: <ul>
|
||||||
|
<% file_list.each do |change_files| %>
|
||||||
|
<% change_files.each do |file| %>
|
||||||
|
<% file_href = "%s%s/%s" % [@url, page_route(file), change.id] %>
|
||||||
|
<li><a href="<%= file_href %>"><%= file %></a></li>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
|
HTML_PARTIAL
|
||||||
|
.result(binding)
|
||||||
|
end
|
||||||
|
|
||||||
|
def feed_item_title(change)
|
||||||
|
change.message.lines.first.strip
|
||||||
|
end
|
||||||
|
|
||||||
|
def latest_changes_url
|
||||||
|
"%s%s" % [@url, latest_changes_path]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ module Precious
|
|||||||
end
|
end
|
||||||
|
|
||||||
def title
|
def title
|
||||||
"Search results for " + @query
|
t[:title]
|
||||||
end
|
end
|
||||||
|
|
||||||
def search
|
def search
|
||||||
|
|||||||
@@ -11,9 +11,13 @@ module Precious
|
|||||||
end
|
end
|
||||||
|
|
||||||
def first_path_available(name)
|
def first_path_available(name)
|
||||||
priority = File.join(template_priority_path, "#{name}.#{template_extension}")
|
|
||||||
default = File.join(template_path, "#{name}.#{template_extension}")
|
default = File.join(template_path, "#{name}.#{template_extension}")
|
||||||
File.exists?(priority) ? priority : default
|
priority =
|
||||||
|
if template_priority_path
|
||||||
|
File.join(template_priority_path, "#{name}.#{template_extension}")
|
||||||
|
end
|
||||||
|
|
||||||
|
priority && File.exist?(priority) ? priority : default
|
||||||
end
|
end
|
||||||
|
|
||||||
# Method should track lib/mustache/settings.rb from Mustache project.
|
# Method should track lib/mustache/settings.rb from Mustache project.
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"mousetrap": "^1.6.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node" : ">=16.15.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
require_relative 'helper'
|
||||||
|
|
||||||
|
require 'selenium-webdriver'
|
||||||
|
require 'capybara/dsl'
|
||||||
|
|
||||||
|
Selenium::WebDriver::Chrome.path = ENV['CHROME_PATH'] if ENV['CHROME_PATH']
|
||||||
|
|
||||||
|
CAPYBARA_DRIVER =
|
||||||
|
if ENV['CI']
|
||||||
|
:selenium_chrome_headless
|
||||||
|
else
|
||||||
|
ENV.fetch('CAPYBARA_DRIVER', :selenium_chrome).to_sym
|
||||||
|
end
|
||||||
|
|
||||||
|
Capybara.default_driver = CAPYBARA_DRIVER
|
||||||
|
Capybara.enable_aria_label = true
|
||||||
|
Capybara.server = :webrick
|
||||||
|
|
||||||
|
def console_log(page, level = :severe)
|
||||||
|
page.driver.browser.logs.get(:browser).select { |log| log.level == level.to_s.upcase }
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
Binary file not shown.
@@ -3,3 +3,5 @@
|
|||||||
f403b791119f8232b7cb0ba455c624ac6435f433 ed6c9f63b98acf73c25b5ffbb38da557d3682023 bootstraponline <cafe@bootstraponline.com> 1336421777 -0600 commit: Add header.
|
f403b791119f8232b7cb0ba455c624ac6435f433 ed6c9f63b98acf73c25b5ffbb38da557d3682023 bootstraponline <cafe@bootstraponline.com> 1336421777 -0600 commit: Add header.
|
||||||
ed6c9f63b98acf73c25b5ffbb38da557d3682023 084a558a1fb3cded23129e2dfad3a17d07d73fd3 Daniel Kimsey <dekimsey@ufl.edu> 1354899095 -0500 push
|
ed6c9f63b98acf73c25b5ffbb38da557d3682023 084a558a1fb3cded23129e2dfad3a17d07d73fd3 Daniel Kimsey <dekimsey@ufl.edu> 1354899095 -0500 push
|
||||||
084a558a1fb3cded23129e2dfad3a17d07d73fd3 02796b1450691f90db5d6dc6a816a4980ce80d07 Dawa Ometto <dawa.ometto@phil.uu.nl> 1538516954 +0200 push
|
084a558a1fb3cded23129e2dfad3a17d07d73fd3 02796b1450691f90db5d6dc6a816a4980ce80d07 Dawa Ometto <dawa.ometto@phil.uu.nl> 1538516954 +0200 push
|
||||||
|
02796b1450691f90db5d6dc6a816a4980ce80d07 db8b297cf5a31b46ac24500edfdbd0d3d8eed4eb Nikita Ivanov <nikita.vyach.ivanov@gmail.com> 1640368693 +0500 commit: Created C (markdown)
|
||||||
|
db8b297cf5a31b46ac24500edfdbd0d3d8eed4eb c736e410f98df7a1173a540364dbb8a18274273e Nikita Ivanov <nikita.vyach.ivanov@gmail.com> 1640368721 +0500 commit: Deleted C.md
|
||||||
|
|||||||
@@ -3,3 +3,5 @@
|
|||||||
f403b791119f8232b7cb0ba455c624ac6435f433 ed6c9f63b98acf73c25b5ffbb38da557d3682023 bootstraponline <cafe@bootstraponline.com> 1336421777 -0600 commit: Add header.
|
f403b791119f8232b7cb0ba455c624ac6435f433 ed6c9f63b98acf73c25b5ffbb38da557d3682023 bootstraponline <cafe@bootstraponline.com> 1336421777 -0600 commit: Add header.
|
||||||
ed6c9f63b98acf73c25b5ffbb38da557d3682023 084a558a1fb3cded23129e2dfad3a17d07d73fd3 Daniel Kimsey <dekimsey@ufl.edu> 1354899095 -0500 push
|
ed6c9f63b98acf73c25b5ffbb38da557d3682023 084a558a1fb3cded23129e2dfad3a17d07d73fd3 Daniel Kimsey <dekimsey@ufl.edu> 1354899095 -0500 push
|
||||||
084a558a1fb3cded23129e2dfad3a17d07d73fd3 02796b1450691f90db5d6dc6a816a4980ce80d07 Dawa Ometto <dawa.ometto@phil.uu.nl> 1538516954 +0200 push
|
084a558a1fb3cded23129e2dfad3a17d07d73fd3 02796b1450691f90db5d6dc6a816a4980ce80d07 Dawa Ometto <dawa.ometto@phil.uu.nl> 1538516954 +0200 push
|
||||||
|
02796b1450691f90db5d6dc6a816a4980ce80d07 db8b297cf5a31b46ac24500edfdbd0d3d8eed4eb Nikita Ivanov <nikita.vyach.ivanov@gmail.com> 1640368693 +0500 commit: Created C (markdown)
|
||||||
|
db8b297cf5a31b46ac24500edfdbd0d3d8eed4eb c736e410f98df7a1173a540364dbb8a18274273e Nikita Ivanov <nikita.vyach.ivanov@gmail.com> 1640368721 +0500 commit: Deleted C.md
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,6 @@
|
|||||||
|
x¥ŽK
|
||||||
|
Â0@]÷³Ê¤ù4A7n¼Ã$3±AÓJ‰ooñ
|
||||||
|
.ß[<^œKÉ:‹»ºˆ€Öɸ€bY¥Á¡öI'Rh¢Ø8hSô¨4Só¢E¦
|
||||||
|
|è†>&KZã(vÆ"
|
||||||
|
'Œ¬Ù‹°‘ÐлŽó·üÈ•àºÒ4¯p˜~Ø®Šc›òt/”ŸmœË”3¨�ï;{ܲÍf·Ý*‡š‹<¥
|
||||||
|
ù-üš…Q×
|
||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
02796b1450691f90db5d6dc6a816a4980ce80d07
|
c736e410f98df7a1173a540364dbb8a18274273e
|
||||||
|
|||||||
@@ -15,12 +15,13 @@ describe Precious::Views::LocaleHelpers do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
::I18n.available_locales = [:en, :de]
|
I18n.available_locales = [:en, :de]
|
||||||
::I18n.load_path = Dir[File.expand_path("test/support/locales" + "/*.yml")]
|
I18n.load_path = Dir[File.expand_path("test/support/locales" + "/*.yml")]
|
||||||
end
|
end
|
||||||
|
|
||||||
def teardown
|
def teardown
|
||||||
I18n.locale = :en
|
I18n.locale = :en
|
||||||
|
I18n.load_path = Dir[::File.expand_path("lib/gollum/locales") + "/*.yml"]
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:dummy_instance) { TestClass.new }
|
let(:dummy_instance) { TestClass.new }
|
||||||
@@ -131,4 +132,99 @@ describe Precious::Views::LocaleHelpers do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#tt" do
|
||||||
|
describe "mustache usage" do
|
||||||
|
let(:subject) { dummy_instance.render(mustache_template) }
|
||||||
|
|
||||||
|
let(:mustache_template) { "{{ tt.test_class.hello_world }}" }
|
||||||
|
|
||||||
|
describe "in the default locale" do
|
||||||
|
it "returns the translation string" do
|
||||||
|
_(subject).must_equal "Hello world"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "in the configured locale" do
|
||||||
|
it "returns the translation string" do
|
||||||
|
I18n.locale = :de
|
||||||
|
|
||||||
|
_(subject).must_equal "Hallo Welt"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "translations with YAML arguments" do
|
||||||
|
let(:mustache_template) { "{{ tt.test_class.author_info.full }}" }
|
||||||
|
|
||||||
|
describe "in the default locale" do
|
||||||
|
it "autofills YAML arguments" do
|
||||||
|
_(subject).must_equal "Author J.R.R. is from Bloemfontein"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "in the configured locale" do
|
||||||
|
it "autofills YAML arguments" do
|
||||||
|
I18n.locale = :de
|
||||||
|
|
||||||
|
_(subject).must_equal "Autor J.R.R. ist vom Bloemfontein"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "translations with invalid arguments" do
|
||||||
|
let(:mustache_template) { "{{ tt.test_class.has_invalid_argument }}" }
|
||||||
|
|
||||||
|
it "fails gracefully with embedded error message" do
|
||||||
|
expected_string = "Welcome to " \
|
||||||
|
"[#{TestClass::NO_METHOD_MESSAGE}: no_matching_method]"
|
||||||
|
|
||||||
|
_(subject).must_equal expected_string
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "missing translations" do
|
||||||
|
let(:mustache_template) {
|
||||||
|
"{{ tt.test_class.nested.nonexistent_key }}"
|
||||||
|
}
|
||||||
|
|
||||||
|
it "outputs an empty string" do
|
||||||
|
_(subject).must_be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "usage" do
|
||||||
|
let(:subject) { dummy_instance.tt }
|
||||||
|
|
||||||
|
it "returns a hash" do
|
||||||
|
_(subject).must_be_kind_of Hash
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns all present translation keys" do
|
||||||
|
i18n_keys = I18n.t(".").keys
|
||||||
|
|
||||||
|
_(subject.keys).must_equal i18n_keys
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nested keys" do
|
||||||
|
nested_keys = subject[:test_class][:author_info].keys
|
||||||
|
|
||||||
|
_(nested_keys).must_equal [:full]
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "auto-filled YAML arguments" do
|
||||||
|
let(:subject) { dummy_instance.tt[:test_class][:author_info][:full] }
|
||||||
|
|
||||||
|
it "auto-fills in the default locale" do
|
||||||
|
_(subject).must_equal "Author J.R.R. is from Bloemfontein"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "auto-fills in a configured locale" do
|
||||||
|
I18n.locale = :de
|
||||||
|
|
||||||
|
_(subject).must_equal "Autor J.R.R. ist vom Bloemfontein"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+34
-14
@@ -1,19 +1,20 @@
|
|||||||
require 'rubygems'
|
require 'rubygems'
|
||||||
require 'rack/test'
|
require 'rack/test'
|
||||||
require 'test/unit'
|
|
||||||
require 'shoulda'
|
require 'shoulda'
|
||||||
require 'mocha/setup'
|
require 'minitest/autorun'
|
||||||
require 'fileutils'
|
|
||||||
require 'minitest/reporters'
|
require 'minitest/reporters'
|
||||||
require 'minitest/spec'
|
require 'minitest/spec'
|
||||||
require 'twitter_cldr'
|
require 'mocha/setup'
|
||||||
|
require 'fileutils'
|
||||||
require 'tmpdir'
|
require 'tmpdir'
|
||||||
|
|
||||||
# Silence locale validation warning
|
# Silence locale validation warning
|
||||||
require 'i18n'
|
require 'i18n'
|
||||||
I18n.enforce_available_locales = false
|
I18n.enforce_available_locales = false
|
||||||
|
|
||||||
MiniTest::Reporters.use!
|
Minitest::Reporters.use! [
|
||||||
|
Minitest::Reporters::DefaultReporter.new({color: true})
|
||||||
|
]
|
||||||
|
|
||||||
dir = File.dirname(File.expand_path(__FILE__))
|
dir = File.dirname(File.expand_path(__FILE__))
|
||||||
$LOAD_PATH.unshift(File.join(dir, '..', 'lib'))
|
$LOAD_PATH.unshift(File.join(dir, '..', 'lib'))
|
||||||
@@ -31,6 +32,7 @@ ENV['RACK_ENV'] = 'test'
|
|||||||
require 'gollum'
|
require 'gollum'
|
||||||
require 'gollum/app'
|
require 'gollum/app'
|
||||||
|
|
||||||
|
|
||||||
# Disable the metadata feature
|
# Disable the metadata feature
|
||||||
$METADATA = false
|
$METADATA = false
|
||||||
|
|
||||||
@@ -63,14 +65,29 @@ def normal(text)
|
|||||||
text
|
text
|
||||||
end
|
end
|
||||||
|
|
||||||
# test/spec/mini 3
|
# The following configuration originates from this gist:
|
||||||
# http://gist.github.com/25455
|
|
||||||
# chris@ozmm.org
|
# http://gist.github.com/25455
|
||||||
# file:lib/test/spec/mini.rb
|
#
|
||||||
|
# But it has been modified since it was first committed. It allows you to
|
||||||
|
# write tests with an RSpec-like DSL:
|
||||||
|
#
|
||||||
|
# context "my test context" do
|
||||||
|
# setup do
|
||||||
|
# # My test setup
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# teardown do
|
||||||
|
# # My test teardown
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# test "some functionality" do
|
||||||
|
# assert true
|
||||||
|
# end
|
||||||
|
# end
|
||||||
def context(*args, &block)
|
def context(*args, &block)
|
||||||
return super unless (name = args.first) && block
|
return super unless (name = args.first) && block
|
||||||
require 'test/unit'
|
klass = Class.new(Minitest::Test) do
|
||||||
klass = Class.new(defined?(ActiveSupport::TestCase) ? ActiveSupport::TestCase : Test::Unit::TestCase) do
|
|
||||||
def self.test(name, &block)
|
def self.test(name, &block)
|
||||||
define_method("test_#{name.gsub(/\W/, '_')}", &block) if block
|
define_method("test_#{name.gsub(/\W/, '_')}", &block) if block
|
||||||
end
|
end
|
||||||
@@ -86,10 +103,13 @@ def context(*args, &block)
|
|||||||
define_method(:teardown, &block)
|
define_method(:teardown, &block)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
(
|
(
|
||||||
class << klass;
|
class << klass;
|
||||||
self
|
self
|
||||||
end).send(:define_method, :name) { name.gsub(/\W/, '_') }
|
end
|
||||||
|
).send(:define_method, :name) { name.gsub(/\W/, '_') }
|
||||||
|
|
||||||
$contexts << klass
|
$contexts << klass
|
||||||
klass.class_eval &block
|
klass.class_eval &block
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
require_relative '../capybara_helper'
|
||||||
|
|
||||||
|
def console_log(page, level = :severe)
|
||||||
|
page.driver.browser.logs.get(:browser).select{|log| log.level == level.to_s.upcase }
|
||||||
|
end
|
||||||
|
|
||||||
|
def expected_errors
|
||||||
|
Regexp.union([
|
||||||
|
%r{Refused to apply style from 'http:.*/gollum/create/custom.css'}
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_only_expected_errors(log)
|
||||||
|
assert_equal [], log.reject {|err| err.message.match?(expected_errors) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'Frontend with mathjax' do
|
||||||
|
include Capybara::DSL
|
||||||
|
|
||||||
|
setup do
|
||||||
|
@path = cloned_testpath("examples/lotr.git")
|
||||||
|
@wiki = Gollum::Wiki.new(@path)
|
||||||
|
Precious::App.set(:gollum_path, @path)
|
||||||
|
Precious::App.set(:wiki_options, {mathjax: true})
|
||||||
|
Capybara.app = Precious::App
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'no unexpected errors on /' do
|
||||||
|
visit '/'
|
||||||
|
log = console_log(page)
|
||||||
|
assert_only_expected_errors(log)
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'no unexpected errors on /create/' do
|
||||||
|
visit '/create/Foobar'
|
||||||
|
log = console_log(page)
|
||||||
|
assert_only_expected_errors(log)
|
||||||
|
end
|
||||||
|
|
||||||
|
teardown do
|
||||||
|
Capybara.reset_sessions!
|
||||||
|
Capybara.use_default_driver
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
require_relative '../capybara_helper'
|
||||||
|
|
||||||
|
context 'Localized frontend' do
|
||||||
|
include Capybara::DSL
|
||||||
|
|
||||||
|
setup do
|
||||||
|
@path = cloned_testpath "examples/lotr.git"
|
||||||
|
@wiki = Gollum::Wiki.new(@path)
|
||||||
|
|
||||||
|
Precious::App.set :gollum_path, @path
|
||||||
|
Precious::App.set :wiki_options, {mathjax: true}
|
||||||
|
|
||||||
|
Capybara.app = Precious::App
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'can visit search results page' do
|
||||||
|
visit '/gollum/search'
|
||||||
|
|
||||||
|
fill_in('Search', with: 'something-to-return-no-results')
|
||||||
|
.native
|
||||||
|
.send_keys(:return)
|
||||||
|
|
||||||
|
assert_includes page.text,
|
||||||
|
'Search results for something-to-return-no-results'
|
||||||
|
assert_includes page.text,
|
||||||
|
'There are no results for your search something-to-return-no-results.'
|
||||||
|
|
||||||
|
click_on 'Back to Top'
|
||||||
|
|
||||||
|
visit '/gollum/search'
|
||||||
|
|
||||||
|
fill_in('Search', with: 'Bilbo').native.send_keys(:return)
|
||||||
|
|
||||||
|
assert_includes page.text, 'Search results for Bilbo'
|
||||||
|
|
||||||
|
click_on 'Show all hits on this page'
|
||||||
|
click_on 'Bilbo-Baggins.md'
|
||||||
|
|
||||||
|
assert page.current_path, '/Bilbo-Baggins.md'
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'can visit overview page' do
|
||||||
|
visit "/gollum/overview"
|
||||||
|
|
||||||
|
assert_includes page.text, 'Overview of master'
|
||||||
|
assert_includes page.text, 'Home'
|
||||||
|
|
||||||
|
click_on 'Back to Top'
|
||||||
|
click_on 'Bilbo-Baggins.md'
|
||||||
|
|
||||||
|
assert page.current_path, '/Bilbo-Baggins.md'
|
||||||
|
end
|
||||||
|
|
||||||
|
teardown do
|
||||||
|
@path = nil
|
||||||
|
@wiki = nil
|
||||||
|
|
||||||
|
Capybara.reset_sessions!
|
||||||
|
Capybara.use_default_driver
|
||||||
|
end
|
||||||
|
end
|
||||||
+54
-34
@@ -3,87 +3,107 @@ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
|||||||
|
|
||||||
context "Precious::Views::Editing" do
|
context "Precious::Views::Editing" do
|
||||||
include Rack::Test::Methods
|
include Rack::Test::Methods
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
@path = cloned_testpath('examples/revert.git')
|
@path = cloned_testpath('examples/revert.git')
|
||||||
Precious::App.set(:gollum_path, @path)
|
Precious::App.set(:gollum_path, @path)
|
||||||
|
Precious::App.set(:wiki_options, {allow_editing: true, allow_uploads: true})
|
||||||
@wiki = Gollum::Wiki.new(@path)
|
@wiki = Gollum::Wiki.new(@path)
|
||||||
end
|
end
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
|
Precious::App.set(:wiki_options, {allow_editing: true, allow_uploads: true})
|
||||||
FileUtils.rm_rf(@path)
|
FileUtils.rm_rf(@path)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "creating page is blocked" do
|
test 'creating pages is not blocked' do
|
||||||
Precious::App.set(:wiki_options, { allow_editing: false})
|
post '/gollum/create',
|
||||||
post "/gollum/create", :content => 'abc', :page => "D",
|
content: 'abc',
|
||||||
:format => 'markdown', :message => 'def'
|
format: 'markdown',
|
||||||
assert !last_response.ok?
|
message: 'def',
|
||||||
|
page: 'D'
|
||||||
|
|
||||||
page = @wiki.page('D')
|
assert_equal last_response.status, 302
|
||||||
assert page.nil?
|
|
||||||
|
refute_nil @wiki.page('D')
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'creating pages is blocked' do
|
||||||
|
Precious::App.set(:wiki_options, {allow_editing: false, allow_uploads: false})
|
||||||
|
|
||||||
|
post '/gollum/create',
|
||||||
|
content: 'abc',
|
||||||
|
format: 'markdown',
|
||||||
|
message: 'def',
|
||||||
|
page: 'D'
|
||||||
|
|
||||||
|
assert last_response.body.include? 'Forbidden. This wiki is set to no-edit mode.'
|
||||||
|
|
||||||
|
refute last_response.ok?
|
||||||
|
|
||||||
|
assert_nil @wiki.page('D')
|
||||||
end
|
end
|
||||||
|
|
||||||
test ".redirects.gollum file should not be accessible" do
|
test ".redirects.gollum file should not be accessible" do
|
||||||
Precious::App.set(:wiki_options, { allow_editing: true, allow_uploads: true })
|
|
||||||
get '/.redirects.gollum'
|
get '/.redirects.gollum'
|
||||||
assert_match /Accessing this resource is not allowed/, last_response.body
|
assert_match /Accessing this resource is not allowed/, last_response.body
|
||||||
end
|
end
|
||||||
|
|
||||||
test ".redirects.gollum file should not be editable" do
|
test ".redirects.gollum file should not be editable" do
|
||||||
Precious::App.set(:wiki_options, { allow_editing: true, allow_uploads: true })
|
|
||||||
get '/gollum/edit/.redirects.gollum'
|
get '/gollum/edit/.redirects.gollum'
|
||||||
assert_match /Changing this resource is not allowed/, last_response.body
|
assert_match /Changing this resource is not allowed/, last_response.body
|
||||||
end
|
end
|
||||||
|
|
||||||
test "frontend links for editing are not blocked" do
|
test "frontend links for editing are not blocked" do
|
||||||
Precious::App.set(:wiki_options, { allow_editing: true, allow_uploads: true })
|
|
||||||
get '/A'
|
get '/A'
|
||||||
|
|
||||||
assert_match /Delete this Page/, last_response.body, "'Delete this Page' link is blocked in page template"
|
assert last_response.body.include? "Delete this Page"
|
||||||
assert_match /New/, last_response.body, "'New' button is blocked in page template"
|
assert last_response.body.include? "New"
|
||||||
assert_match /Upload\b/, last_response.body, "'Upload' link is blocked in page template"
|
assert last_response.body.include? "<span>Upload</span>"
|
||||||
assert_match /Rename/, last_response.body, "'Rename' link is blocked in page template"
|
assert last_response.body.include? "Rename"
|
||||||
assert_match /Edit/, last_response.body, "'Edit' link is blocked in page template"
|
assert last_response.body.include? "Edit"
|
||||||
|
|
||||||
get '/gollum/overview'
|
get '/gollum/overview'
|
||||||
|
|
||||||
assert_match /New/, last_response.body, "'New' link is blocked in pages template"
|
assert last_response.body.include? "New"
|
||||||
|
|
||||||
get '/gollum/history/A'
|
get '/gollum/history/A'
|
||||||
|
|
||||||
assert_no_match /Edit/, last_response.body, "'Edit' link is not blocked in history template"
|
refute last_response.body.include? "Edit"
|
||||||
|
|
||||||
get '/gollum/compare/A/fc66539528eb96f21b2bbdbf557788fe8a1196ac..b26b791cb7917c4f37dd9cb4d1e0efb24ac4d26f'
|
get '/gollum/compare/A/fc665395..b26b791c'
|
||||||
|
|
||||||
assert_no_match /Edit Page/, last_response.body, "'Edit Page' link is not blocked in compare template"
|
refute last_response.body.include? "Edit Page"
|
||||||
assert_match /Revert Changes/, last_response.body, "'Revert Changes' link is blocked in compare template"
|
|
||||||
|
assert last_response.body.include? "Revert Changes"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "frontend links for editing blocked" do
|
test "frontend links for editing blocked" do
|
||||||
Precious::App.set(:wiki_options, { allow_editing: false })
|
Precious::App.set(:wiki_options, {allow_editing: false, allow_uploads: false})
|
||||||
|
|
||||||
get '/A'
|
get '/A'
|
||||||
|
|
||||||
assert_no_match /Delete this Page/, last_response.body, "'Delete this Page' link not blocked in page template"
|
refute last_response.body.include? "Delete this Page"
|
||||||
assert_no_match /New/, last_response.body, "'New' button not blocked in page template"
|
refute last_response.body.include? "<span>Upload</span>"
|
||||||
assert_no_match /Upload\b/, last_response.body, "'Upload' link not blocked in page template"
|
refute last_response.body.include? "Rename"
|
||||||
assert_no_match /Rename/, last_response.body, "'Rename' link not blocked in page template"
|
refute last_response.body.include? "Edit"
|
||||||
assert_no_match /Edit/, last_response.body, "'Edit' link not blocked in page template"
|
refute last_response.body.include? "New"
|
||||||
|
|
||||||
get '/gollum/overview'
|
get '/gollum/overview'
|
||||||
|
|
||||||
assert_no_match /New/, last_response.body, "'New' link not blocked in pages template"
|
refute last_response.body.include? "New"
|
||||||
|
|
||||||
get '/gollum/history/A'
|
get '/gollum/history/A'
|
||||||
|
|
||||||
assert_no_match /Edit/, last_response.body, "'Edit' link not blocked in history template"
|
refute last_response.body.include? "Edit"
|
||||||
|
|
||||||
get '/gollum/compare/A/fc66539528eb96f21b2bbdbf557788fe8a1196ac..b26b791cb7917c4f37dd9cb4d1e0efb24ac4d26f'
|
get '/gollum/compare/A/fc665395..b26b791c'
|
||||||
|
|
||||||
assert_no_match /Edit Page/, last_response.body, "'Edit Page' link not blocked in compare template"
|
refute last_response.body.include? "Edit Page"
|
||||||
assert_no_match /Revert Changes/, last_response.body, "'Revert Changes' link not blocked in compare template"
|
refute last_response.body.include? "Revert Changes"
|
||||||
end
|
end
|
||||||
|
|
||||||
def app
|
def app
|
||||||
Precious::App
|
Precious::App
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+254
-81
@@ -14,7 +14,7 @@ context "Frontend" do
|
|||||||
teardown do
|
teardown do
|
||||||
FileUtils.rm_rf(@path)
|
FileUtils.rm_rf(@path)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "utf-8 kcode" do
|
test "utf-8 kcode" do
|
||||||
assert_equal 'μ†ℱ'.scan(/./), ["μ", "†", "ℱ"]
|
assert_equal 'μ†ℱ'.scan(/./), ["μ", "†", "ℱ"]
|
||||||
end
|
end
|
||||||
@@ -39,44 +39,34 @@ context "Frontend" do
|
|||||||
assert_match /<pre><code>one\ntwo\nthree\nfour\n<\/code><\/pre>\n/m, last_response.body
|
assert_match /<pre><code>one\ntwo\nthree\nfour\n<\/code><\/pre>\n/m, last_response.body
|
||||||
end
|
end
|
||||||
|
|
||||||
def nfd utf8
|
|
||||||
TwitterCldr::Normalization.normalize(utf8, using: :nfd)
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'mathjax assets are served' do
|
test 'mathjax assets are served' do
|
||||||
get '/gollum/assets/mathjax/MathJax.js'
|
get '/gollum/assets/mathjax/MathJax.js'
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
end
|
end
|
||||||
|
|
||||||
test "UTF-8 headers href preserved" do
|
test "UTF-8 headers href preserved" do
|
||||||
page = 'utfh1'
|
page_content = <<~TEXT
|
||||||
text = nfd('한글')
|
## 한글
|
||||||
|
|
||||||
# don't use h1 or it will be promoted to replace file name
|
Test page "utfh1" content.
|
||||||
# which doesn't generate a normal header link
|
TEXT
|
||||||
@wiki.write_page(page, :markdown, '## ' + text,
|
|
||||||
{ :name => 'user1', :email => 'user1' });
|
|
||||||
|
|
||||||
get page
|
@wiki.write_page('utfh1',
|
||||||
expected = "<h2 class=\"editable\"><a class=\"anchor\" (href|id)=\"(#)?#{text}\" (href|id)=\"(#)?#{text}\"></a>#{text}</h2>"
|
:markdown,
|
||||||
actual = nfd(last_response.body)
|
page_content,
|
||||||
|
{name: 'user1', email: 'user1'})
|
||||||
|
|
||||||
assert_match /#{expected}/, actual
|
get 'utfh1'
|
||||||
|
expected = "<h2 class=\"editable\"><a class=\"anchor\" (href|id)=\"(#)?한글\" (href|id)=\"(#)?한글\"></a>한글</h2>"
|
||||||
|
|
||||||
|
assert_match /#{expected}/, last_response.body
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'rss feed' do
|
test 'rss feed' do
|
||||||
channel_title = <<EOF
|
|
||||||
<title>Gollum Wiki Latest Changes</title>
|
|
||||||
EOF
|
|
||||||
item = <<EOF
|
|
||||||
<description>Commited by: <a href="mailto:dawa.ometto@phil.uu.nl">Dawa Ometto</a><br/>Commit ID: 02796b1<br/><br/>Affected files:<ul><li><a href="http://example.org/custom.css/02796b1450691f90db5d6dc6a816a4980ce80d07">custom.css</a></li><li><a href="http://example.org/custom.js/02796b1450691f90db5d6dc6a816a4980ce80d07">custom.js</a></li></ul></description>
|
|
||||||
EOF
|
|
||||||
get '/gollum/feed/'
|
get '/gollum/feed/'
|
||||||
|
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
assert_equal 'application/rss+xml', last_response.headers['Content-Type']
|
assert_equal 'application/rss+xml', last_response.headers['Content-Type']
|
||||||
assert last_response.body.start_with?('<?xml')
|
|
||||||
assert last_response.body.include?(item)
|
|
||||||
assert last_response.body.include?(channel_title)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "show sidebar, header, footer when present" do
|
test "show sidebar, header, footer when present" do
|
||||||
@@ -106,24 +96,24 @@ EOF
|
|||||||
page_2 = @wiki.page(page_1.name)
|
page_2 = @wiki.page(page_1.name)
|
||||||
assert_equal 'abc', page_2.raw_data
|
assert_equal 'abc', page_2.raw_data
|
||||||
assert_equal 'def', page_2.version.message
|
assert_equal 'def', page_2.version.message
|
||||||
assert_not_equal page_1.version.sha, page_2.version.sha
|
refute_equal page_1.version.sha, page_2.version.sha
|
||||||
end
|
end
|
||||||
|
|
||||||
test "edit page fails when page is outdated (edit collision)" do
|
test "edit page fails when page is outdated (edit collision)" do
|
||||||
page = @wiki.page('A')
|
page = @wiki.page('A')
|
||||||
old_sha = page.sha
|
old_sha = page.sha
|
||||||
post "/gollum/edit/A", :content => 'abc', :page => 'A',
|
post "/gollum/edit/A", :content => 'abc', :page => 'A',
|
||||||
:format => page.format, :message => 'def', :etag => old_sha
|
:format => page.format, :message => 'def', :etag => old_sha
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
|
|
||||||
@wiki.clear_cache
|
@wiki.clear_cache
|
||||||
page = @wiki.page('A')
|
page = @wiki.page('A')
|
||||||
new_sha = page.sha
|
new_sha = page.sha
|
||||||
assert_not_equal old_sha, new_sha
|
refute_equal old_sha, new_sha
|
||||||
|
|
||||||
post "/gollum/edit/A", :content => 'def', :page => 'A',
|
post "/gollum/edit/A", :content => 'def', :page => 'A',
|
||||||
:format => page.format, :message => 'def', :etag => old_sha
|
:format => page.format, :message => 'def', :etag => old_sha
|
||||||
assert_equal last_response.status, 412
|
assert_equal last_response.status, 412
|
||||||
end
|
end
|
||||||
|
|
||||||
test "edit page with empty message" do
|
test "edit page with empty message" do
|
||||||
@@ -136,7 +126,7 @@ EOF
|
|||||||
page_2 = @wiki.page(page_1.name)
|
page_2 = @wiki.page(page_1.name)
|
||||||
assert_equal 'abc', page_2.raw_data
|
assert_equal 'abc', page_2.raw_data
|
||||||
assert_equal '[no message]', page_2.version.message
|
assert_equal '[no message]', page_2.version.message
|
||||||
assert_not_equal page_1.version.sha, page_2.version.sha
|
refute_equal page_1.version.sha, page_2.version.sha
|
||||||
end
|
end
|
||||||
|
|
||||||
test "edit page with slash" do
|
test "edit page with slash" do
|
||||||
@@ -167,13 +157,13 @@ EOF
|
|||||||
assert_equal 'header', header_2.raw_data
|
assert_equal 'header', header_2.raw_data
|
||||||
assert_equal 'footer', foot_2.raw_data
|
assert_equal 'footer', foot_2.raw_data
|
||||||
assert_equal 'def', foot_2.version.message
|
assert_equal 'def', foot_2.version.message
|
||||||
assert_not_equal foot_1.version.sha, foot_2.version.sha
|
refute_equal foot_1.version.sha, foot_2.version.sha
|
||||||
assert_not_equal header_1.version.sha, header_2.version.sha
|
refute_equal header_1.version.sha, header_2.version.sha
|
||||||
|
|
||||||
assert_equal 'sidebar', side_2.raw_data
|
assert_equal 'sidebar', side_2.raw_data
|
||||||
assert_equal 'def', side_2.version.message
|
assert_equal 'def', side_2.version.message
|
||||||
assert_not_equal side_1.version.sha, side_2.version.sha
|
refute_equal side_1.version.sha, side_2.version.sha
|
||||||
assert_equal commits+1, @wiki.repo.commits('master').size
|
assert_equal commits, @wiki.repo.commits('master').size
|
||||||
end
|
end
|
||||||
|
|
||||||
test "renames page" do
|
test "renames page" do
|
||||||
@@ -189,7 +179,7 @@ EOF
|
|||||||
page_2 = @wiki.page('C')
|
page_2 = @wiki.page('C')
|
||||||
assert_equal "INITIAL\n\nSPAM2\n", page_2.raw_data
|
assert_equal "INITIAL\n\nSPAM2\n", page_2.raw_data
|
||||||
assert_equal 'def', page_2.last_version.message
|
assert_equal 'def', page_2.last_version.message
|
||||||
assert_not_equal page_1.version.sha, page_2.version.sha
|
refute_equal page_1.version.sha, page_2.version.sha
|
||||||
end
|
end
|
||||||
|
|
||||||
test "rename preserves format" do
|
test "rename preserves format" do
|
||||||
@@ -224,7 +214,7 @@ EOF
|
|||||||
|
|
||||||
test "renames page in subdirectory" do
|
test "renames page in subdirectory" do
|
||||||
page_1 = @wiki.page("G/H")
|
page_1 = @wiki.page("G/H")
|
||||||
assert_not_equal page_1, nil
|
refute_equal page_1, nil
|
||||||
post "/gollum/rename/G/H", :rename => "/I/C", :message => 'def'
|
post "/gollum/rename/G/H", :rename => "/I/C", :message => 'def'
|
||||||
|
|
||||||
follow_redirect!
|
follow_redirect!
|
||||||
@@ -236,12 +226,12 @@ EOF
|
|||||||
page_2 = @wiki.page('I/C')
|
page_2 = @wiki.page('I/C')
|
||||||
assert_equal "INITIAL\n\nSPAM2\n", page_2.raw_data
|
assert_equal "INITIAL\n\nSPAM2\n", page_2.raw_data
|
||||||
assert_equal 'def', page_2.last_version.message
|
assert_equal 'def', page_2.last_version.message
|
||||||
assert_not_equal page_1.version.sha, page_2.version.sha
|
refute_equal page_1.version.sha, page_2.version.sha
|
||||||
end
|
end
|
||||||
|
|
||||||
test "renames page relative in subdirectory" do
|
test "renames page relative in subdirectory" do
|
||||||
page_1 = @wiki.page("G/H")
|
page_1 = @wiki.page("G/H")
|
||||||
assert_not_equal page_1, nil
|
refute_equal page_1, nil
|
||||||
post "/gollum/rename/G/H", :rename => "K/C", :message => 'def'
|
post "/gollum/rename/G/H", :rename => "K/C", :message => 'def'
|
||||||
|
|
||||||
follow_redirect!
|
follow_redirect!
|
||||||
@@ -253,7 +243,7 @@ EOF
|
|||||||
page_2 = @wiki.page('G/K/C')
|
page_2 = @wiki.page('G/K/C')
|
||||||
assert_equal "INITIAL\n\nSPAM2\n", page_2.raw_data
|
assert_equal "INITIAL\n\nSPAM2\n", page_2.raw_data
|
||||||
assert_equal 'def', page_2.last_version.message
|
assert_equal 'def', page_2.last_version.message
|
||||||
assert_not_equal page_1.version.sha, page_2.version.sha
|
refute_equal page_1.version.sha, page_2.version.sha
|
||||||
end
|
end
|
||||||
|
|
||||||
test "creates page" do
|
test "creates page" do
|
||||||
@@ -322,7 +312,7 @@ EOF
|
|||||||
name = "#{dir}/bar"
|
name = "#{dir}/bar"
|
||||||
get "/gollum/create/#{name}"
|
get "/gollum/create/#{name}"
|
||||||
assert_match(/\/#{dir}/, last_response.body)
|
assert_match(/\/#{dir}/, last_response.body)
|
||||||
assert_no_match(/[^\/]#{dir}/, last_response.body)
|
refute_match(/[^\/]#{dir}/, last_response.body)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "create with template succeed if template exists" do
|
test "create with template succeed if template exists" do
|
||||||
@@ -330,9 +320,9 @@ EOF
|
|||||||
page='_Template'
|
page='_Template'
|
||||||
post '/gollum/create', :content => 'fake template with some Utf-8: Ü', :page => page,
|
post '/gollum/create', :content => 'fake template with some Utf-8: Ü', :page => page,
|
||||||
:path => '/', :format => 'markdown', :message => ''
|
:path => '/', :format => 'markdown', :message => ''
|
||||||
follow_redirect!
|
follow_redirect!
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
@wiki.clear_cache
|
@wiki.clear_cache
|
||||||
get "/gollum/create/TT"
|
get "/gollum/create/TT"
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
post '/gollum/delete/_Template'
|
post '/gollum/delete/_Template'
|
||||||
@@ -340,12 +330,51 @@ EOF
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "create with template succeed if template doesn't exist" do
|
test "create with template succeed if template doesn't exist" do
|
||||||
Precious::App.set(:wiki_options, { :template_page => true })
|
Precious::App.set(:wiki_options, { :template_page => true })
|
||||||
get "/gollum/create/TT"
|
get "/gollum/create/TT"
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
Precious::App.set(:wiki_options, { :template_page => false })
|
Precious::App.set(:wiki_options, { :template_page => false })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "create with template filter without parameter" do
|
||||||
|
Precious::App.set(:wiki_options, { :template_page => true })
|
||||||
|
|
||||||
|
# arrange
|
||||||
|
now = Time.parse('2022-04-16')
|
||||||
|
Gollum::TemplateFilter.add_filter("{{today}}", & -> () { now.strftime("%Y-%m-%d") })
|
||||||
|
template_content = "# Daily Log, {{today}}"
|
||||||
|
|
||||||
|
@wiki.write_page("daily-logs/_Template",
|
||||||
|
:markdown,
|
||||||
|
template_content)
|
||||||
|
# act
|
||||||
|
get "/gollum/create/daily-logs/test"
|
||||||
|
# assert
|
||||||
|
assert last_response.ok?
|
||||||
|
assert_match("# Daily Log, 2022-04-16", last_response.body)
|
||||||
|
|
||||||
|
Precious::App.set(:wiki_options, { :template_page => false })
|
||||||
|
end
|
||||||
|
|
||||||
|
test "create with template filter with parameter" do
|
||||||
|
Precious::App.set(:wiki_options, { :template_page => true })
|
||||||
|
|
||||||
|
# arrange
|
||||||
|
Gollum::TemplateFilter.add_filter("{{page_name}}", & -> (page) { page.name })
|
||||||
|
template_content = "# Daily Log, {{page_name}}"
|
||||||
|
|
||||||
|
@wiki.write_page("daily-logs/_Template",
|
||||||
|
:markdown,
|
||||||
|
template_content)
|
||||||
|
# act
|
||||||
|
get "/gollum/create/daily-logs/2022-04-16"
|
||||||
|
# assert
|
||||||
|
assert last_response.ok?
|
||||||
|
assert_match("# Daily Log, 2022-04-16", last_response.body)
|
||||||
|
|
||||||
|
Precious::App.set(:wiki_options, { :template_page => false })
|
||||||
|
end
|
||||||
|
|
||||||
test "edit returns nil for non-existant page" do
|
test "edit returns nil for non-existant page" do
|
||||||
# post '/edit' fails. post '/edit/' works.
|
# post '/edit' fails. post '/edit/' works.
|
||||||
page = 'not-real-page'
|
page = 'not-real-page'
|
||||||
@@ -353,7 +382,7 @@ EOF
|
|||||||
post '/gollum/edit/', :content => 'edit_msg',
|
post '/gollum/edit/', :content => 'edit_msg',
|
||||||
:page => page, :path => path, :message => ''
|
:page => page, :path => path, :message => ''
|
||||||
page_e = @wiki.page(::File.join(path,page))
|
page_e = @wiki.page(::File.join(path,page))
|
||||||
assert_equal nil, page_e
|
assert_nil page_e
|
||||||
end
|
end
|
||||||
|
|
||||||
test "edit allows changing format" do
|
test "edit allows changing format" do
|
||||||
@@ -409,23 +438,31 @@ EOF
|
|||||||
|
|
||||||
@wiki.clear_cache
|
@wiki.clear_cache
|
||||||
page = @wiki.page(name)
|
page = @wiki.page(name)
|
||||||
assert_not_equal 'abc', page.raw_data
|
refute_equal 'abc', page.raw_data
|
||||||
end
|
end
|
||||||
|
|
||||||
test "uploading is not allowed unless explicitly enabled" do
|
test "uploading is not allowed unless explicitly enabled" do
|
||||||
temp_upload_file = Tempfile.new(['upload', '.file']) << 'abc'
|
temp_upload_file = Tempfile.new(['upload', '.file']) << 'abc'
|
||||||
temp_upload_file.close
|
temp_upload_file.close
|
||||||
post "/gollum/upload_file", :file => Rack::Test::UploadedFile.new(::File.open(temp_upload_file))
|
|
||||||
|
Precious::App.set(
|
||||||
|
:wiki_options,
|
||||||
|
{allow_uploads: false, per_page_uploads: false}
|
||||||
|
)
|
||||||
|
|
||||||
|
post '/gollum/upload_file',
|
||||||
|
file: Rack::Test::UploadedFile.new(File.open(temp_upload_file))
|
||||||
|
|
||||||
assert_equal 405, last_response.status
|
assert_equal 405, last_response.status
|
||||||
end
|
end
|
||||||
|
|
||||||
test "upload a file with mode dir" do
|
test "upload a file with mode dir" do
|
||||||
temp_upload_file = Tempfile.new(['upload', '.file']) << 'abc'
|
temp_upload_file = Tempfile.new(['upload', '.file']) << 'abc'
|
||||||
temp_upload_file.close
|
temp_upload_file.close
|
||||||
Precious::App.set(:wiki_options, {allow_uploads: true})
|
Precious::App.set(:wiki_options, {allow_uploads: true})
|
||||||
|
|
||||||
post "/gollum/upload_file", :file => Rack::Test::UploadedFile.new(::File.open(temp_upload_file))
|
post "/gollum/upload_file", :file => Rack::Test::UploadedFile.new(::File.open(temp_upload_file))
|
||||||
|
|
||||||
assert_equal 302, last_response.status # redirect is expected
|
assert_equal 302, last_response.status # redirect is expected
|
||||||
@wiki.clear_cache
|
@wiki.clear_cache
|
||||||
file = @wiki.file("uploads/#{::File.basename(temp_upload_file.path)}")
|
file = @wiki.file("uploads/#{::File.basename(temp_upload_file.path)}")
|
||||||
@@ -434,11 +471,53 @@ EOF
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "upload a file with mode page" do
|
test "upload a file with mode page" do
|
||||||
temp_upload_file = Tempfile.new(['upload', '.file']) << 'abc'
|
temp_upload_file = Tempfile.new(['upload', '.file']) << "abc\r"
|
||||||
temp_upload_file.close
|
temp_upload_file.close
|
||||||
Precious::App.set(:wiki_options, {allow_uploads: true, per_page_uploads: true})
|
Precious::App.set(:wiki_options, {allow_uploads: true, per_page_uploads: true})
|
||||||
post "/gollum/upload_file", {:file => Rack::Test::UploadedFile.new(::File.open(temp_upload_file))}, {'HTTP_REFERER' => 'http://localhost:4567/Home.md', 'HTTP_HOST' => 'localhost:4567'}
|
post "/gollum/upload_file", {:file => Rack::Test::UploadedFile.new(::File.open(temp_upload_file))}, {'HTTP_REFERER' => 'http://localhost:4567/Home.md', 'HTTP_HOST' => 'localhost:4567'}
|
||||||
|
|
||||||
|
assert_equal 302, last_response.status # redirect is expected
|
||||||
|
@wiki.clear_cache
|
||||||
|
# Find the file in a page-specific subdir (here: Home), based on referer
|
||||||
|
file = @wiki.file("uploads/Home/#{::File.basename(temp_upload_file.path)}")
|
||||||
|
assert_equal "abc\r", file.raw_data
|
||||||
|
Precious::App.set(:wiki_options, {allow_uploads: false, per_page_uploads: false})
|
||||||
|
end
|
||||||
|
|
||||||
|
test "upload a file with valid extension" do
|
||||||
|
temp_upload_file = Tempfile.new(['upload', '.txt']) << "abc\r"
|
||||||
|
temp_upload_file.close
|
||||||
|
Precious::App.set(:wiki_options, {allow_uploads: true, per_page_uploads: true})
|
||||||
|
post "/gollum/upload_file", {:file => Rack::Test::UploadedFile.new(::File.open(temp_upload_file))}, {'HTTP_REFERER' => 'http://localhost:4567/Home.md', 'HTTP_HOST' => 'localhost:4567'}
|
||||||
|
|
||||||
|
assert_equal 302, last_response.status # redirect is expected
|
||||||
|
@wiki.clear_cache
|
||||||
|
# Find the file in a page-specific subdir (here: Home), based on referer
|
||||||
|
file = @wiki.file("uploads/Home/#{::File.basename(temp_upload_file.path)}")
|
||||||
|
assert_equal "abc", file.raw_data
|
||||||
|
Precious::App.set(:wiki_options, {allow_uploads: false, per_page_uploads: false})
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'upload a file with mode page from the edit page (drag and drop)' do
|
||||||
|
temp_upload_file = Tempfile.new(['upload', '.file']) << "abc\r"
|
||||||
|
temp_upload_file.close
|
||||||
|
Precious::App.set(:wiki_options, {allow_uploads: true, per_page_uploads: true})
|
||||||
|
post "/gollum/upload_file", {:file => Rack::Test::UploadedFile.new(::File.open(temp_upload_file))}, {'HTTP_REFERER' => 'http://localhost:4567/gollum/edit/foo/Bar.md', 'HTTP_HOST' => 'localhost:4567'}
|
||||||
|
|
||||||
|
assert_equal 302, last_response.status # redirect is expected
|
||||||
|
@wiki.clear_cache
|
||||||
|
# Find the file in a page-specific subdir (here: foo/Bar), based on referer
|
||||||
|
file = @wiki.file("uploads/foo/Bar/#{::File.basename(temp_upload_file.path)}")
|
||||||
|
assert_equal "abc\r", file.raw_data
|
||||||
|
Precious::App.set(:wiki_options, {allow_uploads: false, per_page_uploads: false})
|
||||||
|
end
|
||||||
|
|
||||||
|
test "upload a file with https referer" do
|
||||||
|
temp_upload_file = Tempfile.new(['https_upload', '.file']) << 'abc'
|
||||||
|
temp_upload_file.close
|
||||||
|
Precious::App.set(:wiki_options, {allow_uploads: true, per_page_uploads: true})
|
||||||
|
post "/gollum/upload_file", {:file => Rack::Test::UploadedFile.new(::File.open(temp_upload_file))}, {'HTTP_REFERER' => 'https://localhost:4567/Home.md', 'HTTP_HOST' => 'localhost:4567'}
|
||||||
|
|
||||||
assert_equal 302, last_response.status # redirect is expected
|
assert_equal 302, last_response.status # redirect is expected
|
||||||
@wiki.clear_cache
|
@wiki.clear_cache
|
||||||
# Find the file in a page-specific subdir (here: Home), based on referer
|
# Find the file in a page-specific subdir (here: Home), based on referer
|
||||||
@@ -446,7 +525,7 @@ EOF
|
|||||||
assert_equal 'abc', file.raw_data
|
assert_equal 'abc', file.raw_data
|
||||||
Precious::App.set(:wiki_options, {allow_uploads: false, per_page_uploads: false})
|
Precious::App.set(:wiki_options, {allow_uploads: false, per_page_uploads: false})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "guard against uploading an existing file" do
|
test "guard against uploading an existing file" do
|
||||||
temp_upload_file = Tempfile.new(['upload', '.file']) << 'abc'
|
temp_upload_file = Tempfile.new(['upload', '.file']) << 'abc'
|
||||||
temp_upload_file.close
|
temp_upload_file.close
|
||||||
@@ -458,7 +537,7 @@ EOF
|
|||||||
assert_equal 409, last_response.status
|
assert_equal 409, last_response.status
|
||||||
Precious::App.set(:wiki_options, {allow_uploads: false})
|
Precious::App.set(:wiki_options, {allow_uploads: false})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "delete a page" do
|
test "delete a page" do
|
||||||
name = "deleteme"
|
name = "deleteme"
|
||||||
post "/gollum/create", :content => 'abc', :page => name,
|
post "/gollum/create", :content => 'abc', :page => name,
|
||||||
@@ -470,15 +549,15 @@ EOF
|
|||||||
|
|
||||||
@wiki.clear_cache
|
@wiki.clear_cache
|
||||||
page = @wiki.page(name)
|
page = @wiki.page(name)
|
||||||
assert_equal nil, page
|
assert_nil page
|
||||||
end
|
end
|
||||||
|
|
||||||
test "previews content" do
|
test "previews content" do
|
||||||
post "/gollum/preview", :content => 'abc', :format => 'markdown', :page => 'Samewise Gamgee.mediawiki'
|
post "/gollum/preview", :content => 'abc', :format => 'markdown', :page => 'Samewise Gamgee.mediawiki'
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
assert last_response.body.include?('Samewise Gamgee</h1>')
|
assert last_response.body.include?('Samewise Gamgee')
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'throws an error when comparing two identical revisions for a page' do
|
test 'throws an error when comparing two identical revisions for a page' do
|
||||||
get '/gollum/compare/A.md/fc66539528eb96f21b2bbdbf557788fe8a1196ac...fc66539528eb96f21b2bbdbf557788fe8a1196ac'
|
get '/gollum/compare/A.md/fc66539528eb96f21b2bbdbf557788fe8a1196ac...fc66539528eb96f21b2bbdbf557788fe8a1196ac'
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
@@ -494,7 +573,7 @@ EOF
|
|||||||
|
|
||||||
@wiki.clear_cache
|
@wiki.clear_cache
|
||||||
page2 = @wiki.page('B')
|
page2 = @wiki.page('B')
|
||||||
assert_not_equal page1.version.sha, page2.version.sha
|
refute_equal page1.version.sha, page2.version.sha
|
||||||
assert_equal "INITIAL", page2.raw_data.strip
|
assert_equal "INITIAL", page2.raw_data.strip
|
||||||
assert_equal "Revert commit 7c45b5f", page2.version.message
|
assert_equal "Revert commit 7c45b5f", page2.version.message
|
||||||
end
|
end
|
||||||
@@ -508,7 +587,7 @@ EOF
|
|||||||
|
|
||||||
@wiki.clear_cache
|
@wiki.clear_cache
|
||||||
page2 = @wiki.page('A')
|
page2 = @wiki.page('A')
|
||||||
assert_not_equal page1.version.sha, page2.version.sha
|
refute_equal page1.version.sha, page2.version.sha
|
||||||
assert_equal "INITIAL", page2.raw_data.strip
|
assert_equal "INITIAL", page2.raw_data.strip
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -522,7 +601,7 @@ EOF
|
|||||||
page2 = @wiki.page('A')
|
page2 = @wiki.page('A')
|
||||||
assert_equal page1.version.sha, page2.version.sha
|
assert_equal page1.version.sha, page2.version.sha
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
# redirects are now handled by class MapGollum in bin/gollum
|
# redirects are now handled by class MapGollum in bin/gollum
|
||||||
# they should be set in config.ru
|
# they should be set in config.ru
|
||||||
@@ -570,7 +649,7 @@ EOF
|
|||||||
{ :name => 'user1', :email => 'user1' });
|
{ :name => 'user1', :email => 'user1' });
|
||||||
|
|
||||||
get page
|
get page
|
||||||
assert_no_match /custom.js/, last_response.body
|
refute_match /custom.js/, last_response.body
|
||||||
end
|
end
|
||||||
|
|
||||||
test "add custom.js if setting" do
|
test "add custom.js if setting" do
|
||||||
@@ -588,7 +667,7 @@ EOF
|
|||||||
|
|
||||||
test "don't allow changing custom js or css" do
|
test "don't allow changing custom js or css" do
|
||||||
Precious::App.set(:wiki_options, { :js => true, :css => true })
|
Precious::App.set(:wiki_options, { :js => true, :css => true })
|
||||||
|
|
||||||
['create', 'edit'].each do |route|
|
['create', 'edit'].each do |route|
|
||||||
['.css', '.js'].each do |ext|
|
['.css', '.js'].each do |ext|
|
||||||
get "/gollum/#{route}/custom#{ext}"
|
get "/gollum/#{route}/custom#{ext}"
|
||||||
@@ -621,7 +700,7 @@ EOF
|
|||||||
:page => 'Multibyte', :format => :markdown, :message => 'mesg'
|
:page => 'Multibyte', :format => :markdown, :message => 'mesg'
|
||||||
|
|
||||||
page = @wiki.page('Multibyte')
|
page = @wiki.page('Multibyte')
|
||||||
|
|
||||||
post "/gollum/edit/Multibyte",
|
post "/gollum/edit/Multibyte",
|
||||||
:content => 'りんご', :header => 'みかん', :footer => 'バナナ', :sidebar => 'スイカ',
|
:content => 'りんご', :header => 'みかん', :footer => 'バナナ', :sidebar => 'スイカ',
|
||||||
:page => 'Multibyte', :format => :markdown, :message => 'mesg', :etag => page.sha
|
:page => 'Multibyte', :format => :markdown, :message => 'mesg', :etag => page.sha
|
||||||
@@ -639,7 +718,7 @@ EOF
|
|||||||
get "A"
|
get "A"
|
||||||
|
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
assert_no_match /meta name="robots" content="noindex, nofollow"/, last_response.body
|
refute_match /meta name="robots" content="noindex, nofollow"/, last_response.body
|
||||||
|
|
||||||
get "A/fc66539528eb96f21b2bbdbf557788fe8a1196ac"
|
get "A/fc66539528eb96f21b2bbdbf557788fe8a1196ac"
|
||||||
|
|
||||||
@@ -655,6 +734,13 @@ EOF
|
|||||||
assert_equal last_response.status, 302
|
assert_equal last_response.status, 302
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "view deleted page in history" do
|
||||||
|
get 'C/db8b297cf5a31b46ac24500edfdbd0d3d8eed4eb'
|
||||||
|
|
||||||
|
assert last_response.ok?
|
||||||
|
assert_match /This page will be deleted in the next commit :\(/, last_response.body
|
||||||
|
end
|
||||||
|
|
||||||
def app
|
def app
|
||||||
Precious::App
|
Precious::App
|
||||||
end
|
end
|
||||||
@@ -804,17 +890,17 @@ context "Frontend with lotr" do
|
|||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
assert_equal last_response.body.include?('delete-link'), false
|
assert_equal last_response.body.include?('delete-link'), false
|
||||||
assert_equal last_response.body.include?('page-info-toggle'), false
|
assert_equal last_response.body.include?('page-info-toggle'), false
|
||||||
assert last_response.body.include?('This version of the page was edited by <b>Tom Preston-Werner</b> at 2010-04-07')
|
assert_match %r{This version of the page was edited by <b>Tom Preston-Werner</b> at <time datetime="2010-04-07T19:49:43Z" data-format="%Y-%m-%d %H:%M:%S">\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}</time>.}, last_response.body
|
||||||
assert last_response.body.include?("<a href=\"/Bilbo-Baggins.md\">View the most recent version.</a></p>")
|
assert last_response.body.include?("<a href=\"/Bilbo-Baggins.md\">View the most recent version.</a></p>")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "show revision of specific file" do
|
test "show revision of specific file" do
|
||||||
old_sha = "df26e61e707116f81ebc6b935ec6d1676b7e96c4"
|
old_sha = "df26e61e707116f81ebc6b935ec6d1676b7e96c4"
|
||||||
update_sha = "f803c64d11407b23797325e3843f3f378b78f611"
|
update_sha = "f803c64d11407b23797325e3843f3f378b78f611"
|
||||||
|
|
||||||
get "Data.csv/#{old_sha}"
|
get "Data.csv/#{old_sha}"
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
assert_no_match /Samwise,Gamgee/, last_response.body
|
refute_match /Samwise,Gamgee/, last_response.body
|
||||||
|
|
||||||
get "Data.csv/#{update_sha}"
|
get "Data.csv/#{update_sha}"
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
@@ -859,7 +945,7 @@ context "Frontend with page-file-dir" do
|
|||||||
name = "#{dir}/baz"
|
name = "#{dir}/baz"
|
||||||
get "/gollum/create/#{name}"
|
get "/gollum/create/#{name}"
|
||||||
assert_match(/\/#{dir}/, last_response.body)
|
assert_match(/\/#{dir}/, last_response.body)
|
||||||
assert_no_match(/[^\/]#{dir}/, last_response.body)
|
refute_match(/[^\/]#{dir}/, last_response.body)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "use custom.css from page-file-dir path if page-file-dir is set" do
|
test "use custom.css from page-file-dir path if page-file-dir is set" do
|
||||||
@@ -900,7 +986,7 @@ end
|
|||||||
|
|
||||||
context "Frontend with empty repo" do
|
context "Frontend with empty repo" do
|
||||||
include Rack::Test::Methods
|
include Rack::Test::Methods
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
@path = cloned_testpath("examples/empty.git")
|
@path = cloned_testpath("examples/empty.git")
|
||||||
@wiki = Gollum::Wiki.new(@path)
|
@wiki = Gollum::Wiki.new(@path)
|
||||||
@@ -911,11 +997,11 @@ context "Frontend with empty repo" do
|
|||||||
teardown do
|
teardown do
|
||||||
FileUtils.rm_rf(@path)
|
FileUtils.rm_rf(@path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def app
|
def app
|
||||||
Precious::App
|
Precious::App
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'previews content on the first page of an empty wiki' do
|
test 'previews content on the first page of an empty wiki' do
|
||||||
post '/gollum/preview', :content => 'abc', :format => 'markdown'
|
post '/gollum/preview', :content => 'abc', :format => 'markdown'
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
@@ -927,12 +1013,12 @@ context "Frontend with empty repo" do
|
|||||||
assert_equal '/gollum/create/Home', last_request.fullpath
|
assert_equal '/gollum/create/Home', last_request.fullpath
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'Frontend with base path' do
|
context 'Frontend with base path' do
|
||||||
include Rack::Test::Methods
|
include Rack::Test::Methods
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
@path = cloned_testpath("examples/lotr.git")
|
@path = cloned_testpath("examples/lotr.git")
|
||||||
@wiki = Gollum::Wiki.new(@path)
|
@wiki = Gollum::Wiki.new(@path)
|
||||||
@@ -944,24 +1030,24 @@ context 'Frontend with base path' do
|
|||||||
teardown do
|
teardown do
|
||||||
FileUtils.rm_rf(@path)
|
FileUtils.rm_rf(@path)
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'page with base path' do
|
test 'page with base path' do
|
||||||
get '/wiki/Home'
|
get '/wiki/Home'
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'base path mathjax assets' do
|
test 'base path mathjax assets' do
|
||||||
get '/wiki/Home'
|
get '/wiki/Home'
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
assert last_response.body.include?('<script defer src="/wiki/gollum/assets/mathjax/MathJax.js?config=')
|
assert last_response.body.include?('<script defer src="/wiki/gollum/assets/mathjax/MathJax.js?config=')
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'compare view' do
|
test 'compare view' do
|
||||||
get '/wiki/gollum/compare/Bilbo-Baggins.md?versions[]=f25eccd98e9b667f9e22946f3e2f945378b8a72d&versions[]=5bc1aaec6149e854078f1d0f8b71933bbc6c2e43'
|
get '/wiki/gollum/compare/Bilbo-Baggins.md?versions[]=f25eccd98e9b667f9e22946f3e2f945378b8a72d&versions[]=5bc1aaec6149e854078f1d0f8b71933bbc6c2e43'
|
||||||
follow_redirect!
|
follow_redirect!
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
assert_equal '/wiki/gollum/compare/Bilbo-Baggins.md/5bc1aaec6149e854078f1d0f8b71933bbc6c2e43...f25eccd98e9b667f9e22946f3e2f945378b8a72d', last_request.fullpath
|
assert_equal '/wiki/gollum/compare/Bilbo-Baggins.md/5bc1aaec6149e854078f1d0f8b71933bbc6c2e43...f25eccd98e9b667f9e22946f3e2f945378b8a72d', last_request.fullpath
|
||||||
|
|
||||||
get '/wiki/gollum/compare/Bilbo-Baggins.md?versions[]=f25eccd98e9b667f9e22946f3e2f945378b8a72d'
|
get '/wiki/gollum/compare/Bilbo-Baggins.md?versions[]=f25eccd98e9b667f9e22946f3e2f945378b8a72d'
|
||||||
follow_redirect!
|
follow_redirect!
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
@@ -972,8 +1058,95 @@ context 'Frontend with base path' do
|
|||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
assert_equal '/wiki/gollum/history/Bilbo-Baggins.md', last_request.fullpath
|
assert_equal '/wiki/gollum/history/Bilbo-Baggins.md', last_request.fullpath
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test 'upload a file with mode page from the edit page (drag and drop)' do
|
||||||
|
temp_upload_file = Tempfile.new(['upload', '.file']) << "abc\r"
|
||||||
|
temp_upload_file.close
|
||||||
|
Precious::App.set(:wiki_options, {allow_uploads: true, per_page_uploads: true})
|
||||||
|
post "/wiki/gollum/upload_file", {:file => Rack::Test::UploadedFile.new(::File.open(temp_upload_file))}, {'HTTP_REFERER' => 'http://localhost:4567/wiki/gollum/edit/foo/Bar.md', 'HTTP_HOST' => 'localhost:4567'}
|
||||||
|
|
||||||
|
assert_equal 302, last_response.status # redirect is expected
|
||||||
|
@wiki.clear_cache
|
||||||
|
# Find the file in a page-specific subdir (here: foo/Bar), based on referer
|
||||||
|
file = @wiki.file("uploads/foo/Bar/#{::File.basename(temp_upload_file.path)}")
|
||||||
|
assert_equal "abc\r", file.raw_data
|
||||||
|
Precious::App.set(:wiki_options, {allow_uploads: false, per_page_uploads: false})
|
||||||
|
end
|
||||||
|
|
||||||
def app
|
def app
|
||||||
Precious::MapGollum.new(@base_path)
|
Precious::MapGollum.new(@base_path)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "Default keybindings" do
|
||||||
|
include Rack::Test::Methods
|
||||||
|
|
||||||
|
setup do
|
||||||
|
@path = cloned_testpath "examples/empty.git"
|
||||||
|
@wiki = Gollum::Wiki.new @path
|
||||||
|
@url = '/gollum/create/test'
|
||||||
|
|
||||||
|
Precious::App.set :gollum_path, @path
|
||||||
|
Precious::App.set :wiki_options, {default_keybinding: nil}
|
||||||
|
end
|
||||||
|
|
||||||
|
teardown do
|
||||||
|
FileUtils.rm_rf @path
|
||||||
|
|
||||||
|
@path = nil
|
||||||
|
@wiki = nil
|
||||||
|
@url = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'keybinding unset' do
|
||||||
|
get @url
|
||||||
|
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="default"'), false
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="vim"'), false
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="emacs"'), false
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'nonexistent keybinding' do
|
||||||
|
Precious::App.set :wiki_options, {:default_keybinding => 'does-not-exist'}
|
||||||
|
|
||||||
|
get @url
|
||||||
|
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="default"'), false
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="vim"'), false
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="emacs"'), false
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'keybinding `default`' do
|
||||||
|
Precious::App.set :wiki_options, {:default_keybinding => 'default'}
|
||||||
|
|
||||||
|
get @url
|
||||||
|
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="default"'), true
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="vim"'), false
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="emacs"'), false
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'keybinding `vim`' do
|
||||||
|
Precious::App.set :wiki_options, {:default_keybinding => 'vim'}
|
||||||
|
|
||||||
|
get @url
|
||||||
|
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="default"'), false
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="vim"'), true
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="emacs"'), false
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'keybinding `emacs`' do
|
||||||
|
Precious::App.set :wiki_options, {:default_keybinding => 'emacs'}
|
||||||
|
|
||||||
|
get @url
|
||||||
|
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="default"'), false
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="vim"'), false
|
||||||
|
assert_equal last_response.body.include?('selected="selected" value="emacs"'), true
|
||||||
|
end
|
||||||
|
|
||||||
|
def app
|
||||||
|
Precious::App
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
require File.expand_path(File.join(File.dirname(__FILE__), "helper"))
|
||||||
|
|
||||||
|
context 'Precious::Helpers' do
|
||||||
|
include Precious::Helpers
|
||||||
|
|
||||||
|
test 'remove trailing and leading slashes' do
|
||||||
|
['/wiki', '/wiki/', 'wiki/', '//wiki//'].each do |param|
|
||||||
|
assert_equal 'wiki', remove_leading_and_trailing_slashes(param)
|
||||||
|
end
|
||||||
|
assert_equal 'wi/ki', remove_leading_and_trailing_slashes('/wi/ki/')
|
||||||
|
assert_equal '', remove_leading_and_trailing_slashes('/')
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'per page upload location helper' do
|
||||||
|
# https referer with and without base path
|
||||||
|
host_with_port = 'localhost:4567'
|
||||||
|
assert_equal 'uploads/Home', find_per_page_upload_subdir('https://localhost:4567/Home.md', host_with_port, nil)
|
||||||
|
assert_equal 'uploads/Home', find_per_page_upload_subdir('https://localhost:4567/wiki/Home.md', host_with_port, '/wiki')
|
||||||
|
|
||||||
|
# http referer with and without base path
|
||||||
|
assert_equal 'uploads/Home', find_per_page_upload_subdir('http://localhost:4567/Home.md', host_with_port, nil)
|
||||||
|
assert_equal 'uploads/Home', find_per_page_upload_subdir('http://localhost:4567/wiki/Home.md', host_with_port, '/wiki')
|
||||||
|
|
||||||
|
# edit page referer with and without base path
|
||||||
|
assert_equal 'uploads/foo/Home', find_per_page_upload_subdir('http://localhost:4567/gollum/edit/foo/Home.md', host_with_port, nil)
|
||||||
|
assert_equal 'uploads/foo/Home', find_per_page_upload_subdir('http://localhost:4567/wiki/gollum/edit/foo/Home.md', host_with_port, '/wiki')
|
||||||
|
|
||||||
|
# referer with base path with slashes in the wrong place
|
||||||
|
assert_equal 'uploads/Home', find_per_page_upload_subdir('http://localhost:4567/wiki/Home.md', host_with_port, '/wiki/')
|
||||||
|
assert_equal 'uploads/Home', find_per_page_upload_subdir('http://localhost:4567/wiki/Home.md', host_with_port, 'wiki')
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# ~*~ encoding: utf-8 ~*~
|
||||||
|
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
||||||
|
require 'nokogiri'
|
||||||
|
require 'json'
|
||||||
|
require 'time'
|
||||||
|
|
||||||
|
def local_time
|
||||||
|
Precious::App.set(:wiki_options, { show_local_time: true})
|
||||||
|
end
|
||||||
|
|
||||||
|
def no_local_time
|
||||||
|
Precious::App.set(:wiki_options, { show_local_time: false})
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_time_tags(body)
|
||||||
|
tags = Nokogiri::HTML(body).css('time')
|
||||||
|
assert_equal tags.empty?, false
|
||||||
|
tags.each do |tag|
|
||||||
|
assert Time.parse(tag[:datetime]).utc?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context ":show_local_time option" do
|
||||||
|
include Rack::Test::Methods
|
||||||
|
|
||||||
|
setup do
|
||||||
|
@path = cloned_testpath('examples/lotr.git')
|
||||||
|
@wiki = Gollum::Wiki.new(@path)
|
||||||
|
Precious::App.set(:gollum_path, @path)
|
||||||
|
local_time()
|
||||||
|
end
|
||||||
|
|
||||||
|
teardown do
|
||||||
|
FileUtils.rm_rf(@path)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "last_commit_info no local time" do
|
||||||
|
no_local_time()
|
||||||
|
get '/gollum/last_commit_info', {path: 'Home.textile'}
|
||||||
|
assert_equal Time.parse(JSON.parse(last_response.body)['date']).utc?, false
|
||||||
|
end
|
||||||
|
|
||||||
|
test "last_commit_info local time" do
|
||||||
|
local_time()
|
||||||
|
get '/gollum/last_commit_info', {path: 'Home.textile'}
|
||||||
|
assert Time.parse(JSON.parse(last_response.body)['date']).utc?
|
||||||
|
end
|
||||||
|
|
||||||
|
test "datetime attributes in utc" do
|
||||||
|
get '/Home/b0d108328459e44fff4a76cd19b10ddc34adce4b'
|
||||||
|
assert_time_tags last_response.body
|
||||||
|
|
||||||
|
get '/gollum/latest_changes'
|
||||||
|
assert_time_tags last_response.body
|
||||||
|
|
||||||
|
get '/gollum/history/Home'
|
||||||
|
assert_time_tags last_response.body
|
||||||
|
|
||||||
|
get '/gollum/commit/b0d108328459e44fff4a76cd19b10ddc34adce4b'
|
||||||
|
assert_time_tags last_response.body
|
||||||
|
end
|
||||||
|
|
||||||
|
def app
|
||||||
|
Precious::App
|
||||||
|
end
|
||||||
|
end
|
||||||
+64
-66
@@ -1,28 +1,6 @@
|
|||||||
# ~*~ encoding: utf-8 ~*~
|
# ~*~ encoding: utf-8 ~*~
|
||||||
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
||||||
|
|
||||||
# Original contents of Subdir/Foo.md:
|
|
||||||
# waa
|
|
||||||
# [[Samwi]]
|
|
||||||
# [[samwise gamgee.mediaWiki]]
|
|
||||||
# [[Samwise Gamgee.mediawiki]]
|
|
||||||
# [[Samwise Gamgee]]
|
|
||||||
# [[Test|Samwise Gamgee#Anchor]]
|
|
||||||
# [[Waaa|Test]]
|
|
||||||
# [[Zaa]]
|
|
||||||
|
|
||||||
# Contents of Subdir/Foo.md after successful tag migration
|
|
||||||
result = <<EOF
|
|
||||||
waa
|
|
||||||
[[Samwi]]
|
|
||||||
[[/Samwise Gamgee.mediawiki]]
|
|
||||||
[[/Samwise Gamgee.mediawiki]]
|
|
||||||
[[/Samwise Gamgee.md]]
|
|
||||||
[[Test|/Samwise Gamgee.md#Anchor]]
|
|
||||||
[[Waaa|/Bar/Test.md]]
|
|
||||||
[[Subsub/Zaa.md]]
|
|
||||||
EOF
|
|
||||||
|
|
||||||
def load_script(**args)
|
def load_script(**args)
|
||||||
settings = {
|
settings = {
|
||||||
:run_silent => true,
|
:run_silent => true,
|
||||||
@@ -31,56 +9,76 @@ def load_script(**args)
|
|||||||
:hyphenate => false,
|
:hyphenate => false,
|
||||||
:page_file_dir => nil,
|
:page_file_dir => nil,
|
||||||
}.merge(args)
|
}.merge(args)
|
||||||
|
|
||||||
settings.each do |const, val|
|
settings.each do |setting, val|
|
||||||
const_name = const.to_s.upcase
|
variable_name = :"@@#{setting.to_s}"
|
||||||
Object.const_set(const_name, val) unless Object.const_defined?(const_name) && Object.const_get(const_name) == val
|
|
||||||
|
unless Object.class_variable_defined?(variable_name) && Object.class_variable_get(variable_name) == val
|
||||||
|
Object.class_variable_set(variable_name, val)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
script_path = File.expand_path(File.join(File.dirname(__FILE__), '../', 'bin', 'gollum-migrate-tags'))
|
script_path = File.expand_path(File.join(File.dirname(__FILE__), '../', 'bin', 'gollum-migrate-tags'))
|
||||||
|
|
||||||
Dir.chdir(@path) do
|
Dir.chdir(@path) do
|
||||||
load script_path
|
load script_path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
unless ENV['CI']
|
context '4.x -> 5.x tag migrator' do
|
||||||
|
include Rack::Test::Methods
|
||||||
|
|
||||||
context '4.x -> 5.x tag migrator' do
|
setup do
|
||||||
include Rack::Test::Methods
|
@path = cloned_testpath("examples/lotr_migration.git")
|
||||||
|
|
||||||
setup do
|
|
||||||
@path = cloned_testpath("examples/lotr_migration.git")
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'repair broken links' do
|
|
||||||
load_script
|
|
||||||
|
|
||||||
f = ::File.new(::File.join(@path, 'Subdir/Foo.md'), 'r')
|
|
||||||
assert_equal result, f.read
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'change spaced filenames to hyphenated filenames' do
|
|
||||||
load_script(hyphenate: true)
|
|
||||||
|
|
||||||
f = ::File.new(::File.join(@path, 'Home.textile'), 'r')
|
|
||||||
output = f.read
|
|
||||||
assert_equal true, output.include?('[[Bilbo-Baggins.md]]')
|
|
||||||
assert_equal true, output.include?('[[evil|Mordor/Eye-Of-Sauron.md]]')
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'migration with page file dir' do
|
|
||||||
load_script(page_file_dir: 'Subdir')
|
|
||||||
|
|
||||||
f = ::File.new(::File.join(@path, 'Subdir/Foo.md'), 'r')
|
|
||||||
output = f.read
|
|
||||||
assert_equal true, output.include?('[[Subsub/Zaa.md]]')
|
|
||||||
assert_equal true, output.include?('[[Samwi]]')
|
|
||||||
end
|
|
||||||
|
|
||||||
teardown do
|
|
||||||
FileUtils.rm_rf(@path)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
test 'repair broken links' do
|
||||||
|
# The original contents of Subdir/Foo.md:
|
||||||
|
#
|
||||||
|
# waa
|
||||||
|
# [[Samwi]]
|
||||||
|
# [[samwise gamgee.mediaWiki]]
|
||||||
|
# [[Samwise Gamgee.mediawiki]]
|
||||||
|
# [[Samwise Gamgee]]
|
||||||
|
# [[Test|Samwise Gamgee#Anchor]]
|
||||||
|
# [[Waaa|Test]]
|
||||||
|
# [[Zaa]]
|
||||||
|
#
|
||||||
|
# The contents will be updated after running the migration script.
|
||||||
|
load_script
|
||||||
|
|
||||||
|
file = ::File.new(::File.join(@path, 'Subdir/Foo.md'), 'r')
|
||||||
|
assert_equal <<~FILE_CONTENTS, file.read
|
||||||
|
waa
|
||||||
|
[[Samwi]]
|
||||||
|
[[/Samwise Gamgee.mediawiki]]
|
||||||
|
[[/Samwise Gamgee.mediawiki]]
|
||||||
|
[[/Samwise Gamgee.md]]
|
||||||
|
[[Test|/Samwise Gamgee.md#Anchor]]
|
||||||
|
[[Waaa|/Bar/Test.md]]
|
||||||
|
[[Subsub/Zaa.md]]
|
||||||
|
FILE_CONTENTS
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'change spaced filenames to hyphenated filenames' do
|
||||||
|
load_script(hyphenate: true)
|
||||||
|
|
||||||
|
f = ::File.new(::File.join(@path, 'Home.textile'), 'r')
|
||||||
|
output = f.read
|
||||||
|
assert_equal true, output.include?('[[Bilbo-Baggins.md]]')
|
||||||
|
assert_equal true, output.include?('[[evil|Mordor/Eye-Of-Sauron.md]]')
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'migration with page file dir' do
|
||||||
|
load_script(page_file_dir: 'Subdir')
|
||||||
|
|
||||||
|
f = ::File.new(::File.join(@path, 'Subdir/Foo.md'), 'r')
|
||||||
|
output = f.read
|
||||||
|
assert_equal true, output.include?('[[Subsub/Zaa.md]]')
|
||||||
|
assert_equal true, output.include?('[[Samwi]]')
|
||||||
|
end
|
||||||
|
|
||||||
|
teardown do
|
||||||
|
FileUtils.rm_rf(@path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ context "Precious::Views::Page" do
|
|||||||
@view.instance_variable_set :@content, page.formatted_data
|
@view.instance_variable_set :@content, page.formatted_data
|
||||||
@view.instance_variable_set :@h1_title, false
|
@view.instance_variable_set :@h1_title, false
|
||||||
|
|
||||||
assert_include @view.breadcrumb, "数学 📘"
|
assert_includes @view.breadcrumb, "数学 📘"
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'page <title> is the page header from content, if present' do
|
test 'page <title> is the page header from content, if present' do
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
require_relative "helper"
|
||||||
|
|
||||||
|
context "Precious::Views::RSS" do
|
||||||
|
# Simplisticially mimics a `Gollum::Git::Actor` object.
|
||||||
|
#
|
||||||
|
MockAuthor = Struct.new(:name, :email)
|
||||||
|
|
||||||
|
# Simplistically mimics a `Gollum::Git::Commit` object.
|
||||||
|
#
|
||||||
|
MockChange = Class.new do
|
||||||
|
def author
|
||||||
|
MockAuthor.new("committer name", "email@example.com")
|
||||||
|
end
|
||||||
|
|
||||||
|
def authored_date
|
||||||
|
Time.new(1999, 01, 01, 0, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
def files
|
||||||
|
["file 1", "file 2"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def id
|
||||||
|
"f0f0f0f0"
|
||||||
|
end
|
||||||
|
|
||||||
|
def message
|
||||||
|
<<~COMMIT_MESSAGE
|
||||||
|
Multi-line commit message
|
||||||
|
|
||||||
|
This commit is multiple lines long so we can test how this is
|
||||||
|
rendered in the feed.
|
||||||
|
|
||||||
|
Git's documentation says that the first line of a commit should
|
||||||
|
be 50 characters or fewer, and the rest of the commit body's
|
||||||
|
lines should not exceed 72 characters in length.
|
||||||
|
COMMIT_MESSAGE
|
||||||
|
end
|
||||||
|
|
||||||
|
def stats
|
||||||
|
OpenStruct.new(files: [{old_file: "old", new_file: "new"}])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "renders a valid RSS feed" do
|
||||||
|
feed = RSSView.new(
|
||||||
|
"/",
|
||||||
|
"Wiki Name",
|
||||||
|
"https://example.com",
|
||||||
|
[MockChange.new]
|
||||||
|
).render
|
||||||
|
|
||||||
|
# Assert that we have required RSS feed elements.
|
||||||
|
#
|
||||||
|
assert_match "<?xml version=\"1.0\" encoding=\"UTF-8\"?>", feed
|
||||||
|
assert_match /<rss version=\"2.0\"(.*)<\/rss>/m, feed
|
||||||
|
assert_match /<channel>(.*)<\/channel>/m, feed
|
||||||
|
|
||||||
|
# Assert that we have feed metadata.
|
||||||
|
#
|
||||||
|
assert_match "<title>Wiki Name Latest Changes</title>", feed
|
||||||
|
assert_match "<link>https://example.com/gollum/latest_changes</link>", feed
|
||||||
|
assert_match "<description>Latest Changes in Wiki Name</description>", feed
|
||||||
|
assert_match /<pubDate>(.*)<\/pubDate>/, feed
|
||||||
|
|
||||||
|
# Assert that we have an item in our feed.
|
||||||
|
#
|
||||||
|
assert_match /<item>(.*)<\/item>/m, feed
|
||||||
|
|
||||||
|
# And it has a title.
|
||||||
|
#
|
||||||
|
assert_match "<title>Multi-line commit message</title>", feed
|
||||||
|
|
||||||
|
# Assert that the description contains expected content.
|
||||||
|
#
|
||||||
|
assert_match /<description>(.*)<\/description>/m, feed
|
||||||
|
assert_match /<p> This commit(.*)<\/p>/, feed
|
||||||
|
assert_match /<p>Git's documentation(.*)<\/p>/, feed
|
||||||
|
|
||||||
|
# Assert that the description contains information about the commit.
|
||||||
|
# i.e.:
|
||||||
|
#
|
||||||
|
# <a href="mailto:email@example.com">committer name</a>
|
||||||
|
#
|
||||||
|
# Commit ID: f0f0f0f0
|
||||||
|
#
|
||||||
|
assert_match /Committed by: /, feed
|
||||||
|
assert_match /\<a href=\"mailto:email@example.com\"\>/, feed
|
||||||
|
assert_match /\>\n committer name\n\<\/a>/, feed
|
||||||
|
assert_match "Commit ID: f0f0f0f", feed
|
||||||
|
|
||||||
|
# Assert that affected files include links to commits, i.e.:
|
||||||
|
#
|
||||||
|
# <a href="https://example.com/old/f0f0f0f0">new</a>
|
||||||
|
#
|
||||||
|
assert_match /Affected files: /, feed
|
||||||
|
assert_match /\<a href=\"https:\/\/example.com\/old\/f0f0f0f0\"/,
|
||||||
|
feed
|
||||||
|
assert_match /f0f0f0f0">new<\/a>/, feed
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,43 +1,59 @@
|
|||||||
# ~*~ encoding: utf-8 ~*~
|
# ~*~ encoding: utf-8 ~*~
|
||||||
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
||||||
|
|
||||||
class TestTemplateCascade < Minitest::Unit::TestCase
|
context "Precious::Views::TemplateCascade" do
|
||||||
include Rack::Test::Methods
|
include Rack::Test::Methods
|
||||||
|
|
||||||
def setup
|
setup do
|
||||||
@path = cloned_testpath('examples/lotr.git')
|
@path = cloned_testpath('examples/lotr.git')
|
||||||
Precious::App.set(:gollum_path, @path)
|
Precious::App.set(:gollum_path, @path)
|
||||||
Precious::App.set(:wiki_options, {template_dir: testpath('examples/template_cascade')})
|
Precious::App.set(
|
||||||
|
:wiki_options,
|
||||||
|
{template_dir: testpath('examples/template_cascade')}
|
||||||
|
)
|
||||||
@wiki = Gollum::Wiki.new(@path)
|
@wiki = Gollum::Wiki.new(@path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def teardown
|
teardown do
|
||||||
FileUtils.rm_rf(@path)
|
FileUtils.rm_rf(@path)
|
||||||
|
|
||||||
|
Precious::App.set(:wiki_options, {template_dir: nil})
|
||||||
|
|
||||||
|
# The following line has been added to avoid order-dependent test failures.
|
||||||
|
# We saw issues where the class variable `@@template_priority_path` was not
|
||||||
|
# being reset between test cases.
|
||||||
|
Precious::Views::TemplateCascade.class_variable_set(
|
||||||
|
:@@template_priority_path,
|
||||||
|
nil
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def app
|
def app
|
||||||
Precious::App
|
Precious::App.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_overridden_page_template_is_used
|
test "overridden_page_template_is_used" do
|
||||||
get '/Home'
|
get '/Home'
|
||||||
|
|
||||||
assert last_response.body.include?('PAGE_OVERRIDE')
|
assert last_response.body.include?('PAGE_OVERRIDE')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_overridden_navbar_partial_is_used
|
test "test_overridden_navbar_partial_is_used" do
|
||||||
get '/Home'
|
get '/Home'
|
||||||
|
|
||||||
assert last_response.body.include?('NAVBAR_OVERRIDE')
|
assert last_response.body.include?('NAVBAR_OVERRIDE')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_overridden_templates_are_ignore_without_template_dir_set
|
test "test_overridden_templates_are_ignore_without_template_dir_set" do
|
||||||
Precious::App.set(:wiki_options, {template_dir: nil})
|
Precious::App.set(:wiki_options, {template_dir: nil})
|
||||||
|
|
||||||
get '/Home'
|
get '/Home'
|
||||||
|
|
||||||
assert_equal '/Home', last_request.fullpath
|
assert_equal '/Home', last_request.fullpath
|
||||||
|
|
||||||
assert last_response.ok?
|
assert last_response.ok?
|
||||||
assert_no_match /PAGE_OVERRIDE/, last_response.body
|
|
||||||
assert_no_match /NAVBAR_OVERRIDE/, last_response.body
|
refute_match /PAGE_OVERRIDE/, last_response.body
|
||||||
|
refute_match /NAVBAR_OVERRIDE/, last_response.body
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
mousetrap@^1.6.5:
|
||||||
|
version "1.6.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.5.tgz#8a766d8c272b08393d5f56074e0b5ec183485bf9"
|
||||||
|
integrity sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA==
|
||||||
Reference in New Issue
Block a user