resources/asciidoctor/lib/edit_me/extension.rb (86 lines of code) (raw):
# frozen_string_literal: true
require 'asciidoctor/extensions'
require 'csv'
require_relative '../delegating_converter'
require_relative '../log_util'
##
# Automatically adds "Edit Me" links to appropriate spots in the documentation.
module EditMe
extend LogUtil
def self.activate(registry)
error message: 'sourcemap is required' unless registry.document.sourcemap
return unless configure registry.document
DelegatingConverter.setup(registry.document) do |doc|
Converter.new doc
end
end
def self.configure(document)
edit_urls_string = document.attributes['edit_urls']
return unless edit_urls_string
if edit_urls_string.is_a? String
document.attributes['edit_urls'] = parse_edit_urls edit_urls_string
return unless document.attributes['edit_urls']
end
true
end
def self.parse_edit_urls(edit_urls_string)
edit_urls = []
CSV.parse edit_urls_string do |toplevel, url|
handle_link edit_urls, toplevel, url
end
# Prefer the longest matching edit url
edit_urls.sort_by { |e| [-e[:toplevel].length, e[:toplevel]] }
end
def self.handle_link(edit_urls, toplevel, url)
unless toplevel
error message: 'invalid edit_urls, no toplevel'
return
end
unless url
error message: 'invalid edit_urls, no url'
return
end
url = url[0..-2] if url.end_with? '/'
edit_urls << { toplevel: toplevel, url: url }
end
##
# Converter implementation that decorates titles with edit me links.
class Converter < DelegatingConverter
include LogUtil
RESPECT_OVERRIDES = 'respect_edit_url_overrides'
def convert_section(block)
block.attributes['edit_me_link'] = link_for block
yield
end
def convert_floating_title(block)
block.attributes['edit_me_link'] = link_for block
yield
end
def link_for(block)
url = edit_url block
return '' unless url
if block.document.attr 'private_edit_urls'
css_classes = 'edit_me edit_me_private'
title = 'Editing on GitHub is available to Elastic'
else
css_classes = 'edit_me'
title = 'Edit this page on GitHub'
end
<<~HTML.strip
<a class="#{css_classes}" rel="nofollow" title="#{title}" href="#{url}">edit</a>
HTML
end
def edit_url(block)
return edit_url_by_path block unless block.document.attr RESPECT_OVERRIDES
url = block.document.attr 'edit_url'
return false if url == ''
return url if url
edit_url_by_path block
end
def edit_url_by_path(block)
# source_location.path doesn't work for relative includes outside of
# the base_dir which we use when we build books from many repos.
# || '<stdin>' allows us to not blow up when translating strings that
# aren't associated with any particular file. '<stdin>' is asciidoctor's
# standard name for such strings.
path = block.source_location&.file || '<stdin>'
edit_urls = block.document.attr 'edit_urls'
entry = edit_urls.find { |e| path.start_with? e[:toplevel] }
return url_for_path path, entry if entry
warn block: block, message: <<~WARN.strip
couldn't find edit url for #{path}
WARN
false
end
def url_for_path(path, entry)
url = entry[:url]
if url == '<disable>'
false
else
url + path[entry[:toplevel].length..-1]
end
end
end
end