Javascript HTML editor

Javascript Best Practices

Javascript HTML editor with a preview pane


Date : 2006-02-14
This HTML page has everything it takes, javascript, CSS, HTML to build a nifty little HTML editor/preview tabbed box. On IE it will even do auto indentation. It uses a regualar form textarea so it works well on many browsers.

It's been tested on:
IE6
Firefox1.5
Opera7.5
NS7.2
Mozilla1.7.5

The auto indent function only works on IE, but doesn't cause trouble with other browsers.

Please feel free to make upgrades and changes to this code but please notify us so we can make additions to the original and everyone can benefit.

Watch for the newline characters in the code below. The article handler keeps messing with the javascript newline characters, so if you see "n" it needs to be a javascript newline character.

You should be able to cut and paste the whole thing and save it as an HTML file and it will work.

Ok... Here it is... What you've been waiting for:
Code:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Javascript HTML editor from bestcodingpractices.com</title>
<script language="JavaScript1.2">
    function showPane(tabID) {
      tab1 = document.getElementById('tab_1');
      pane1 = document.getElementById('pane_1');
      tab2 = document.getElementById('tab_2');
      pane2 = document.getElementById('pane_2');
      content_el = document.getElementById('HTMLContent');
      preview_area = document.getElementById('Preview_content');
      if (tabID == 1) {
        tab1.style.top = '1px';
        tab1.style.zIndex = '2';
        pane1.style.display = 'block';
        tab2.style.top = '3px';
        tab2.style.zIndex = '1';
        pane2.style.display = 'none';
      } else if (tabID == 2) {
        try {
          HTMLcontent = content_el.value;
          preview_area.innerHTML = HTMLcontent;
          tab2.style.top = '1px';
          tab2.style.zIndex = '2';
          pane2.style.display = 'block';
          tab1.style.top = '3px';
          tab1.style.zIndex = '1';
          pane1.style.display = 'none';
        } catch(err) {
          txt="There has been an error trying to preview your HTML.n This is probably caused by browser limitationn" +
              "or security settings.  Some browsers will not allow n dynamic forms to be created which will cause\n" +
              "this error.  You should still be able to edit the HTML\n and submit it but you will be unable to preview."
          alert(txt)
        }
      }
      return false;
    }
    function storeCaret (textEl) {
       if (textEl.createTextRange) {
         textEl.focus();
         textEl.caretPos = document.selection.createRange().duplicate();
       }
    }
    function insertAtCaret (textEl, text) {
      if (textEl.createTextRange && textEl.caretPos) {
        var caretPos = textEl.caretPos;
        caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? text + ' ' : text;
      } else {
        textEl.value  = text;
      }
    }
    function handleKey(e)
    {
      var code;
      if (!e) var e = window.event;
      if (e.keyCode) code = e.keyCode;
      else if (e.which) code = e.which;
      var character = String.fromCharCode(code);
      if (code == 13) {
        var tArea = document.getElementById('HTMLContent');
        storeCaret(tArea);
        var hPos = getCursorPos(tArea);
        var hTXT = getCorrectPadding(tArea);
        insertAtCaret(tArea,hTXT);
        event.keyCode = 0;
      }
    }
    function insertTemplateMarker(el,textarea) {
      var tArea = document.getElementById('HTMLContent');
      storeCaret(tArea);
      insertAtCaret(tArea,"%" + el.options[el.selectedIndex].value.toUpperCase() + "%");
      el.selectedIndex = 0;
    }
    function getCursorPos(textElement) {
      var sOldText = textElement.value;
      var objRange = document.selection.createRange();
      var sOldRange = objRange.text;
      var sUniqueString = '#^~';

      objRange.text = sOldRange + sUniqueString;
      objRange.moveStart('character', (0 - sOldRange.length - sUniqueString.length));

      var sNewText = textElement.value;
      objRange.text = sOldRange;
      for (i=0; i <= sNewText.length; i++) {
        var sTemp = sNewText.substring(i, i + sUniqueString.length);
        if (sTemp == sUniqueString) {
          var cursorPos = (i - sOldRange.length);
          return cursorPos;
        }
      }
    }
    function getCorrectPadding(textElement) {
      var sOldText = textElement.value;
      var objRange = document.selection.createRange();
      var sOldRange = objRange.text;
      var sUniqueString = '#^~';
      objRange.text = sOldRange + sUniqueString;
      objRange.moveStart('character', (0 - sOldRange.length - sUniqueString.length));
      var sNewText = textElement.value;
      objRange.text = sOldRange;
      for (i=0; i <= sNewText.length; i++) {
        var sTemp = sNewText.substring(i, i + sUniqueString.length);
        if (sTemp == sUniqueString) {
          var cursorPos = (i - sOldRange.length);
          var chktxt = sNewText.substring(0,cursorPos);
          var linestart = chktxt.lastIndexOf("\n");
          if (linestart == -1) { linestart = 0; }
          var lastline = chktxt.substring(linestart);
          var bl="\n";
          var nc=false;
          for (x=1;x<lastline.length;x++) {
            if ((lastline.charAt(x) == ' ') && (nc == false)) {
              bl += " ";
            } else {
              nc = true;
            }
          }
          return bl;
        }
      }
    }
    function insertString(stringToInsert,cursorPos) {
      El = document.getElementById('HTMLContent');
      var firstPart = El.value.substring(0, cursorPos);
      var secondPart = El.value.substring(cursorPos,El.value.length);
      El.value = firstPart + stringToInsert + secondPart;
    }
