Advanced/Sophisticated Text Editor with Preview

1 post Page 1 of 1
Contributors
User avatar
mikethedj4
VIP - Site Partner
VIP - Site Partner
Posts: 2592
Joined: Thu Mar 25, 2010 4:36 am

Many people have asked me how I made the HTML OnLive Debugger. So I'm answering that question here.

Preview:
sophisticated-text-editor.png
You can easily make an HTML editor with preview a few different ways.
  • You can do simple by setting a textarea's value as the html of a div for example. However this can draw many bugs.
  • Another way that's less buggy, but still draws problems is instead of using a div you use an iframe.
  • The most popular and effective way would be by using Codemirror or the Ace editor.
Here's a snippet of a "Basic Editor w Preview":
Code: Select all
<!DOCTYPE html>
<html>
  <head>
    <title>Simple Example HTML Editor with Preview</title>
    <meta charset='utf-8'>
    <meta name='viewport' content='initial-scale=1.0'>
    <meta http-equiv='X-UA-Compatible' content='IE=9' />
    <link type='text/css' rel='stylesheet' href='http://necolas.github.io/normalize.css/3.0.1/normalize.css'/>
    <script type='text/javascript' src='http://code.jquery.com/jquery-latest.min.js'></script>
    <style type='text/css'>
      body {
        margin: 0;
        background: #333;
      }
      
      #editor, #preview {
        position: absolute;
        width: 50%;
        height: 100%;
      }
      
      #editor {
        left: 0;
        padding: 0;
        font-family: monospace;
        line-height: 1;
        min-height: 1.4em;
        line-height: 1.4em;
        font-size: 1em;
        border: 0;
        border-radius: 0;
        resize: none;
        color: #0b0;
        background-color: #000;
      }
      
      ::-webkit-input-placeholder { /* WebKit browsers */
        color: #060;
      }
      :-moz-placeholder { /* Mozilla Firefox 4 to 18 */
        color: #060;
      }
      ::-moz-placeholder { /* Mozilla Firefox 19+ */
        color: #060;
      }
      :-ms-input-placeholder { /* Internet Explorer 10+ */
        color: #060;
      }
      
      #preview {
        right: 0;
        overflow: auto;
        background-color: #fff;
      }
    </style>
    <script type='text/javascript'>
      $(function() {
        var editor = $('#editor'),
            preview = $('[ID$=preview]');
        
        // Using the <TAB>
        $('#editor').keydown(function(e) {
          if(e.keyCode == 9) {
            var start = $(this).get(0).selectionStart;
            $(this).val($(this).val().substring(0, start) + '  ' + $(this).val().substring($(this).get(0).selectionEnd));
            $(this).get(0).selectionStart = $(this).get(0).selectionEnd = start + 1;
            return false;
          }
        });
        
        // Live Debugging
        editor.keyup(IntPrev);
        
        function IntPrev(e) {
          preview.contents().find('body').html(editor.val());
        }
      });
    </script>
  </head>
  <body>
    <textarea id='editor' placeholder='Code goes here...'></textarea>
    <iframe id='preview' frameborder='0' src='about:blank'></iframe>
  </body>
</html>
Now there is pros and cons with this method, and not one I generally like. However if you decide to go with this method here's a list of some plugins you may consider using.

JQuery Lined TextArea plugin
Tabby (A JQuery Plugin) easily allows Indent/Outdent implementation for textareas

It's upto you which sophisticated text editor you want to use. Codemirror or the Ace?

Not sure you can read this article for more help.

Here's a Codemirror Demo: The demo includes syntax highlighting, code wrapping, line numbering, auto close tags, drag and drop importing, and more.

I've made this demo to make your life easier if you decide to go this route.

Hope all works out for you!

Here's the Codemirror snippet:
Code: Select all
<!DOCTYPE html>
<html>
  <head>
    <title>Codemirror: HTML5 Preview</title>
    <meta charset='utf-8'>
    <meta name='viewport' content='initial-scale=1.0'>
    <meta http-equiv='X-UA-Compatible' content='IE=9' />
    <link type='text/css' rel='stylesheet' href='http://necolas.github.io/normalize.css/3.0.1/normalize.css'/>
    <script type='text/javascript' src='http://code.jquery.com/jquery-latest.min.js'></script>
    <script src='http://codemirror.net/lib/codemirror.js'></script>
    <link rel='stylesheet'  href="http://codemirror.net/lib/codemirror.css">
    <link rel="stylesheet"  href="http://codemirror.net/addon/fold/foldgutter.css" />
    <script src='http://codemirror.net/javascripts/code-completion.js'></script>
    <script src='http://codemirror.net/javascripts/css-completion.js'></script>
    <script src='http://codemirror.net/javascripts/html-completion.js'></script>
    <script src='http://codemirror.net/mode/javascript/javascript.js'></script>
    <script src='http://codemirror.net/mode/xml/xml.js'></script>
    <script src='http://codemirror.net/mode/css/css.js'></script>
    <script src='http://codemirror.net/mode/htmlmixed/htmlmixed.js'></script>
    <script src='http://codemirror.net/addon/edit/closetag.js'></script>
    <script src='http://codemirror.net/addon/edit/matchbrackets.js'></script>
    <script src='http://codemirror.net/addon/selection/active-line.js'></script>
    <script src='http://codemirror.net/keymap/extra.js'></script>
    <script src='http://codemirror.net/addon/fold/foldcode.js'></script>
    <script src='http://codemirror.net/addon/fold/foldgutter.js'></script>
    <script src='http://codemirror.net/addon/fold/brace-fold.js'></script>
    <script src='http://codemirror.net/addon/fold/xml-fold.js'></script>
    <script src='http://codemirror.net/addon/fold/comment-fold.js'></script>
    <style type='text/css'>
      .CodeMirror {
        float: left;
        width: 50%;
        border: 1px solid black;
      }

      iframe {
        width: 49%;
        float: left;
        height: 300px;
        border: 1px solid black;
        border-left: 0;
      }
    </style>
  </head>
  <body>
    <div align='center'>
      <button class='undo'>Undo</button>
      <button class='redo'>Redo</button>
      <button class='jquery'>Add JQuery</button>
      <button class='bold'>Bold</button>
    </div>
    <textarea id='code' name='code'><!doctype html>
