Add Banzai::Filter::GollumTagsFilter for parsing Gollum's tags in HTML
This commit is contained in:
parent
aac6598482
commit
a6a5990ee5
4 changed files with 210 additions and 0 deletions
|
@ -38,6 +38,10 @@ class ProjectWiki
|
|||
[Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
|
||||
end
|
||||
|
||||
def wiki_base_path
|
||||
["/", @project.path_with_namespace, "/wikis"].join('')
|
||||
end
|
||||
|
||||
# Returns the Gollum::Wiki object.
|
||||
def wiki
|
||||
@wiki ||= begin
|
||||
|
|
106
lib/banzai/filter/gollum_tags_filter.rb
Normal file
106
lib/banzai/filter/gollum_tags_filter.rb
Normal file
|
@ -0,0 +1,106 @@
|
|||
require 'banzai'
|
||||
require 'html/pipeline/filter'
|
||||
|
||||
module Banzai
|
||||
module Filter
|
||||
# HTML Filter for parsing Gollum's tags in HTML.
|
||||
#
|
||||
# Based on Gollum::Filter::Tags
|
||||
#
|
||||
# Context options:
|
||||
# :project_wiki (required) - Current project wiki.
|
||||
#
|
||||
class GollumTagsFilter < HTML::Pipeline::Filter
|
||||
include ActionView::Helpers::TagHelper
|
||||
|
||||
# Pattern to match tag contents.
|
||||
TAGS_PATTERN = %r{(.?)\[\[(.+?)\]\]([^\[]?)}
|
||||
|
||||
def call
|
||||
search_text_nodes(doc).each do |node|
|
||||
content = node.content
|
||||
|
||||
next unless content.match(TAGS_PATTERN)
|
||||
|
||||
html = process_tag($2)
|
||||
|
||||
node.replace(html) if html != node.content
|
||||
end
|
||||
|
||||
doc
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Process a single tag into its final HTML form.
|
||||
#
|
||||
# tag - The String tag contents (the stuff inside the double brackets).
|
||||
#
|
||||
# Returns the String HTML version of the tag.
|
||||
def process_tag(tag)
|
||||
if html = process_image_tag(tag)
|
||||
html
|
||||
else
|
||||
process_page_link_tag(tag)
|
||||
end
|
||||
end
|
||||
|
||||
# Attempt to process the tag as an image tag.
|
||||
#
|
||||
# tag - The String tag contents (the stuff inside the double brackets).
|
||||
#
|
||||
# Returns the String HTML if the tag is a valid image tag or nil
|
||||
# if it is not.
|
||||
def process_image_tag(tag)
|
||||
parts = tag.split('|')
|
||||
return if parts.size.zero?
|
||||
|
||||
name = parts[0].strip
|
||||
|
||||
if file = project_wiki.find_file(name)
|
||||
path = ::File.join project_wiki_base_path, file.path
|
||||
elsif name =~ /^https?:\/\/.+(jpg|png|gif|svg|bmp)$/i
|
||||
path = name
|
||||
end
|
||||
|
||||
if path
|
||||
content_tag(:img, nil, src: path)
|
||||
end
|
||||
end
|
||||
|
||||
# Attempt to process the tag as a page link tag.
|
||||
#
|
||||
# tag - The String tag contents (the stuff inside the double brackets).
|
||||
#
|
||||
# Returns the String HTML if the tag is a valid page link tag or nil
|
||||
# if it is not.
|
||||
def process_page_link_tag(tag)
|
||||
parts = tag.split('|')
|
||||
return if parts.size.zero?
|
||||
|
||||
if parts.size == 1
|
||||
url = parts[0].strip
|
||||
else
|
||||
name, url = *parts.compact.map(&:strip)
|
||||
end
|
||||
|
||||
content_tag(:a, name || url, href: url)
|
||||
end
|
||||
|
||||
def project_wiki
|
||||
context[:project_wiki]
|
||||
end
|
||||
|
||||
def project_wiki_base_path
|
||||
project_wiki && project_wiki.wiki_base_path
|
||||
end
|
||||
|
||||
# Ensure that a :project_wiki key exists in context
|
||||
#
|
||||
# Note that while the key might exist, its value could be nil!
|
||||
def validate
|
||||
needs :project_wiki
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
93
spec/lib/banzai/filter/gollum_tags_filter_spec.rb
Normal file
93
spec/lib/banzai/filter/gollum_tags_filter_spec.rb
Normal file
|
@ -0,0 +1,93 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Banzai::Filter::GollumTagsFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
let(:project) { create(:project) }
|
||||
let(:user) { double }
|
||||
let(:project_wiki) { ProjectWiki.new(project, user) }
|
||||
|
||||
describe 'validation' do
|
||||
it 'ensure that a :project_wiki key exists in context' do
|
||||
expect { filter("See [[images/image.jpg]]", {}) }.to raise_error ArgumentError, "Missing context keys for Banzai::Filter::GollumTagsFilter: :project_wiki"
|
||||
end
|
||||
end
|
||||
|
||||
context 'linking internal images' do
|
||||
it 'creates img tag if image exists' do
|
||||
file = Gollum::File.new(project_wiki.wiki)
|
||||
expect(file).to receive(:path).and_return('images/image.jpg')
|
||||
expect(project_wiki).to receive(:find_file).with('images/image.jpg').and_return(file)
|
||||
|
||||
tag = '[[images/image.jpg]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.at_css('img')['src']).to eq "#{project_wiki.wiki_base_path}/images/image.jpg"
|
||||
end
|
||||
|
||||
it 'does not creates img tag if image does not exist' do
|
||||
expect(project_wiki).to receive(:find_file).with('images/image.jpg').and_return(nil)
|
||||
|
||||
tag = '[[images/image.jpg]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.css('img').size).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'linking external images' do
|
||||
it 'creates img tag for valid URL' do
|
||||
expect(project_wiki).to receive(:find_file).with('http://example.com/image.jpg').and_return(nil)
|
||||
|
||||
tag = '[[http://example.com/image.jpg]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.at_css('img')['src']).to eq "http://example.com/image.jpg"
|
||||
end
|
||||
|
||||
it 'does not creates img tag for invalid URL' do
|
||||
expect(project_wiki).to receive(:find_file).with('http://example.com/image.pdf').and_return(nil)
|
||||
|
||||
tag = '[[http://example.com/image.pdf]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.css('img').size).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'linking external resources' do
|
||||
it "the created link's text will be equal to the resource's text" do
|
||||
tag = '[[http://example.com]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.at_css('a').text).to eq 'http://example.com'
|
||||
expect(doc.at_css('a')['href']).to eq 'http://example.com'
|
||||
end
|
||||
|
||||
it "the created link's text will be link-text" do
|
||||
tag = '[[link-text|http://example.com/pdfs/gollum.pdf]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.at_css('a').text).to eq 'link-text'
|
||||
expect(doc.at_css('a')['href']).to eq 'http://example.com/pdfs/gollum.pdf'
|
||||
end
|
||||
end
|
||||
|
||||
context 'linking internal resources' do
|
||||
it "the created link's text will be equal to the resource's text" do
|
||||
tag = '[[wiki-slug]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.at_css('a').text).to eq 'wiki-slug'
|
||||
expect(doc.at_css('a')['href']).to eq 'wiki-slug'
|
||||
end
|
||||
|
||||
it "the created link's text will be link-text" do
|
||||
tag = '[[link-text|wiki-slug]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.at_css('a').text).to eq 'link-text'
|
||||
expect(doc.at_css('a')['href']).to eq 'wiki-slug'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -36,6 +36,13 @@ describe ProjectWiki, models: true do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#wiki_base_path" do
|
||||
it "returns the wiki base path" do
|
||||
wiki_base_path = "/#{project.path_with_namespace}/wikis"
|
||||
expect(subject.wiki_base_path).to eq(wiki_base_path)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#wiki" do
|
||||
it "contains a Gollum::Wiki instance" do
|
||||
expect(subject.wiki).to be_a Gollum::Wiki
|
||||
|
|
Loading…
Reference in a new issue