Compare commits

..

1 Commits

Author SHA1 Message Date
Dawa Ometto f3fd06ef7a Update test.yaml 2021-11-06 13:36:32 +01:00
62 changed files with 393 additions and 896 deletions
+5 -15
View File
@@ -1,22 +1,12 @@
name: Deploy docker name: Deploy docker
on: on: [push]
push: env:
branches: DEPLOY_NAME: gollumwiki/gollum:latest
- 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
@@ -46,4 +36,4 @@ jobs:
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
- name: Image digest - name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }} run: echo ${{ steps.docker_build.outputs.digest }}
+2 -2
View File
@@ -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 gollum as test - name: Run tests
run: docker run -e CI=true ${{ env.CI_IMAGE }} --irb run: docker run -e CI=true -w /app --entrypoint bundle ${{ env.CI_IMAGE }} exec rake
+11 -28
View File
@@ -1,46 +1,29 @@
name: Ruby Build name: Ruby Build
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
jruby_build: build:
name: JRuby (${{ matrix.ruby }})
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
ruby: [jruby-9.3.2.0] ruby: [2.4.0, 2.6.0, 3.0.0, jruby-9.2.18.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 }}
- name: Set up Java - uses: actions/setup-java@v2
uses: actions/setup-java@v2
with: with:
distribution: 'adopt' distribution: 'temurin'
java-version: '11' java-version: '11'
- name: Set up Ruby - uses: ruby/setup-ruby@v1
uses: ruby/setup-ruby@v1
with: with:
ruby-version: ${{ matrix.ruby }} ruby-version: ${{ matrix.ruby }}
bundler-cache: true bundler-cache: true
- name: Run tests - name: 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 run: bundle exec rake
+5 -16
View File
@@ -1,11 +1,9 @@
FROM ruby:2.7-alpine AS builder FROM ruby:2.7
ENV DEBIAN_FRONTEND="noninteractive"
RUN apk add \ RUN apt-get update && apt-get install -y \
build-base \ libicu-dev \
cmake \ cmake
git \
icu-dev \
openssl-dev
COPY Gemfile* /tmp/ COPY Gemfile* /tmp/
COPY gollum.gemspec* /tmp/ COPY gollum.gemspec* /tmp/
@@ -25,15 +23,6 @@ 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
VOLUME /wiki VOLUME /wiki
WORKDIR /wiki WORKDIR /wiki
COPY docker-run.sh /docker-run.sh COPY docker-run.sh /docker-run.sh
+4 -18
View File
@@ -1,23 +1,9 @@
source 'https://rubygems.org' source 'https://rubygems.org'
gem 'warbler', platforms: :jruby if RUBY_PLATFORM == 'java'
gem 'warbler'
# FIXME: end
#
# 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.
gemspec gemspec
gem 'rake', '~> 13.0' gem 'rake', '~> 13.0'
-1
View File
@@ -117,7 +117,6 @@ 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> |
+13 -1
View File
@@ -1,5 +1,6 @@
require 'rubygems' require 'rubygems'
require 'rake' require 'rake'
require 'date'
############################################################################# #############################################################################
# #
@@ -37,6 +38,14 @@ 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
@@ -134,9 +143,12 @@ 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 and version # replace name version and date
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`.
+2 -5
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env -S ruby -Eutf-8 #!/usr/bin/env ruby
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib]) $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
@@ -112,9 +112,6 @@ 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
@@ -209,7 +206,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 1 exit
end end
# --gollum-path wins over ARGV[0] # --gollum-path wins over ARGV[0]
+28 -40
View File
@@ -11,11 +11,8 @@ migrate_options = {
:hyphenate => true :hyphenate => true
} }
def setting(variable_name) def setting(const)
class_variable_name = :"@@#{variable_name.to_s}" Object.const_defined?(const.upcase) && Object.const_get(const.upcase)
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|
@@ -28,7 +25,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.
@@ -41,7 +38,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.
@@ -55,23 +52,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
@@ -81,11 +78,8 @@ end
begin begin
opts.parse! opts.parse!
migrate_options.each do |setting, value| migrate_options.each do |setting, value|
variable_name = :"@@#{setting.to_s}" const = setting.to_s.upcase
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
@@ -94,7 +88,7 @@ rescue OptionParser::InvalidOption
exit exit
end end
wiki_directory = ARGV[0] || Dir.pwd REPO = ARGV[0] || Dir.pwd
require 'gollum-lib' require 'gollum-lib'
@@ -104,7 +98,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
@@ -132,7 +126,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
@@ -140,7 +134,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
@@ -148,23 +142,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
@@ -174,7 +168,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]
@@ -209,12 +203,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
@@ -226,7 +220,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
@@ -238,12 +232,8 @@ end
filter_chain = [:PlainTextMigrator, :CodeMigrator, :TagMigrator] filter_chain = [:PlainTextMigrator, :CodeMigrator, :TagMigrator]
wiki = ::Gollum::Wiki.new(wiki_directory, wiki_options.merge({:filter_chain => filter_chain})) wiki = ::Gollum::Wiki.new(REPO, 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
@@ -253,9 +243,7 @@ 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!
Object.class_variable_get(:"@@wiki_tree").select { |path| TREE.select {|path| path =~ /^\/(.*\/)?#{test_path}/i}
path =~ /^\/(.*\/)?#{test_path}/i
}
end end
def log(kind, msg = nil) def log(kind, msg = nil)
@@ -280,4 +268,4 @@ wiki.pages.each do |page|
f.close f.close
end end
log(:none, '====') log(:none, '====')
end end
+1 -10
View File
@@ -5,14 +5,5 @@ 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
[[ "$@" != *--mathjax* ]] && echo "WARNING: Mathjax will soon be disabled by default. To explicitly enable it, use --mathjax" >&2 gollum --mathjax
exec gollum $@ --mathjax
+5 -2
View File
@@ -1,9 +1,12 @@
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.required_ruby_version = '>= 2.6' s.rubygems_version = '1.3.5'
s.required_ruby_version = '>= 1.9'
s.name = 'gollum' s.name = 'gollum'
s.version = '5.2.3' s.version = '5.2.3'
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.'
@@ -41,6 +44,7 @@ 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'
@@ -1149,7 +1153,6 @@ 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
+2 -3
View File
@@ -29,10 +29,9 @@ module Gollum
@@filters[pattern] = replacement @@filters[pattern] = replacement
end end
def self.apply_filters(wiki_page, data) def self.apply_filters(data)
@@filters.each do |pattern, replacement| @@filters.each do |pattern, replacement|
params = replacement.parameters.length == 0 ? nil : wiki_page data.gsub!(pattern, replacement.call)
data.gsub!(pattern, replacement.call(*params))
end end
data data
end end
+30 -45
View File
@@ -20,7 +20,6 @@ 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'
@@ -103,14 +102,16 @@ module Precious
end end
before do before do
@allow_editing = settings.wiki_options.fetch(:allow_editing, true) settings.wiki_options[: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')
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
Precious::Views::Layout.template_priority_path = settings.wiki_options[:template_dir] Precious::Views::Layout.template_priority_path = settings.wiki_options[:template_dir]
@@ -124,7 +125,6 @@ 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,8 +140,6 @@ 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
@@ -178,9 +176,7 @@ 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
authored_date = version.authored_date {:author => version.author.name, :date => version.authored_date}.to_json
authored_date = authored_date.utc.iso8601 if @show_local_time
{:author => version.author.name, :date => authored_date}.to_json
end end
end end
@@ -221,6 +217,7 @@ 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
@@ -242,7 +239,7 @@ module Precious
halt 500 unless tempfile.is_a? Tempfile halt 500 unless tempfile.is_a? Tempfile
if wiki.per_page_uploads if wiki.per_page_uploads
dir = request.referer.match(/^https?:\/\/#{request.host_with_port}\/(.*)/)[1] dir = request.referer.sub(request.base_url, '')
# remove base path if it is set # remove base path if it is set
dir.sub!(/^#{wiki.base_path}/, '') if wiki.base_path dir.sub!(/^#{wiki.base_path}/, '') if wiki.base_path
# remove base_url and gollum/* subpath if necessary # remove base_url and gollum/* subpath if necessary
@@ -368,7 +365,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(wikip, @path) if settings.wiki_options[:template_page] @template_page = load_template(@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)
@@ -442,18 +439,23 @@ 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
show_history wiki_page(params[:splat].first) wikip = 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
@@ -600,24 +602,6 @@ 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)
@@ -629,6 +613,7 @@ 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
@@ -660,9 +645,9 @@ module Precious
end end
end end
def load_template(wiki_page, path) def load_template(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(wiki_page, template_page.text_data) : nil template_page ? Gollum::TemplateFilter.apply_filters(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)
@@ -674,9 +659,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, wiki = nil) def wiki_page(path, version = nil)
pathname = (Pathname.new('/') + path).cleanpath pathname = (Pathname.new('/') + path).cleanpath
wiki = wiki_new if wiki.nil? wiki = wiki_new
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
@@ -1 +1 @@
{"files":{"app-f05401ee374f0c7f48fc2bc08e30b4f4db705861fd5895ed70998683b383bfb5.js":{"logical_path":"app.js","mtime":"2021-11-15T20:08:30-08:00","size":136040,"digest":"f05401ee374f0c7f48fc2bc08e30b4f4db705861fd5895ed70998683b383bfb5","integrity":"sha256-8FQB7jdPDH9I/CvAjjC09NtwWGH9WJXtcJmGg7ODv7U="},"editor-9881d0c7ae663293f0e3a7e72729eec7e940fa613185c076709b76d292f5703a.js":{"logical_path":"editor.js","mtime":"2021-11-15T20:08:30-08:00","size":744886,"digest":"9881d0c7ae663293f0e3a7e72729eec7e940fa613185c076709b76d292f5703a","integrity":"sha256-mIHQx65mMpPw46fnJynux+lA+mExhcB2cJt20pL1cDo="},"app-309be032396e783b13a47df58f389b7c8e11c2b2d42640560b874f677c25f6e5.css":{"logical_path":"app.css","mtime":"2021-11-15T20:08:30-08:00","size":396731,"digest":"309be032396e783b13a47df58f389b7c8e11c2b2d42640560b874f677c25f6e5","integrity":"sha256-MJvgMjlueDsTpH31jzibfI4RwrLUJkBWC4dPZ3wl9uU="},"criticmarkup-31ae5d3282bbb8e7b7c3c9917e9fb68e3315a6b4a75da6cec48d21b8846905c4.css":{"logical_path":"criticmarkup.css","mtime":"2021-08-22T15:24:51-07:00","size":646,"digest":"31ae5d3282bbb8e7b7c3c9917e9fb68e3315a6b4a75da6cec48d21b8846905c4","integrity":"sha256-Ma5dMoK7uOe3w8mRfp+2jjMVprSnXabOxI0huIRpBcQ="},"print-512498c368be0d3fb1ba105dfa84289ae48380ec9fcbef948bd4e23b0b095bfb.css":{"logical_path":"print.css","mtime":"2021-08-22T15:24:51-07: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-309be032396e783b13a47df58f389b7c8e11c2b2d42640560b874f677c25f6e5.css","criticmarkup.css":"criticmarkup-31ae5d3282bbb8e7b7c3c9917e9fb68e3315a6b4a75da6cec48d21b8846905c4.css","print.css":"print-512498c368be0d3fb1ba105dfa84289ae48380ec9fcbef948bd4e23b0b095bfb.css"}} {"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"}}
@@ -1,6 +1,5 @@
//= require jquery-1.7.2.min //= require jquery-1.7.2.min
//= require identicon //= require identicon
//= require date.min
//= require mousetrap.min //= require mousetrap.min
//= require clipboard.min //= require clipboard.min
//= require gollum //= require gollum
-123
View File
@@ -1,123 +0,0 @@
/**
* @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)})();
@@ -96,13 +96,6 @@ 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 = '';
@@ -162,16 +155,6 @@ $(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');
@@ -591,9 +574,8 @@ $(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>, ' + date); $("#last-edit-in-progress").html('Last edited by <b>' + data.author + '</b>, ' + data.date);
} }
}); });
$("#last-edit").next(".dotted-spinner").toggleClass('hidden') $("#last-edit").next(".dotted-spinner").toggleClass('hidden')
@@ -510,14 +510,6 @@ a {
border: none; border: none;
} }
#head .header-title {
font-size: 1.5em;
@include largemobile-breakpoint {
font-size: 32px;
}
}
/* Highlights */ /* Highlights */
.highlight { .highlight {
+2 -4
View File
@@ -1,9 +1,7 @@
<div id="wiki-wrapper" class="compare"> <div id="wiki-wrapper" class="compare">
<div id="head"> <div id="head">
<h1 class="header-title text-center text-md-left py-4"> <h1 class="py-4">{{message}}</h1>
{{message}} {{author}} commited {{authored_date}}
</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>
+4 -10
View File
@@ -1,14 +1,8 @@
<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>
<h1 class="header-title text-center text-md-left py-4"> </div>
<span class="f1-light text-gray-light">
Comparing versions of
</span>
{{name}}
</h1>
</div>
{{#message}} {{#message}}
<p>{{message}}</p> <p>{{message}}</p>
+4 -7
View File
@@ -1,11 +1,8 @@
<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>
<h1 class="header-title text-center text-md-left py-4"> </div>
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">
+4 -7
View File
@@ -1,11 +1,8 @@
<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>
<h1 class="header-title text-center text-md-left py-4"> </div>
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">
+3 -10
View File
@@ -1,15 +1,8 @@
<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">
History for
</span>
{{name}}
</h1>
</div> </div>
<div id="page-history"> <div id="page-history">
{{>pagination}} {{>pagination}}
@@ -23,7 +16,7 @@
<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>
<time class="flex-auto col-1 text-gray-light" datetime="{{datetime}}" data-format="{{date_format}}">{{date}}</time> <span class="flex-auto col-1 text-gray-light">{{date}}</span>
<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>
+5 -8
View File
@@ -1,11 +1,8 @@
<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>
<h1 class="header-title text-center text-md-left py-4"> </div>
{{title}}
</h1>
</div>
{{>pagination}} {{>pagination}}
@@ -15,7 +12,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>
<time class="flex-auto col-1 text-gray-light" datetime="{{datetime}}" data-format="{{date_format}}">{{date}}</time> <span class="flex-auto col-1 text-gray-light">{{date}}</span>
<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/>
-1
View File
@@ -14,7 +14,6 @@
<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') {
+2 -9
View File
@@ -1,11 +1,4 @@
<nav class="TableObject <nav class="TableObject actions pt-4 px-2 px-lg-0 overflow-x-scroll">
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>
@@ -52,7 +45,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}}/{{version}}" href="{{history_path}}/{{escaped_url_path}}"
id="minibutton-history" id="minibutton-history"
> >
History History
+4 -7
View File
@@ -1,11 +1,8 @@
<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>
<h1 class="header-title text-center text-md-left py-4"> </div>
{{title}}
</h1>
</div>
<div id="overview"> <div id="overview">
{{#has_results}} {{#has_results}}
+1 -7
View File
@@ -1,13 +1,7 @@
<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">
Search results for
</span>
{{name}}
</h1>
</div> </div>
{{#has_results}} {{#has_results}}
+2 -4
View File
@@ -1,7 +1,5 @@
<div id="wiki-content" class="px-2 px-lg-0"> <div id="wiki-content" class="px-2 px-lg-0">
<h1 class="header-title text-center text-md-left pt-4"> <h1 class="pt-4">{{page_header}}</h1>
{{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}}">
@@ -56,7 +54,7 @@
{{/preview}} {{/preview}}
{{/historical}} {{/historical}}
{{#historical}} {{#historical}}
<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> <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>
{{/historical}} {{/historical}}
</div> </div>
-4
View File
@@ -17,10 +17,6 @@ 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
+2 -3
View File
@@ -2,7 +2,6 @@ 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
@@ -42,9 +41,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
+5 -2
View File
@@ -3,7 +3,6 @@ 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
@@ -19,6 +18,10 @@ 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?
@@ -64,7 +67,7 @@ module Precious
def etag def etag
@etag @etag
end end
def allow_uploads def allow_uploads
@allow_uploads @allow_uploads
end end
-11
View File
@@ -1,11 +0,0 @@
module Precious
module HasMath
def mathjax
@mathjax
end
def mathjax_config
@mathjax_config
end
end
end
+1 -1
View File
@@ -42,7 +42,7 @@ module Precious
end end
def fill_argument_content(i18n_key, i18n_value) def fill_argument_content(i18n_key, i18n_value)
i18n_value = i18n_value.gsub(YAML_VARIABLE_REGEXP) do |argument| 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?
+12 -17
View File
@@ -1,8 +1,6 @@
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
@@ -20,21 +18,18 @@ 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)
authored_date = v.authored_date { :id => v.id,
{ :id => v.id, :id7 => v.id[0..6],
:id7 => v.id[0..6], :href => page_route("gollum/commit/#{v.id}"),
:href => page_route("gollum/commit/#{v.id}"), :href_page => page_route("#{filename}/#{v.id}"),
:href_page => page_route("#{filename}/#{v.id}"), :num => i,
:num => i, :selected => @page.version.id == v.id,
:selected => @page.version.id == v.id, :author => v.author.name.respond_to?(:force_encoding) ? v.author.name.force_encoding('UTF-8') : v.author.name,
:author => v.author.name.respond_to?(:force_encoding) ? v.author.name.force_encoding('UTF-8') : v.author.name, :message => v.message.respond_to?(:force_encoding) ? v.message.force_encoding('UTF-8') : v.message,
:message => v.message.respond_to?(:force_encoding) ? v.message.force_encoding('UTF-8') : v.message, :date => v.authored_date.strftime("%B %d, %Y"),
:date_full => authored_date, :user_icon => self.user_icon_code(v.author.email),
:date => authored_date.strftime(DATE_FORMAT), :filename => filename,
:datetime => authored_date.utc.iso8601, :date_full => v.authored_date,
:date_format => DATE_FORMAT,
:user_icon => self.user_icon_code(v.author.email),
:filename => filename
} }
end end
end end
+10 -15
View File
@@ -1,8 +1,6 @@
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
@@ -16,19 +14,16 @@ module Precious
i = @versions.size + 1 i = @versions.size + 1
@versions.map do |v| @versions.map do |v|
i -= 1 i -= 1
authored_date = v.authored_date { :id => v.id,
{ :id => v.id, :id7 => v.id[0..6],
:id7 => v.id[0..6], :href => page_route("gollum/commit/#{v.id}"),
:href => page_route("gollum/commit/#{v.id}"), :num => i,
:num => i, :author => v.author.name.respond_to?(:force_encoding) ? v.author.name.force_encoding('UTF-8') : v.author.name,
:author => v.author.name.respond_to?(:force_encoding) ? v.author.name.force_encoding('UTF-8') : v.author.name, :message => v.message.respond_to?(:force_encoding) ? v.message.force_encoding('UTF-8') : v.message,
:message => v.message.respond_to?(:force_encoding) ? v.message.force_encoding('UTF-8') : v.message, :date => v.authored_date.strftime("%B %d, %Y"),
:date_full => authored_date, :user_icon => self.user_icon_code(v.author.email),
:date => authored_date.strftime(DATE_FORMAT), :date_full => v.authored_date,
:datetime => authored_date.utc.iso8601, :files => v.stats.files.map { |f|
: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}",
-4
View File
@@ -67,10 +67,6 @@ module Precious
@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
+18 -23
View File
@@ -2,9 +2,8 @@ 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, :version attr_reader :content, :page, :header, :footer, :preview, :historical
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',
@@ -48,23 +47,11 @@ 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
date_full.strftime(DATE_FORMAT) first = @version ? page.version : page.last_version
end return Time.now.strftime(DATE_FORMAT) unless first
first.authored_date.strftime(DATE_FORMAT)
def datetime
date_full.utc.iso8601
end
def date_format
DATE_FORMAT
end end
def noindex def noindex
@@ -74,11 +61,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
@@ -86,11 +73,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
@@ -170,6 +157,14 @@ 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
@@ -187,7 +182,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.
# #
+2 -6
View File
@@ -11,13 +11,9 @@ 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}")
priority = File.exists?(priority) ? priority : default
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.
Binary file not shown.
-2
View File
@@ -3,5 +3,3 @@
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,5 +3,3 @@
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
@@ -1,6 +0,0 @@
x¥ŽK
Â0@]÷³ʤù4A7n¼Ã$3±AÓJ‰ooñ
.ß[<^œKÉ:‹»ºˆ€Öɸ€bY¥Á¡öI'Rh¢Ø8 hSô¨4Só¢E¦
|è†>&KZã(vÆ"
'Œ¬Ù‹°‘ÐлŽó·üÈ•àºÒ4¯p˜~Ø®Šc›òt/”ŸmœË”3¨ï;{ܲÍf·Ý*‡š‹<¥
ù-üš…Q×
+1 -1
View File
@@ -1 +1 @@
c736e410f98df7a1173a540364dbb8a18274273e 02796b1450691f90db5d6dc6a816a4980ce80d07
+14 -33
View File
@@ -1,20 +1,19 @@
require 'rubygems' require 'rubygems'
require 'rack/test' require 'rack/test'
require 'test/unit'
require 'shoulda' require 'shoulda'
require 'minitest/autorun'
require 'minitest/reporters'
require 'minitest/spec'
require 'mocha/setup' require 'mocha/setup'
require 'fileutils' require 'fileutils'
require 'minitest/reporters'
require 'minitest/spec'
require 'twitter_cldr'
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'))
@@ -64,29 +63,14 @@ def normal(text)
text text
end end
# The following configuration originates from this gist: # test/spec/mini 3
# http://gist.github.com/25455
# http://gist.github.com/25455 # chris@ozmm.org
# # 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
klass = Class.new(Minitest::Test) do require 'test/unit'
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
@@ -102,13 +86,10 @@ def context(*args, &block)
define_method(:teardown, &block) define_method(:teardown, &block)
end end
end end
( (
class << klass; class << klass;
self self
end end).send(:define_method, :name) { name.gsub(/\W/, '_') }
).send(:define_method, :name) { name.gsub(/\W/, '_') }
$contexts << klass $contexts << klass
klass.class_eval &block klass.class_eval &block
end end
+34 -54
View File
@@ -3,107 +3,87 @@ 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 pages is not blocked' do test "creating page is blocked" do
post '/gollum/create', Precious::App.set(:wiki_options, { allow_editing: false})
content: 'abc', post "/gollum/create", :content => 'abc', :page => "D",
format: 'markdown', :format => 'markdown', :message => 'def'
message: 'def', assert !last_response.ok?
page: 'D'
assert_equal last_response.status, 302 page = @wiki.page('D')
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 last_response.body.include? "Delete this Page" assert_match /Delete this Page/, last_response.body, "'Delete this Page' link is blocked in page template"
assert last_response.body.include? "New" assert_match /New/, last_response.body, "'New' button is blocked in page template"
assert last_response.body.include? "<span>Upload</span>" assert_match /Upload\b/, last_response.body, "'Upload' link is blocked in page template"
assert last_response.body.include? "Rename" assert_match /Rename/, last_response.body, "'Rename' link is blocked in page template"
assert last_response.body.include? "Edit" assert_match /Edit/, last_response.body, "'Edit' link is blocked in page template"
get '/gollum/overview' get '/gollum/overview'
assert last_response.body.include? "New" assert_match /New/, last_response.body, "'New' link is blocked in pages template"
get '/gollum/history/A' get '/gollum/history/A'
refute last_response.body.include? "Edit" assert_no_match /Edit/, last_response.body, "'Edit' link is not blocked in history template"
get '/gollum/compare/A/fc665395..b26b791c' get '/gollum/compare/A/fc66539528eb96f21b2bbdbf557788fe8a1196ac..b26b791cb7917c4f37dd9cb4d1e0efb24ac4d26f'
refute last_response.body.include? "Edit Page" assert_no_match /Edit Page/, last_response.body, "'Edit Page' link is not blocked in compare template"
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, allow_uploads: false}) Precious::App.set(:wiki_options, { allow_editing: false })
get '/A' get '/A'
refute last_response.body.include? "Delete this Page" assert_no_match /Delete this Page/, last_response.body, "'Delete this Page' link not blocked in page template"
refute last_response.body.include? "<span>Upload</span>" assert_no_match /New/, last_response.body, "'New' button not blocked in page template"
refute last_response.body.include? "Rename" assert_no_match /Upload\b/, last_response.body, "'Upload' link not blocked in page template"
refute last_response.body.include? "Edit" assert_no_match /Rename/, last_response.body, "'Rename' link not blocked in page template"
refute last_response.body.include? "New" assert_no_match /Edit/, last_response.body, "'Edit' link not blocked in page template"
get '/gollum/overview' get '/gollum/overview'
refute last_response.body.include? "New" assert_no_match /New/, last_response.body, "'New' link not blocked in pages template"
get '/gollum/history/A' get '/gollum/history/A'
refute last_response.body.include? "Edit" assert_no_match /Edit/, last_response.body, "'Edit' link not blocked in history template"
get '/gollum/compare/A/fc665395..b26b791c' get '/gollum/compare/A/fc66539528eb96f21b2bbdbf557788fe8a1196ac..b26b791cb7917c4f37dd9cb4d1e0efb24ac4d26f'
refute last_response.body.include? "Edit Page" assert_no_match /Edit Page/, last_response.body, "'Edit Page' link not blocked in compare template"
refute last_response.body.include? "Revert Changes" assert_no_match /Revert Changes/, last_response.body, "'Revert Changes' link not blocked in compare template"
end end
def app def app
Precious::App Precious::App
end end
end end
+71 -138
View File
@@ -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,29 +39,31 @@ 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_content = <<~TEXT page = 'utfh1'
## 한글 text = nfd('한글')
Test page "utfh1" content. # don't use h1 or it will be promoted to replace file name
TEXT # which doesn't generate a normal header link
@wiki.write_page(page, :markdown, '## ' + text,
{ :name => 'user1', :email => 'user1' });
@wiki.write_page('utfh1', get page
:markdown, expected = "<h2 class=\"editable\"><a class=\"anchor\" (href|id)=\"(#)?#{text}\" (href|id)=\"(#)?#{text}\"></a>#{text}</h2>"
page_content, actual = nfd(last_response.body)
{name: 'user1', email: 'user1'})
get 'utfh1' assert_match /#{expected}/, actual
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 channel_title = <<EOF
<title>Gollum Wiki Latest Changes</title> <title>Gollum Wiki Latest Changes</title>
@@ -104,24 +106,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
refute_equal page_1.version.sha, page_2.version.sha assert_not_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
refute_equal old_sha, new_sha assert_not_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
@@ -134,7 +136,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
refute_equal page_1.version.sha, page_2.version.sha assert_not_equal page_1.version.sha, page_2.version.sha
end end
test "edit page with slash" do test "edit page with slash" do
@@ -165,13 +167,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
refute_equal foot_1.version.sha, foot_2.version.sha assert_not_equal foot_1.version.sha, foot_2.version.sha
refute_equal header_1.version.sha, header_2.version.sha assert_not_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
refute_equal side_1.version.sha, side_2.version.sha assert_not_equal side_1.version.sha, side_2.version.sha
assert_equal commits, @wiki.repo.commits('master').size assert_equal commits+1, @wiki.repo.commits('master').size
end end
test "renames page" do test "renames page" do
@@ -187,7 +189,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
refute_equal page_1.version.sha, page_2.version.sha assert_not_equal page_1.version.sha, page_2.version.sha
end end
test "rename preserves format" do test "rename preserves format" do
@@ -222,7 +224,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")
refute_equal page_1, nil assert_not_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!
@@ -234,12 +236,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
refute_equal page_1.version.sha, page_2.version.sha assert_not_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")
refute_equal page_1, nil assert_not_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!
@@ -251,7 +253,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
refute_equal page_1.version.sha, page_2.version.sha assert_not_equal page_1.version.sha, page_2.version.sha
end end
test "creates page" do test "creates page" do
@@ -320,7 +322,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)
refute_match(/[^\/]#{dir}/, last_response.body) assert_no_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
@@ -328,9 +330,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'
@@ -338,51 +340,12 @@ 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'
@@ -390,7 +353,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_nil page_e assert_equal nil, page_e
end end
test "edit allows changing format" do test "edit allows changing format" do
@@ -446,31 +409,23 @@ EOF
@wiki.clear_cache @wiki.clear_cache
page = @wiki.page(name) page = @wiki.page(name)
refute_equal 'abc', page.raw_data assert_not_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)}")
@@ -483,7 +438,7 @@ EOF
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 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
@@ -491,22 +446,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 "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
@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 "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
@@ -518,7 +458,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,
@@ -530,15 +470,15 @@ EOF
@wiki.clear_cache @wiki.clear_cache
page = @wiki.page(name) page = @wiki.page(name)
assert_nil page assert_equal 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') assert last_response.body.include?('Samewise Gamgee</h1>')
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?
@@ -554,7 +494,7 @@ EOF
@wiki.clear_cache @wiki.clear_cache
page2 = @wiki.page('B') page2 = @wiki.page('B')
refute_equal page1.version.sha, page2.version.sha assert_not_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
@@ -568,7 +508,7 @@ EOF
@wiki.clear_cache @wiki.clear_cache
page2 = @wiki.page('A') page2 = @wiki.page('A')
refute_equal page1.version.sha, page2.version.sha assert_not_equal page1.version.sha, page2.version.sha
assert_equal "INITIAL", page2.raw_data.strip assert_equal "INITIAL", page2.raw_data.strip
end end
@@ -582,7 +522,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
@@ -630,7 +570,7 @@ EOF
{ :name => 'user1', :email => 'user1' }); { :name => 'user1', :email => 'user1' });
get page get page
refute_match /custom.js/, last_response.body assert_no_match /custom.js/, last_response.body
end end
test "add custom.js if setting" do test "add custom.js if setting" do
@@ -648,7 +588,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}"
@@ -681,7 +621,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
@@ -699,7 +639,7 @@ EOF
get "A" get "A"
assert last_response.ok? assert last_response.ok?
refute_match /meta name="robots" content="noindex, nofollow"/, last_response.body assert_no_match /meta name="robots" content="noindex, nofollow"/, last_response.body
get "A/fc66539528eb96f21b2bbdbf557788fe8a1196ac" get "A/fc66539528eb96f21b2bbdbf557788fe8a1196ac"
@@ -715,13 +655,6 @@ 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
@@ -871,17 +804,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_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?('This version of the page was edited by <b>Tom Preston-Werner</b> at 2010-04-07')
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?
refute_match /Samwise,Gamgee/, last_response.body assert_no_match /Samwise,Gamgee/, last_response.body
get "Data.csv/#{update_sha}" get "Data.csv/#{update_sha}"
assert last_response.ok? assert last_response.ok?
@@ -926,7 +859,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)
refute_match(/[^\/]#{dir}/, last_response.body) assert_no_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
@@ -967,7 +900,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)
@@ -978,11 +911,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?
@@ -994,12 +927,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)
@@ -1011,24 +944,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?
@@ -1039,8 +972,8 @@ 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
def app def app
Precious::MapGollum.new(@base_path) Precious::MapGollum.new(@base_path)
end end
end end
-66
View File
@@ -1,66 +0,0 @@
# ~*~ 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
+70 -68
View File
@@ -1,6 +1,28 @@
# ~*~ 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,
@@ -9,76 +31,56 @@ 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|
const_name = const.to_s.upcase
Object.const_set(const_name, val) unless Object.const_defined?(const_name) && Object.const_get(const_name) == val
end
script_path = File.expand_path(File.join(File.dirname(__FILE__), '../', 'bin', 'gollum-migrate-tags'))
Dir.chdir(@path) do
load script_path
end
end
settings.each do |setting, val| unless ENV['CI']
variable_name = :"@@#{setting.to_s}"
unless Object.class_variable_defined?(variable_name) && Object.class_variable_get(variable_name) == val context '4.x -> 5.x tag migrator' do
Object.class_variable_set(variable_name, val) include Rack::Test::Methods
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
script_path = File.expand_path(File.join(File.dirname(__FILE__), '../', 'bin', 'gollum-migrate-tags')) end
Dir.chdir(@path) do
load script_path
end
end
context '4.x -> 5.x tag migrator' do
include Rack::Test::Methods
setup do
@path = cloned_testpath("examples/lotr_migration.git")
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
+1 -1
View File
@@ -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_includes @view.breadcrumb, "数学 📘" assert_include @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
+10 -26
View File
@@ -1,59 +1,43 @@
# ~*~ 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'))
context "Precious::Views::TemplateCascade" do class TestTemplateCascade < Minitest::Unit::TestCase
include Rack::Test::Methods include Rack::Test::Methods
setup do def setup
@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( Precious::App.set(:wiki_options, {template_dir: testpath('examples/template_cascade')})
:wiki_options,
{template_dir: testpath('examples/template_cascade')}
)
@wiki = Gollum::Wiki.new(@path) @wiki = Gollum::Wiki.new(@path)
end end
teardown do def teardown
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.new Precious::App
end end
test "overridden_page_template_is_used" do def test_overridden_page_template_is_used
get '/Home' get '/Home'
assert last_response.body.include?('PAGE_OVERRIDE') assert last_response.body.include?('PAGE_OVERRIDE')
end end
test "test_overridden_navbar_partial_is_used" do def test_overridden_navbar_partial_is_used
get '/Home' get '/Home'
assert last_response.body.include?('NAVBAR_OVERRIDE') assert last_response.body.include?('NAVBAR_OVERRIDE')
end end
test "test_overridden_templates_are_ignore_without_template_dir_set" do def test_overridden_templates_are_ignore_without_template_dir_set
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
refute_match /PAGE_OVERRIDE/, last_response.body assert_no_match /NAVBAR_OVERRIDE/, last_response.body
refute_match /NAVBAR_OVERRIDE/, last_response.body
end end
end end