class Object

Constants

ElementalCreation

Entry-point for MediaMolecules to render HTML (and maybe eventually other formats!).

Liquid is arguably a poor choice for this use case since it is designed to handle arbitrary user-supplied templates in a safe way, versus e.g. ERB which allows in-template execution of arbitrary Ruby code, but our templates are bundled here in the Gem (ostensibly) should be trustworthy.

I considered using Nokogiri's DocumentFragment Builder instead: fragment = Nokogiri::HTML::DocumentFragment.parse(''.freeze) Nokogiri::HTML::Builder.with(fragment) do |doc|

doc.picture {
  changes.each { |change| doc.source(:srcset=change.name) }
}

end fragment.to_html

But the way DistorteD works (with MIME::Type#distorted_template_method) means we would need a way to collate child elements anyway, since each call to a :distorted_template_method should generate only one variation, meaning we'd end up with a bunch of <source> tag Strings but would still need to collect them under a parent <picture> with a sibling <img>.

Liquid is already heavily used by Jekyll, and of course DistorteD-Jekyll itself is a Liquid::Tag, so we may as well use it. Nokogiri, on the other hand, is not an explicit dependency of Jekyll. It will most likely be available, and DD itself pulls it in via SVGO and others, but Liquid will also allow us the flexibility to render formats other than just HTML/XML, e.g. BBCode or even Markdown.

I might revisit this design decision once I experience working with more media formats and in more page contexts :)

FATAL_FURY
MD_IMAGE_REGEX

Replace standard Markdown image syntax with instances of DistorteD via its Liquid tag.

SYNTAX

I'm calling individual media elements “images” here because I'm overloading the Markdown image syntax to express them. There is no dedicated syntax for other media types in any flavor of Markdown as of 2019, so that seemed like the cleanest and sanest way to deal with non-images in DistorteD.

DistorteD::Invoker will do the media type inspection and handling once we get into Liquid Land. This is the approach suggested by CommonMark: talk.commonmark.org/t/embedded-audio-and-video/441/15

Media elements will display as a visibly related group when two or more Markdown image tags exist in consecutive Markdown unordered (e.g. *-+) list item or ordered (e.g. 1.) list item lines. Their captions should be hidden until opened in a lightbox or as a tooltip on desktop browsers via ::hover state.

The inspiration for this display can be seen in the handling of two, three, or four images in any single post on Tw*tter. DistorteD expands on the concept by supporting things such as groups of more than four media elements and elements of heterogeneous media types.

Standalone image elements (not contained in list item) should be displayed as single solo elements spanning the entire usable width of the container element, whatever that happens to be at the point where our regex excised a block of Markdown for us to work with.

TECHNICAL CONSIDERATIONS

Jekyll processes Liquid templates before processing page/post Markdown, so we can't rely on customizing the Markdown renderer's `:img` element output as a means to invoke DistorteD. jekyllrb.com/tutorials/orderofinterpretation/

Prefer the POSIX-style bracket expressions (e.g. [[:digit:]]) over basic character classes (e.g. d) in regex because they match Unicode instead of just ASCII. ruby-doc.org/core/Regexp.html#class-Regexp-label-Character+Classes

INLINE ATTRIBUTE LISTS

Support additional arguments passed to DistorteD via Kramdown-style inline attribute lists. kramdown.gettalong.org/syntax.html#images kramdown.gettalong.org/syntax.html#inline-attribute-lists

IALs can be on the same line or on a line before or after their associated flow element. In ambiguous situations (flow elements both before and after an IAL), the IAL applies to the flow element before it. All associated elements and IALs must be on contiguous lines.

This page provides a regex for parsing IALs, Section 5.3: golem.ph.utexas.edu/~distler/maruku/proposal.html

SOLUTION

A `pre_render` hook uses this regex to process Markdown source files and replace instances of the Markdown image syntax with instances of DistorteD's Liquid tags. Single images will be replaced with {% distorted %}. Multiple list-item images will be replaced with a {% distort %} block.

By doing with with a regex (sorry!!) I hope to avoid a hard dependency on any one particular Markdown engine. Though I only support Kramdown for now, any engine that supports IALs should be fine.

High-level explanation of what we intend to match:

{:optional_ial => line_before_image} # Iff preceded by a blank line! (optional_list_item)? ![alt](image){:optional_ial => same_line} {:optional_ial => next_consecutive_line} Repeat both preceding matches (together) any number of times to parse a {% distort %} block. See inline comments below for more detail.

UPDATE_RUBY

Public Instance Methods

md_injection() click to toggle source
# File lib/distorted-jekyll/md_injection.rb, line 151
def md_injection
  Proc.new { |document, payload|
    # Compare any given document's file extension to the list of enabled
    # Markdown file extensions in Jekyll's config.
    if payload['site']['markdown_ext'].include? document.extname.downcase[1..-1]
      # Convert Markdown images to {% distorted %} tags.
      #
      # Use the same Markdown parser as Jekyll to avoid parsing inconsistencies
      # between this pre_render hook and the main Markdown render step.
      # This is still effectively a Markdown-parsing regex (and still
      # effectively a bad idea lol) but it's the cleanest way I can come up
      # with right now for separating DistorteD-destined Markdown from
      # the rest of any given page.
      # NOTE: Attribute List Definitions elsewhere in a Markdown document
      # will be lost when converting this way. I might end up just parsing
      # the entire document once with my own `to_liquid` converter, but I've been
      # avoiding that as it seems wasteful because Jekyll then renders the entire
      # Markdown document a second time immediately after our Liquid tag.
      # It's fast enough that I should stop trying to prematurely optimize this :)
      # TODO: Implement MD → DD love using only the #{CONFIGURED_MARKDOWN_ENGINE},
      # searching for :img elements inside :li elements to build BLOCKS.
      document.content = document.content.gsub(MD_IMAGE_REGEX) { |match| 
        Kramdown::Document.new(match).to_liquid
      }
    end
  }
end
update_ruby() click to toggle source
# File lib/distorted-jekyll.rb, line 9
def update_ruby
  if defined? RUBY_PLATFORM
    if (/freebsd/ =~ RUBY_PLATFORM) != nil
      return 'pkg install lang/ruby27'
    elsif (/darwin/ =~ RUBY_PLATFORM) != nil
      return 'brew upgrade ruby'
    elsif (/win/ =~ RUBY_PLATFORM) != nil
      return 'https://rubyinstaller.org/'
    elsif (/linux/ =~ RUBY_PLATFORM) != nil
      if File.exists?('/etc/lsb-release')
        lsb = File.read('/etc/lsb-release')
        if (/Ubuntu|LinuxMint/ =~ lsb) != nil
          return 'https://www.brightbox.com/docs/ruby/ubuntu/#installation'
        end
      end
    end
  end
  return 'https://github.com/rbenv/ruby-build'
end