Lightweight Markdown Editor

In this example below you will see how to do a Lightweight Markdown Editor with some HTML / CSS and Javascript

Looking to replace a clunky old wysiwyg editor, this is a first draft at working with markdown and a real-time preview.

Thumbnail
This awesome code was written by anatomic, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright anatomic ©

Technologies

  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>Lightweight Markdown Editor</title>
  
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">

  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  <h1>Basic Markdown Editor</h1>
<p class="lede">Lightweight markdown editor with a live preview underneath. Next steps is to include a simple method for inserting placeholders for images that allow drag and drop upload.</p>
<p>Also includes some basic features for keyboard shortcuts, try with cmd+i (ctrl+i) and cmd+b (ctrl+b) either on a text selection or while in the editor.</p>
<p><b>Experimental</b> - I've had a play with a very basic implementation of undo and redo - access via (ctrl+z) and (ctrl+r) even on a mac
<h2>Editor</h2>
<textarea id="content">
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
  
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.  
</textarea>
<h2>Preview</h2>  
<div id="preview"></div>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.js'></script>

  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/anatomic/lightweight-markdown-editor-WvKeYY */
body {
  padding: 1em;
  font-size: 0.875em;
  line-height: 1.5;
  color: #5b5b5b;
}

.lede {
  font-size: 1rem;
}

#content {
  width: 100%;
  height: 40vh;
  padding: 1.5em;
  margin: 1em 0;
  border: none;
  background-color: #f8f8f8;
  box-sizing: border-box;
  resize: none;
}
#content:focus {
  outline: none;
  background-color: #f3f3f3;
}

#preview {
  width: 100%;
  height: 40vh;
}

h1 {
  padding-bottom: 0.2em;
  margin-bottom: 0.6em;
  border-bottom: 1px solid #f0f0f0;
}

h2 {
  margin-bottom: 0.2em;
}


/*Downloaded from https://www.codeseek.co/anatomic/lightweight-markdown-editor-WvKeYY */
marked.setOptions({
  renderer: new marked.Renderer(),
  gfm: true,
  tables: true,
  breaks: false,
  pedantic: false,
  sanitize: true,
  smartLists: true,
  smartypants: false
});
var undoStack = [];
var redoStack = [];
var undoTimeout = void 0;
var editor = document.querySelector('#content');
var preview = document.querySelector('#preview');

preview.innerHTML = marked(editor.value);

function updateStack(text, immediate) {
  if (undoTimeout) {
    clearTimeout(undoTimeout);
  }

  undoTimeout = setTimeout(function () {
    undoStack.push(text);

    if (undoStack.length > 50) {
      undoStack.shift();
    }
  }, immediate ? 0 : 200);
}

function undo() {
  if (undoStack.length > 1) {
    redoStack.push(undoStack.pop());
    editor.value = undoStack.pop();
    preview.innerHTML = marked(editor.value);
  }
}

function redo() {
  if (redoStack.length) {
    updateStack(editor.value, true);
    editor.value = redoStack.pop();
    preview.innerHTML = marked(editor.value);
  }
}

editor.addEventListener('input', function (e) {
  updateStack(editor.value);
  preview.innerHTML = marked(editor.value);
  redoStack = [];
});

editor.addEventListener('keypress', function (e) {
  if (e.metaKey || e.ctrlKey) {
    var text = editor.value;
    var start = editor.selectionStart;
    var end = editor.selectionEnd;
    var selection = text.slice(start, end);
    var replacement = selection;
    var keyCode = e.key || e.keyCode || e.charCode || e.char;

    switch (keyCode) {
      case 105:
        replacement = '*' + selection + '*';
        break;
      case 98:
        replacement = '**' + selection + '**';
        break;

      case 26:
        undo();
        return;

      case 18:
        redo();
        return;
    }

    var diff = replacement.length - selection.length;
    if (diff === 0) {} else {
      updateStack(text);
      redoStack = [];
    }

    text = text.slice(0, start) + replacement + text.slice(end);
    editor.value = text;
    preview.innerHTML = marked(editor.value);
    if (selection.length) {
      editor.setSelectionRange(start, end + diff);
    } else {
      var sel = start + diff / 2;
      editor.setSelectionRange(sel, sel);
    }
  }
});

Comments