<html>
  <head>
    <meta charset=utf-8>
    <title>HTML5 canvas demo</title>
    <style>p {font-family: monospace;}</style>
  </head>
  <body>
    <p>Canvas pane goes here:</p>
    <canvas id=pane width=300 height=200></canvas>

    <script>
      var canvas = document.getElementById('pane');
      var context = canvas.getContext('2d');

      context.fillStyle = 'rgb(250,0,0)';
      context.fillRect(10, 10, 55, 50);

      context.fillStyle = 'rgba(0, 0, 250, 0.5)';
      context.fillRect(30, 30, 55, 50);
    </script>
  </body>
</html></textarea>

    <iframe id='preview'></iframe>

    <script type='text/javascript'>
      // Append JS library to HTML <head>
      function appendJSLib(txt) {
        var textArea = editor.getValue();
        var searchText = textArea.search('<head>');
        if(searchText>0) {
          txt = '<head>'+'\n'+txt;
          var updatedTextArea = textArea.replace('<head>',txt);
          editor.setValue(updatedTextArea);
        }
        else {
          reset();
          alert('WARNING! The <head&gt tag seems to be missing in your HTML. Although your code may still work, we highly recommened that you have a valid HTML syntax. Please refer to the new document of correct formatted');
          txt = txt+textArea;
          htmlEditor.setLine(0, txt);
          return false;
        }
      }

      // Add JQuery as JS Source
      $('.jquery').click(function() {
        txt = '<'+'script type=\'text/javascript\' src=\'http://code.jquery.com/jquery-latest.min.js\'>'+'</'+'script'+'>';
        appendJSLib(txt);
      });

      // Undo/Redo Initiation
      $('.undo').click(function() {
        editor.undo();
      });
      $('.redo').click(function() {
        editor.redo();
      });

      // Make selected text bold (If no text selected it adds the code and focus's cursor to center of tag)
      $('.bold').click(function() {
        // For codemirror & center cursor
        var selected_text = editor.getSelection();  // Need to grab the Active Selection
        console.log(selected_text);  // Active Selection

        editor.replaceSelection('', editor.getCursor());
        editor.replaceRange('<strong></strong>', editor.getCursor());
        editor.focus();
        var str = '</strong>';
        var mynum = str.length;
        var start_cursor = editor.getCursor();  // Need to get the cursor position
        console.log(start_cursor);  // Cursor position 
        var cursorLine = start_cursor.line;
        var cursorCh = start_cursor.ch;

        // Code to move cursor back [x] amount of spaces. [x] is the data-val value.
        editor.setCursor({line: cursorLine , ch : cursorCh -mynum });
        editor.replaceRange(selected_text, editor.getCursor());
        editor.focus();
      });

      var delay;

      // Initialize CodeMirror editor
      var editor = CodeMirror.fromTextArea(document.getElementById('code'), {
        mode: "text/html",
        tabMode: 'indent',
        styleActiveLine: true,
        lineNumbers: true,
        lineWrapping: true,
        autoCloseTags: true,
        foldGutter: true,
        dragDrop : true,
        gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"]
      });

      // Live preview
      editor.on('change', function() {
        clearTimeout(delay);
        delay = setTimeout(updatePreview, 300);
      });

      function updatePreview() {
        var previewFrame = document.getElementById('preview');
        var preview =  previewFrame.contentDocument ||  previewFrame.contentWindow.document;
        preview.open();
        preview.write(editor.getValue());
        document.title = $('#preview').contents().find('title').html();
        if ( document.title === 'undefined' ) {
          document.title = 'App name';
        }
        preview.close();
      }
      setTimeout(updatePreview, 300);
    
      function handleFileSelect(evt) {
        evt.stopPropagation();
        evt.preventDefault();

        var files = evt.dataTransfer.files; // FileList object.
        var reader = new FileReader();  
        reader.onload = function(event) {
          editor.setValue( event.target.result );
        }        
        reader.readAsText(files[0],"UTF-8");
      }
    </script>
  </body>
</html>
You do not have the required permissions to view the files attached to this post.
1 post Page 1 of 1
Return to “Tutorials”