</script>
<style>
  #HTMLEditor {
    width            : 800px;
    height           : 600px;
    border           : 0px;
  }
  #HTMLEditor form {
    margin           : 0px;
    padding          : 0px;
    border           : 0px;
    display          : inline;
  }
  .HTMLEditor_tab_label a:link {
    font-size        : 9px;
    font-family      : courier new;
    font-weight      : 800;
    color            : #555555;
  }
  .HTMLEditor_tab_label a:visited {
    text-decoration  : none;
    color            : #555555;
  }
  .HTMLEditor_tab_label a:active {
    text-decoration  : none;
    color            : #000000;
  }
  .HTMLEditor_tab_label a:hover {
    text-decoration  : none;
    color            : #000000;
  }
  #HTMLEditor_tabs {
    width            : 100%;
    padding          : 2px 0px 0px 0px;
    border           : 0px;
    border-bottom    : 1px solid #999999;
    overflow         : hidden;
  }
  .HTMLEditor_tab {
    width            : 100px;
    height           : 20px;
    display          : block;
    float            : left;
    background       : url('/images/tab_background.gif') no-repeat top left;
  }
  .HTMLEditor_tab_label {
    width            : 100px;
    height           : 20px;
    border           : 0px;
    padding          : 2px 0px 0px 0px;
    text-align       : center;
  }
  #tab_1 {
    position         : relative;
    top              : 1px;
    left             : 0px;
    z-index          : 2;
  }
  #tab_2 {
    position         : relative;
    top              : 3px;
    left             : -2px;
    z-index          : 1;
  }
  .HTMLEditor_pane {
    border           : 1px solid;
    width            : 100%;
    height           : 480px;
    display          : block;
    overflow         : hidden;
  }
  #pane_1 {
    display          : block;
  }
  #pane_2 {
    display          : none;
  }
  #Preview_content {
    background-color : #FFFFFF;
    margin           : 0px;
    padding          : 0px;
  }
  .HTMLEditor_content {
    width            : 100%;
    height           : 477px;
    border           : 0px;
    padding          : 2px 2px 2px 2px;
    font-family      : courier new, courier, monospace;
    font-size        : 11px;
    color            : #000000;
    overflow         : auto;
  }
  .Preview_pane {
    overflow         : scroll;
  }
</style>
</head>
<body>
  <div id="HTMLEditor">
    <div id="HTMLEditor_tabs">
      <div class="HTMLEditor_tab" id="tab_1">
        <div class="HTMLEditor_tab_label" id="tab_label_1" onClick="return showPane(1);"><a href="#" onClick="return showPane(1);">HTML</a></div>
      </div>
      <div class="HTMLEditor_tab" id="tab_2">
        <div class="HTMLEditor_tab_label" id="tab_label_2" onClick="return showPane(2);"><a href="#" onClick="return showPane(2);">Preview</a></div>
      </div>
    </div>
    <div id="pane_1" class="HTMLEditor_pane">
      <textarea name="HTMLContent" id="HTMLContent" class="HTMLEditor_content" onKeyPress="handleKey()"></textarea>
    </div>
    <div id="pane_2" class="HTMLEditor_pane Preview_pane">
      <div id="Preview_content"></div>
    </div>
  </div>
  <div id="holdtext" style="display:none;"></div>
</body>
</html>

Comments :

HeavyAl 2006-04-07 #5

Hey! Thats just what I've been needing for a site I admin for a client. I added a few extra functions for uploading code, but overall this allows you to edit and view the results of your code with little hassle. Maybe I'll post my changes in another article.

Thanks!

  • Search For Articles