lib/playbook/markdown/helper.rb



# frozen_string_literal: true

require "redcarpet"
require "rouge"
require "rouge/plugins/redcarpet"
require "action_view"

module Playbook
  module Markdown
    module Helper
      def markdown(text)
        options = {
          filter_html: false,
          hard_wrap: true,
          link_attributes: { rel: "nofollow", target: "_blank" },
          space_after_headers: true,
          fenced_code_blocks: true,
          no_styles: false,
          safe_links_only: true,
        }

        extensions = {
          autolink: true,
          superscript: true,
          fenced_code_blocks: true,
          tables: true,
          disable_indented_code_blocks: false,
          strikethrough: true,
          underline: true,
          highlight: true,
          footnotes: true,
          with_toc_data: true,
        }

        renderer = HTMLBlockCode.new(options)
        markdown = Redcarpet::Markdown.new(renderer, extensions)

        markdown.render(text).html_safe
      end

      def rouge(text, language)
        formatter = Rouge::Formatters::HTML.new(scope: ".highlight")
        lexer = Rouge::Lexer.find(language)
        formatter.format(lexer.lex(text))
      end

      def rouge_markdown(text)
        render_options = {
          filter_html: true,
          hard_wrap: true,
          link_attributes: { rel: "nofollow" },
        }
        renderer = HTML.new(render_options)

        extensions = {
          autolink: true,
          fenced_code_blocks: true,
          lax_spacing: true,
          no_intra_emphasis: true,
          strikethrough: true,
          superscript: true,
        }
        markdown = Redcarpet::Markdown.new(renderer, extensions)
        markdown.render(text)
      end
    end

    class HTML < Redcarpet::Render::HTML
      include Rouge::Plugins::Redcarpet
    end

    class HTMLBlockCode < Redcarpet::Render::HTML
      include ActionView::Helpers::AssetTagHelper
      def header(title, level)
        if level == 7
          @headers ||= []
          permalink = title.gsub(/\W+/, "-")
          if @headers.include?(permalink)
            permalink += "_1"
            loop do
              break unless @headers.include?(permalink)

              permalink.gsub!(/_(\d+)$/, "_#{Regexp.last_match(1).to_i + 1}")
            end
          end
          @headers << permalink
          %(\n<a name="#{permalink}" class="markdown-header-anchor anchor" href="##{permalink}"><span class="fa fa-link anchor-icon"></span></a><h#{level} id=\"#{permalink}\">#{title}</h#{level}>\n)
        else
          %(\n<h#{level}>#{title}</h#{level}>\n)
        end
      end

      def image(link, title, alt_text)
        image_tag(link, title: title, alt: alt_text, class: "imageloader lazyload")
      end

      def preprocess(full_document)
        full_document.gsub(/\[component (.*)\]/) do
          @string = Regexp.last_match(1)
          @default_height = "160"
          @attr = ["", @default_height]

          # Set src from attributes
          @string.gsub(/src="(.*?)"/) do
            @attr[0] = Regexp.last_match(1)
          end

          # Set height from attributes
          @string.gsub(/height="(.*?)"/) do
            @attr[1] = (Regexp.last_match(1) || @default_height)
          end

          %(\n<div class="uix-component-frame"><iframe scrolling="no" id="component-preview" src="#{@attr[0]}" width="100%" height="#{@attr[1]}"></iframe><a href="#{@attr[0]}" target="_blank" class="uix-component-link">View component</a></div>\n)
        end
      end

      def list(contents, _list_type)
        @contents = contents
        @list_items = contents.split("\n")

        if @list_items[0].include?("[do]") || @list_items[0].include?("[dont]")
          @element_items = []
          @list_items.each do |item, _index|
            item.gsub(%r{<li>(.*)</li>}) do
              @element_items.push(Regexp.last_match(1))
            end
          end

          # Doing both because we could have either/both
          # clean up
          @dont_items, @trash_items_dont = @element_items.partition { |x, _i| x.include? "[dont]" }
          @do_items, @trash_items_do = @element_items.partition { |x, _i| x.include? "[do]" }

          @do_list = []
          @do_items.each do |item, _index|
            @do_list.push("<li>#{item.sub('[do] ', '')}</li>")
          end
          @do_list = "<ul class='uix-ruleset do-list'>#{@do_list.join('')}</ul>"

          @dont_list = []
          @dont_items.each do |item, _index|
            @dont_list.push("<li>#{item.sub('[dont] ', '')}</li>")
          end
          @dont_list = "<ul class='uix-ruleset dont-list'>#{@dont_list.join('')}</ul>"

          "<div class='row uix-ruleset-block'><div class='col-sm-6'>#{@do_list}</div><div class='col-sm-6'>#{@dont_list}</div></div>"
        else
          @contents
        end
      end
    end
  end
end