Skip to content

Commit

Permalink
update card docs
Browse files Browse the repository at this point in the history
  • Loading branch information
bantic committed Nov 24, 2015
1 parent bd83fc5 commit 5b87106
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 141 deletions.
201 changes: 89 additions & 112 deletions CARDS.md
Original file line number Diff line number Diff line change
@@ -1,133 +1,110 @@
## Mobiledoc Cards
# Mobiledoc Cards

Cards are an API supported by
[Mobiledoc Kit](https://github.com/bustlelabs/mobiledoc-kit),
the [Mobiledoc format](https://github.com/bustlelabs/mobiledoc-kit/blob/master/MOBILEDOC.md),
the [Mobiledoc DOM Renderer](https://github.com/bustlelabs/mobiledoc-dom-renderer)
and [Mobiledoc HTML Renderer](https://github.com/bustlelabs/mobiledoc-html-renderer).
the [Mobiledoc DOM Renderer](https://github.com/bustlelabs/mobiledoc-dom-renderer),
the [Mobiledoc HTML Renderer](https://github.com/bustlelabs/mobiledoc-html-renderer),
and the [Mobiledoc Text Renderer](https://github.com/bustlelabs/mobiledoc-text-renderer).

A card is an object with a name and at least one of several hooks defined. For example:

```js
var demoCard = {
name: 'demo',
display: {
setup(element) {
element.innerHTML = 'display demo content';
}
}
};
```
## Card format

A card is a javascript object with 3 *required* properties:

* `name` [string] - The name of this card in the mobiledoc
* `type` [string] - The output of this card. Valid values are 'dom', 'html', and 'text'
* `render` [function] - Invoked by the renderer to render this card

And one optional property, if this card will be used by an editor:

* `edit` [function] - Has the same signature as `render`, and can be invoked when the card
is being rendered by an editor (as opposed to rendered for display) to switch between "display"
and "edit" modes for a card in the editor.

## Card rendering

The `render` and (when present) `edit` functions on a card have the same signature. They
are called by an instance of a renderer and passed an object with the following three properties:

* `env` [object] - A set of environment-specific properties
* `options` [object] - Rendering options that were passed to the renderer (as `cardOptions`) when it was instantiated
* `payload` [object] - The data payload for this card from the mobiledoc

The return value of the `render` (and `edit`) functions will be inserted by the renderer into the rendered mobiledoc.
The return value can be null if a card does not have any output. If there is a return value it
must be of the correct type (a DOM Node for the dom renderer, a string of html or text for the html or text renderers, respectively).

In this minimally viable demo, a `display` hook is defined showing some text.
Given a Mobiledoc referencing `demo` as a card this text would render for that
name.
#### `env`

Cards are executed at runtime by a renderer. This means
you must pass any cards you want available to an editor or renderer. See the
documentation for each project on how to do this.
`env` always has the following properties:

### Available hooks
* `isInEditor` [boolean] - true when the card is being rendered by an editor (not being rendered for display)
* `name` [string] - the name of the card
* `onTeardown` [function] - The card can pass a callback function: `onTeardown(callbackFn)`. The callback will be called when the rendered content is torn down.

Between the [Mobiledoc Kit](https://github.com/bustlelabs/mobiledoc-kit) provided
editor,
the [Mobiledoc DOM Renderer](https://github.com/bustlelabs/mobiledoc-dom-renderer)
and [Mobiledoc HTML Renderer](https://github.com/bustlelabs/mobiledoc-html-renderer)
there are several hooks a complete card should define.
When being rendered by an editor (i.e., `env.isInEditor` is true), the env will have the following additional properties:

|Hook|Used by Mobiledoc Kit|Used by DOM Renderer|Used by HTML Renderer|
|---|---|---|---|
|`display`||||
|`edit`||||
|`html`||||
* `edit` [function] - This function can be called to switch the card to "edit" mode. It is a no-op if the card is already in edit mode
* `save` [function] - Used to save a new payload for a card. Typically called when the card is in "edit" mode to update the payload and transition
back to "display" mode. The function signature is `save(newPayload, transition=true)`. When `transition` is false the payload is
updated but the card is not switched to display mode
* `cancel` [function] - Called to transition from "edit" to "display" mode without changing the payload. It is a no-op if the card is in display mode already
* `remove` [function] - Removes this card from the document
* `postModel` [object] - The instance of this card's section in the editor's internal abstract tree. This can be used along with the mobiledoc-kit `postEditor` API to transform the card in other ways (for example, moving the card to a different section of the document)

Each hook has a `setup` and `teardown` method. The arguments are:
## Renderers

All of the officially-supported mobiledoc renderers have the same signature and methods.
To instantiate a renderer, call its constructor with an object of options that has any of the following optional properties:

* `cards` [array] - The cards that your mobiledoc includes and that the renderer will encounter
* `cardOptions` [object] - Options to be passed to the card `render` (or `edit`) function
* `unknownCardHandler` [function] - This function is called (with the same arguments as `render`) whenever the renderer encounters a card that doesn't
match one of the `cards` it has been provided

An instance of a renderer has one method, `render`. This method accepts a mobiledoc and returns an object with two properties:
* `result` [mixed] - The rendered result. Its type depends on the renderer, and can be a DOM Node (dom renderer) or a string (html or text renderers)
* `teardown` [function] - Call this function to tear down the rendered mobiledoc. The dom renderer will remove the rendered dom from the screen. All renderers will call
the card teardown callbacks that were registered using `env.onTeardown(callbackFunction)`

Example usage of a renderer:
```js
var exampleCard = {
name: 'example',
display: {
setup(element, options, env, payload) {},
teardown(setupReturnValue) {}
},
edit: {
setup(element, options, env, payload) {},
teardown(setupReturnValue) {}
},
html: {
setup(buffer, options, env, payload) {},
teardown(setupReturnValue) {}
}
};
let renderer = new DOMRenderer({cards: [card1, card2], cardOptions: {foo: 'bar'});
let rendered = renderer.render(mobiledoc);

document.body.appendChild(renderered.result);

// later...

rendered.teardown(); // removes the rendered items, calls teardown hooks
```
* `element` is a DOM element for that section. Nodes of that view for a card
should be appended to the `element`.
* `buffer` is an array passed to the `html` hook instead of a DOM element.
The content for the card should be pushed on that array as a string.
* `options` is the `cardOptions` argument passed to the editor or renderer.
* `env` contains information about the running of this hook. It may contain
the following properties:
* `env.name` The name of this card
* `env.save(payload)` will save a new payload for a card instance. `save`
also accepts a boolean as a second argument, `true` if the card should
be transitioned to `display` and `false` if it should remain in `edit`
mode. The default behavior is to transition to `display`.
* `env.cancel()` will swap a card in edit mode to display without changing
the payload.
* `env.edit()` is available to the `display` setup, and when called swaps
the instance to edit mode.
* `env.remove()` remove this card. This calls the current mode's `teardown()`
hook and removes the card from DOM and from the post abstract.
the instance to edit mode.
* `env.section` the CardSection from the Post -- this can be used when
programmatically interacting with the card, for example to move the card
using `editor.run(postEditor => postEditor.moveSectionUp(section)`.
* `payload` is the payload for this card instance. It was either loaded from
a Mobiledoc or generated and passed into an `env.save` call.

Additionally, *renderers may offer the ability to configure a non-standard
hook name at runtime*. An example would be having the DOM renderer called with
an option specifying the hook name `mobile-placeholder`. This allows for
variants of a card in different situations.

### Card Lifecycle

Cards rendered by the Mobiledoc Kit editor may move between `edit` and `display` hooks
many times after being added (or loaded from a Mobiledoc). The can do this
by calling the functions passed to `env`.

The `env.save` function accepts the argument of a payload, which is passed to
later setup calls. A minimal editable component would look like:
## Card examples
Example dom card that renders an image:
```js
var displayTextCard = {
name: 'display-text',
display: {
setup(element, options, env, payload) {
$('<div>').text(payload.text).appendTo(element);
if (env.edit) {
$('<button>Edit</button>').appendTo(element).on('click', env.edit);
}
$('<button>Remove</button>').appendTo(element).on('click', env.remove);
}
},
edit: {
setup(element, options, env, payload) {
$('<div>Edit this card:</div>').appendTo(element);
let input = $('<input>');
if (payload.text) {
input.val(payload.text);
}
$('<button>Save</button>').appendTo(element).on('click', function() {
env.save(input.val());
});
$('<button>Cancel</button>').appendTo(element).on('click', env.cancel);
}
}
let card = {
name: 'simple-image',
type: 'dom',
render({env, options, payload}) {
let src = payload.src || 'http://placekitten.com/100x100';
let img = document.createElement('img');
img.src = src;
return img;
}
};
```
Additionally, if anything is returned from `setup` that result will be passed
to `teardown` as the only argument. This allows you to pass a reference to
any objects you may have created during `setup` for destruction.
Example dom card that registers a teardown callback:
```js
let card = {
name: 'card-with-teardown-callback',
type: 'dom',
render({env, options, payload}) {
env.onTeardown(() => {
console.log('tearing down card named: ' + env.name);
});
}
};
```
46 changes: 17 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@

[![Join the chat at https://gitter.im/bustlelabs/mobiledoc-kit](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bustlelabs/mobiledoc-kit?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

Mobiledoc Kit (WARNING: beta!!) is a library for buildling WYSIWYG editors
supporting rich content via cards. Try a
demo at [bustlelabs.github.io/mobiledoc-kit/demo](http://bustlelabs.github.io/mobiledoc-kit/demo/).
Mobiledoc Kit (warning: beta) is a library for building WYSIWYG editors
supporting rich content via cards.

* Posts are serialized to a JSON payload called **Mobiledoc** instead of to
**Try a demo at [bustlelabs.github.io/mobiledoc-kit/demo](http://bustlelabs.github.io/mobiledoc-kit/demo/)**.

* Posts are serialized to a JSON format called **Mobiledoc** instead of to
HTML. Mobiledoc can be rendered for the web, mobile web, or in theory on any
platform. Mobiledoc is portable and fast.
* The editor makes limited use of Content Editable, the siren-song of doomed
web editor technologies.
* Mobiledoc is designed for *rich* content. We call these sections of an
article "cards", and implementing a new one doesn't require an understanding
of Mobiledoc editor internals. Adding a new card takes an afternoon, not several
days.
days. To learn more about cards and mobiledoc renderers, see the **[Cards docs](https://github.com/bustlelabs/mobiledoc-kit/blob/master/CARDS.md)**.

To learn more about the ideas behind Mobiledoc and the editor (note that the
editor used to be named Content-Kit), see these blog posts:
Expand All @@ -25,8 +26,8 @@ editor used to be named Content-Kit), see these blog posts:
* [Building the Content-Kit Editor on Content Editable](https://medium.com/@bantic/building-content-kit-editor-on-contenteditable-99a94871c951)
* [Content-Kit: Programmatic Editing](http://madhatted.com/2015/8/25/content-kit-programmatic-editing)

The Mobiledoc kit saves posts to
**[Mobiledoc](https://github.com/bustlelabs/mobiledoc-kit/blob/master/MOBILEDOC.md)**.
The Mobiledoc kit saves posts in
**[Mobiledoc format](https://github.com/bustlelabs/mobiledoc-kit/blob/master/MOBILEDOC.md)**.

### Usage

Expand All @@ -50,11 +51,12 @@ editor.render(element);

`options` is an object which may include the following properties:

* `placeholder` - default text to show before a user starts typing.
* `spellcheck` - a boolean option enabling spellcheck. Default is true.
* `autofocus` - a boolean option for grabbing input focus when an editor is
rendered.
* `cards` - an object describing available cards.
* `placeholder` - [string] default text to show before a user starts typing.
* `spellcheck` - [boolean] whether to enable spellcheck. Defaults to true.
* `autofocus` - [boolean] When true, focuses on the editor when it is rendered.
* `cards` - [array] The list of cards that the editor may render
* `cardOptions` - [object] Options passed to
* `unknownCardHandler` - [function] This will be invoked by the editor-renderer whenever it encounters an unknown card

### Editor API

Expand Down Expand Up @@ -159,21 +161,7 @@ Modifiers can be any of `CTRL`, `META`, `SHIFT`, or `ALT`.

The key can be any of the alphanumeric characters on the keyboard, or one of the following special keys:

* `BACKSPACE`
* `TAB`
* `ENTER`
* `ESC`
* `SPACE`
* `PAGEUP`
* `PAGEDOWN`
* `END`
* `HOME`
* `LEFT`
* `UP`
* `RIGHT`
* `DOWN`
* `INS`
* `DEL`
`BACKSPACE`, `TAB`, `ENTER`, `ESC`, `SPACE`, `PAGEUP`, `PAGEDOWN`, `END`, `HOME`, `LEFT`, `UP`, `RIGHT`, `DOWN`, `INS`, `DEL`

#### Overriding built-in keys

Expand All @@ -194,9 +182,9 @@ To fall-back to the default behavior, return `false` from `run`.

### Configuring text expansions

Text expansions can also be registered with the editor. These are methods that
Text expansions can also be registered with the editor. These are functions that
are run when a text string is entered and then a trigger character is entered.
For example, the text `"*"` followed by a space character triggers a method that
For example, the text `"*"` followed by a space character triggers a function that
turns the current section into a list item. To register a text expansion call
`editor.registerExpansion` with an object that has `text`, `trigger` and `run`
properties, e.g.:
Expand Down

0 comments on commit 5b87106

Please sign in to comment.