Permalink
57670bb Nov 16, 2016
@bantic @mixonic @rlivsey
197 lines (163 sloc) 6.42 KB

Mobiledoc

Mobiledoc is a simple post or article format that aims to be:

  • Platform agnostic. Should be possible to render without an HTML parser.
  • Efficient to transfer. Compresses well, and limits the duplication of content.
  • Extensible at runtime. Stores content, not layout or final display.

Mobiledoc is primarily intended to be used for news-related content such as articles and blog posts. It is deliberately simple, and organizes its content in an array of "sections" that are considered as individual blocks of content.

There is no concept of layout or design built into Mobiledoc. It is up to the renderer to generate a display appropriate for its context. On mobile this may mean each section is full-width and they are displayed sequentially. On larger displays the sections may be rendered side-by-side. Mobiledoc makes no prescription for output display.

Usage

Often Mobiledoc will be used with one or more of:

Specification

Mobiledoc consists of a wrapping object, type definitions for markup, atoms and cards, and an array of section data. Using arrays makes Mobiledocs each to render quickly.

The wrapper signature:

{
  version: "0.3.1",                         ──── Versioning information
  markups: [                              ──── Ordered list of markup types
    markup,
    markup
  ],
  atoms: [                                ──── Ordered list of atom types
    atom,
    atom
  ],
  cards: [                                ──── Ordered list of card types
    card,
    card
  ],
  sections: [                             ──── Ordered list of sections.
    section,
    section,
    section
  ]
}

Markup definition signature

Markups have a tagName and an optional array of attributes. Not all markups can have attributes, but for those that do the attributes array is a single array of all the attribute names and values, one after another. E.g., ["a", ["href", "http://bustle.com", "target", "_blank"].

{
  version: "0.3.1",
  markups: [
    [tagName, optionalAttributesArray],   ──── Markup
    ["em"],                               ──── Example simple markup with no attributes
    ["a", ["href", "http://google.com", "target", "_blank"]], ──── Example markup with 2 attributes ("href" and "target")
  ]
}

Atom definition signature

Atoms have a name, text value and arbitrary payload.

{
  version: "0.3.1",
  atoms: [
    [atomName, atomText, atomPayload],    ──── Atom
    ['mention', '@bob', { id: 42 }]       ──── Example 'mention' atom
  ]
}

Card definition signature

Cards have a name and arbitrary payload.

{
  version: "0.3.1",
  cards: [
    [cardName, cardPayload],            ──── Card
    ['image', {                         ──── Example 'image' card
      src: 'http://google.com/logo.png'
    }]
  ]
}

Markup Section

Markup sections, in addition to plain text, can include markups and atoms.

{
  version: "0.3.1",
  markups: [
    ["b"],                                ──── Markup at index 0
    ["i"]                                 ──── Markup at index 1
  ],
  atoms: [
    ["mention", "@bob", { id: 42 }]       ──── mention Atom at index 0
    ["mention", "@tom", { id: 12 }]       ──── mention Atom at index 1
  ]
  sections: [
    [sectionTypeIdentifier, tagName, markers],   ──── sectionTypeIdentifier for markup sections
    [1, "h2", [                                       is always 1.
      [0, [], 0, "Simple h2 example"],
    ]],
    [1, "p", [
      [textTypeIdentifier, openMarkupsIndexes, numberOfClosedMarkups, value],
      [0, [], 0, "Example with no markup"],      ──── textTypeIdentifier for markup is always 0
      [0, [0], 1, "Example wrapped in b tag (opened markup #0), 1 closed markup"],
      [0, [1], 0, "Example opening i tag (opened markup with #1, 0 closed markups)"],
      [0, [], 1, "Example closing i tag (no opened markups, 1 closed markup)"],
      [0, [1, 0], 1, "Example opening i tag and b tag, closing b tag (opened markups #1 and #0, 1 closed markup [closes markup #1])"],
      [0, [], 1, "Example closing b tag, (no opened markups, 1 closed markup [closes markup #0])"],
    ]],
    [1, "p", [
      [textTypeIdentifier, openMarkupsIndexes, numberOfClosedMarkups, atomIndex],
      [1, [], 0, 0],             ──── mention atom at index 0 (@bob), textTypeIdentifier for atom is always 1
      [1, [0], 1, 1]             ──── mention atom at index 1 (@tom) wrapped in b tag (markup index 0)
    ]],
  ]
}

A section tagName must be one of:

  • aside
  • blockquote
  • h1
  • h2
  • h3
  • h4
  • h5
  • h6
  • p

The index in openMarkupsIndex specifies which markups should be opened at the start of the value text. As these tags are opened, then create a stack of opened markups. The numberOfClosedMarkups says how many of those opened markup tags should be closed at the end of a value.

In addition to markers, markup sections may contain ATOMS. Atoms in a markup section have a textTypeIdentifier of 1 and contain an atomTypeIndex. They also contain the same openMarkupsIndex and numberOfClosedMarkups values that other markers have, so that markup can flow across them.

A markup definition array's first item (the markup tagName) must be one of:

  • a - Hypertext link
  • b - Bold
  • code - Code
  • em - Emphasis
  • i - Italic
  • s - Strike-through
  • strong - Strong
  • sub - Subscript
  • sup - Superscript
  • u - Underline

If an atom is present in Mobiledoc but no atom implementation is registered, the text value of the atom will be rendered as plain text as a fallback.

Card Section

{
  version: "0.3.1",
  cards: [
    ["card-name", { cardPayload }]
  ],
  sections: [
    [typeIdentifier, cardIndex],                 ──── typeIdentifier for card sections
    [10, 0]                                           is always 10.
  ]
}

cardPayload is arbitrary and should be passed through to the card implementation.