/Preview-In-Place

A plain JS library for building an in-place preview similar to Typora (typora.io)

Apache License 2.0Apache-2.0

Preview In Place

A simple plain JS library for building an 'in-place preview'. With inspiration from Typora (the wonderfully minimalistic markdown editor).

Demo: https://preview-in-place.vercel.app/

Installation

To install, you can either copy the previewinplace.js or previewinplace.min.js files into your project or use a cdn:

<script src="dist/previewinplace.min.js"></script>

or

<script src="https://cdn.jsdelivr.net/gh/JackChilds/Preview-In-Place@main/dist/previewinplace.min.js"></script>

Usage

The HTML for the in place preview should look something like this:

<div id="idOfElement" class="block">
  <textarea class="edit">Some Text Here</textarea>
  <div class="preview"></div>
</div>

A div container with class 'block', with 2 child elements with class names 'edit' and 'preview'. Note: if you are using class prefixes you will need to change the class names.

Basic Setup

For a complete file, see the demo/index.html.

// get element:
var el = document.querySelector('#idOfElement')
// function to process the user's data, e.g. you could convert markdown to HTML here:
function processData(data) {
  return data.toUpperCase() // do something with the data here
}
// initialise the class:
var example = new PreviewInPlace(el, {
  // options
  previewGenerator: processData // reference to the function that processes the data
})

Options

Property Type Info
previewGenerator function reference Required: function reference that processes the data and returns the HTML content for the preview element. Note: if sanitisePreview is false, return value is not sanitised and is injected as HTML.
defaultIsPreview boolean Optional: if true then the 'preview' mode is the default, if false then the 'edit' mode is the default. Default: true
classPrefix string Optional: the prefix that is added in front of class references. Default:'' (no prefix)
editValue function reference or undefined or false Optional: function reference that gets the value of the user's input and returns a string. If not specified (or false) then the .value property of the element with the class 'edit' is used (which works with textareas and input tags). Default: false
loadDefaultCSS boolean Optional: if true then the default CSS will be injected into the <head> tag of the page. The default CSS file ensures that the edit and preview elements are aligned on top of each other, for more details, see the default css below this table. Default: true
sanitisePreview boolean Optional: if true then data returned from the previewGenerator function will be sanitised through the use of DOMElement.textContent instead of DOMElement.innerHTML. Default: true (recommended to prevent HTML injection attacks)
events.onPreview function reference or undefined Optional: function reference that gets called when the block enters preview mode. Default:undefined
events.onEdit function reference or undefined Optional: function reference that gets called when the block enters edit mode. Default:undefined

Default CSS

A tiny bit of CSS that is injected into the <head> tag of the page to ensure that the block displays correctly with the edit and preview elements on top of each other. Note: the CSS is automatically changed when you are using class prefixes.

.block {
    position: relative;
    display: grid
}

.block .edit,
.block .preview {
    grid-column: 1;
    grid-row: 1
}

Class Methods

Method Type Info
init (element, options) function The same method as the constructor, useful if you want to re-initialise the class with different settings at a later point.
mode property Get : the current mode the element is in. Either previewor edit.
Set : the mode the element is in. Use either preview or edit.
toggleMode() function Toggles the block between preview and edit.
editVal property Get : the value of the edit element.
previewVal property Get : the value of the preview element as a HTML string.
el property Get : the block element, edit element and preview element as a dictionary.
{block : blockElement, edit : editElement, preview: previewElement}

Examples

Class Prefixes

HTML:

<div class="prefix-block">
  <textarea class="prefix-edit">Some Text</textarea>
  <div class="prefix-preview"></div>
</div>

JS:

...
new PreviewInPlace (el, {
  previewGenerator: processData,
  classPrefix: 'prefix-'
})
...

Getting the value of the editor manually

HTML:

<div class="block">
  <textarea class="edit" id="editor-id">Some Text</textarea>
  <div class="preview"></div>
</div>

JS:

...
function getEditValue() {
  return document.querySelector('#editor-id').value
}

new PreviewInPlace(el, {
  previewGenerator: processInput,
  editValue: getEditValue
})
...

Events

HTML:

<div class="block">
  <textarea class="edit">Some Text Here</textarea>
  <div class="preview"></div>
</div>

JS:

...
function previewMode() {
  console.log("Preview mode")
}
function editMode() {
  console.log("Edit mode")
}

new PreviewInPlace(el, {
  previewGenerator: processInput,
  events: {
    onPreview: previewMode,
    onEdit: editMode
  }
})
...

Toggle Mode

HTML:

<div class="block">
  <textarea class="edit">Some Text Here</textarea>
  <div class="preview"></div>
</div>
<button onclick="toggleMode()">Toggle Mode</button>

JS:

...
var example = new PreviewInPlace(el, {
  previewGenerator: processInput,
})

function toggleMode() {
  example.toggleMode()
}
...

Styling

You can style the block differently in CSS depending on which mode it is in by using the state-preview and state-edit classes that are added to the block when in the preview mode and edit mode, respectively. Note: if using class prefixes then you will have to change class names in your css.

An example of some basic CSS used to style the block depending on which mode it is in (taken from the demo file):

/* Some basic styling of the 'block' and the 'edit' and 'preview' elements  */
.block {
  width: 200px;
}
.block .edit {
  border: none;
  outline: none;
  border-radius: 0;
  resize: none;
}
.block .edit, .block .preview {
  padding: 8px;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 16px;
}

/* Make the 'block' have a red background when in edit mode */
.block.state-edit .edit {
  background-color: rgba(131, 0, 0, 0.3);
}
/* Make the 'block' have a green background when in preview mode */
.block.state-preview .preview {
  background-color: rgba(9, 174, 0, 0.3);
}