Wysiwyg Editor

by Greggg

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/2.24.2/js/uikit.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/2.24.2/css/uikit.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.9.0/codemirror.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.9.0/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.9.0/mode/xml/xml.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.9.0/mode/htmlmixed/htmlmixed.min.js"></script>
<script src="https://rawgit.com/Voog/wysihtml/master/dist/wysihtml-toolbar.min.js"></script>
<script src="https://rawgit.com/ZeGregg/wysihtml-master/bb3559f47623a9b909ba4d1fb76be418674044e4/parser_rules/advanced_and_extended.js"></script>
<!-- START TOOLBAR -->
<div id="toolbar" class="toolbar" data-uk-sticky>
  <!-- START GROUP 1 -->
  <div class="uk-button-group">
    <div class="uk-button-dropdown" data-uk-dropdown="{hoverDelayIdle:0}">
      <button class="uk-button test"><i class="uk-icon-bold"></i></button>
      <div class="uk-dropdown uk-dropdown-small uk-dropdown-bottom uk-dropdown-close">
        <ul class="uk-nav uk-nav-dropdown">
          <li><a class="uk-button" data-wysihtml5-command="bold" title="CTRL+B"><i class="uk-icon-bold"></i></a></li>
          <li><a class="uk-button" data-wysihtml5-command="italic" title="CTRL+I"><i class="uk-icon-italic"></i></a></li>
          <li><a class="uk-button" data-wysihtml5-command="strikethrough"><i class="uk-icon-strikethrough"></i></a></li>
          <li><a class="uk-button" data-wysihtml5-command="underline" title="CTRL+U"><i class="uk-icon-underline"></i></a></li>
          <li><a class="uk-button" data-wysihtml5-command="superscript" title="Sup"><i class="uk-icon-superscript"></i></a></li>
          <li><a class="uk-button" data-wysihtml5-command="subscript" title="Sub"><i...

CSS

body {
  margin: 1em;
}

::selection {
  opacity: 0.6;
  color: inherit;
}

#editor {
  outline: 1px dashed #CCC;
}


/* UIKIT STYLES OVERRIDE */

.uk-dropdown {
  width: auto !important;
  /*opacity: .6;*/
}

.uk-dropdown-small {
  min-width: 50px;
}

.uk-button {
  min-height: 28px;
  padding: 0 8px;
}

em {
  color: initial
}


/* COLOR STYLES */

.uk-color-set {
  font-size: 0;
  line-height: 0
}

.uk-color-set > * {
  display: inline-block;
  width: 32px;
  height: 32px;
  position: relative;
  z-index: 1;
}

.uk-color-set > *:hover {
  cursor: pointer;
  outline: 1px solid #000;
  outline-offset: -1px;
  z-index: 2
}

.uk-color-set > *.uk-selected-color::after {
  color: #ffffff;
  content: "\f00c";
  font-family: FontAwesome;
  font-size: 13px;
  font-weight: 400;
  line-height: 32px;
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
  text-align: center;
  cursor: default;
}

.uk-color-set > * > i {
  text-align: center;
  line-height: 32px;
  height: 32px;
  width: 32px;
  font-size: 13px;
  position: absolute;
  bottom: 0;
  cursor: default;
  left: 0;
}

code {
  background: #ddd;
  padding: 10px;
  white-space: pre;
  display: block;
  margin: 1em 0;
}

.impact {
  font-family: impact
}

.times {
  font-family: times
}


/* TABLE STYLE */

.wysihtml5-editor table {
  width: 100%;
  border-collapse: collapse;
}

.wysihtml5-editor table th,
.wysihtml5-editor table td {
  padding: 5px;
  vertical-align: middle;
  border: 1px solid #ddd;
}

.wysihtml5-editor table td.wysiwyg-tmp-selected-cell,
.wysihtml5-editor table th.wysiwyg-tmp-selected-cell {
  border: 1px double #1e88e5;
}


/* table selector */

.wysigrid {
  padding: 10px;
  line-height: initial;
}

.wysigrid table {
  border-collapse: collapse;
  line-height: 0;
}

.wysigrid td {
  padding: 0 2px 2px 0;
  display: none;
}

.wysigrid td > span {
  width: 12px;
  height: 12px;
  border: 1px solid #dddddd;
  display: inline-block;
}

.wysigrid .hover {
  background: rgba(30, 136,...

JavaScript

wysihtml5ParserRules.attributes = {
  'data-*': 'any'
}; /* in advanced_and_extended.js also now */

/* INIT EDITOR */
var editor = new wysihtml5.Editor(document.getElementById('editor'), {
    toolbar: document.getElementById('toolbar'),
    parserRules: wysihtml5ParserRules,
    useLineBreaks: false
  }),
  composer = editor.composer,
  cm; //code mirror

/* CODE MIRROR */
editor.on("change_view", function() {
  if (!cm) {
    setTimeout(_ => {
      cm = CodeMirror.fromTextArea(document.getElementsByClassName("wysihtml5-source-view")[0], {
        mode: /* "text/html"*/ "htmlmixed",
        lineNumbers: true,
        tabSize: 2,
        selectionPointer: true,
        lineWrapping: true
      });
    }, 0);
  } else {
    cm.toTextArea();
    cm = null;
  }
});


/* FONT FAMILY */
$('.impact').click(function() {
  composer.commands.exec("formatInline", {
    nodeName: "span",
    styleProperty: 'fontFamily',
    styleValue: 'impact, helvetica, sans serif'
  });
});
$('.times').click(function() {
  composer.commands.exec("formatInline", {
    nodeName: "span",
    styleProperty: 'fontFamily',
    styleValue: 'times, serif'
  });
});


/* MERGES SPAN STYLES */
editor.on("interaction", function() { /* need editor interaction to merge span !! */
  var spans = document.querySelectorAll('span');

  for (var i = 0; i < spans.length; i++) {
    if (spans[i].hasChildNodes() && spans[i].childNodes.length == 1 && spans[i].firstChild.tagName == 'SPAN') {
      var parent = spans[i];
      var child = spans[i].firstChild;

      // Copy new properties to child.
      for (var j = 0; j < parent.style.length; j++) {
        var prop = parent.style[j];
        if (child.style.getPropertyValue(prop) === "") {
          child.style.setProperty(prop, parent.style.getPropertyValue(prop), '');
        }
      }
      // Replace parent with child.
      parent.parentNode.insertBefore(child, parent);
      parent.parentNode.removeChild(parent);
    }
  }
});


/* COLOR MANAGER...