Skip to main content
added 8 characters in body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
  1. Indented code with two spaces rather than four.
  2. Changed the download attribute value, myFile.html, to something meaningful: template.html.
  3. Combined the preview and createURL functions in a new function.
  4. Removed the fileChooser.onclick function: this function is done by the Reset button now.
  5. Added downloader.download = file.name; to the fileChooser.onchange function so the downloader download attribute has the same value as the imported file name. Now there's a logical relationship between the text field content, fileChooser value, and the downloader download attribute value.
  6. In the resize function, changed flex to flexGrow as flexShrink and flexBasis never change.
  7. Defined a new task for the Reset button so it not only resets the text field, but also the fileChooser and downloader download attribute values.
  8. Added a confirmation message on page exit if the text field is modified.
  9. Added a new option: Dark theme; made some code improvements.
  10. Added flex-wrap: wrap; to the header and footer so the flex items wrap if necessary.
  11. Added a run-stop toggle switch:
    • Sometimes you shouldn't run your code until you finish coding or else it will crash your browser. For example, when you're writing loops it can cause an infinite loop.
    • You might want to re-run your code and re-see the result when working with CSS animations, for example. You can achieve it by double-clicking the Run checkbox.
  12. Now Edge supports outputObject.value: changed indicator.textContent to indicator.value.
  13. Added a font sizer; made some code improvements.
  • Sometimes you shouldn't run your code until you finish coding or else it will crash your browser. For example, when you're writing loops it can cause an infinite loop.
  • You might want to re-run your code and re-see the result when working with CSS animations, for example. You can achieve it by double-clicking the Run checkbox.
  1. Now Edge supports outputObject.value — changed indicator.textContent to indicator.value.
  2. Added a font sizer; made some code improvements.
  1. Indented code with two spaces rather than four.
  2. Changed the download attribute value, myFile.html, to something meaningful: template.html.
  3. Combined the preview and createURL functions in a new function.
  4. Removed the fileChooser.onclick function: this function is done by the Reset button now.
  5. Added downloader.download = file.name; to the fileChooser.onchange function so the downloader download attribute has the same value as the imported file name. Now there's a logical relationship between the text field content, fileChooser value, and the downloader download attribute value.
  6. In the resize function, changed flex to flexGrow as flexShrink and flexBasis never change.
  7. Defined a new task for the Reset button so it not only resets the text field, but also the fileChooser and downloader download attribute values.
  8. Added a confirmation message on page exit if the text field is modified.
  9. Added a new option: Dark theme; made some code improvements.
  10. Added flex-wrap: wrap; to the header and footer so the flex items wrap if necessary.
  11. Added a run-stop toggle switch:
  • Sometimes you shouldn't run your code until you finish coding or else it will crash your browser. For example, when you're writing loops it can cause an infinite loop.
  • You might want to re-run your code and re-see the result when working with CSS animations, for example. You can achieve it by double-clicking the Run checkbox.
  1. Now Edge supports outputObject.value — changed indicator.textContent to indicator.value.
  2. Added a font sizer; made some code improvements.
  1. Indented code with two spaces rather than four.
  2. Changed the download attribute value, myFile.html, to something meaningful: template.html.
  3. Combined the preview and createURL functions in a new function.
  4. Removed the fileChooser.onclick function: this function is done by the Reset button now.
  5. Added downloader.download = file.name; to the fileChooser.onchange function so the downloader download attribute has the same value as the imported file name. Now there's a logical relationship between the text field content, fileChooser value, and the downloader download attribute value.
  6. In the resize function, changed flex to flexGrow as flexShrink and flexBasis never change.
  7. Defined a new task for the Reset button so it not only resets the text field, but also the fileChooser and downloader download attribute values.
  8. Added a confirmation message on page exit if the text field is modified.
  9. Added a new option: Dark theme; made some code improvements.
  10. Added flex-wrap: wrap; to the header and footer so the flex items wrap if necessary.
  11. Added a run-stop toggle switch:
    • Sometimes you shouldn't run your code until you finish coding or else it will crash your browser. For example, when you're writing loops it can cause an infinite loop.
    • You might want to re-run your code and re-see the result when working with CSS animations, for example. You can achieve it by double-clicking the Run checkbox.
  12. Now Edge supports outputObject.value: changed indicator.textContent to indicator.value.
  13. Added a font sizer; made some code improvements.
added 8 characters in body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
  1. Indented code with two spaces rather than four.
  2. Changed the download attribute value, myFile.html, to something meaningful: template.html.
  3. Combined the preview and createURL functions in a new function.
  4. Removed the fileChooser.onclick function: this function is done by the Reset button now.
  5. Added downloader.download = file.name; to the fileChooser.onchange function so the downloader download attribute has the same value as the imported file name. Now there's a logical relationship between the text field content, fileChooser value, and the downloader download attribute value.
  6. In the resize function, changed flex to flexGrow as flexShrink and flexBasis never change.
  7. Defined a new task for the Reset button so it not only resets the text field, but also the fileChooser and downloader download attribute values.
  8. Added a confirmation message on page exit if the text field is modified.
  9. Added a new option: Dark theme; made some code improvements.
  10. Added flex-wrap: wrap; to the header and footer so the flex items wrap if necessary.
  11. Added a run-stop toggle switch:
  1. Indented code with two spaces rather than four
  2. Changed the download attribute value, myFile.html, to something meaningful: template.html
  3. Combined the preview and createURL functions in a new function
  4. Removed the fileChooser.onclick function: this function is done by the Reset button now.
  5. Added downloader.download = file.name; to the fileChooser.onchange function so the downloader download attribute has the same value as the imported file name. Now there's a logical relationship between the text field content, fileChooser value, and the downloader download attribute value.
  6. In the resize function, changed flex to flexGrow as flexShrink and flexBasis never change
  7. Defined a new task for the Reset button so it not only resets the text field, but also the fileChooser and downloader download attribute values
  8. Added a confirmation message on page exit if the text field is modified
  9. Added a new option: Dark theme; made some code improvements
  10. Added flex-wrap: wrap; to the header and footer so the flex items wrap if necessary
  11. Added a run-stop toggle switch:
  1. Indented code with two spaces rather than four.
  2. Changed the download attribute value, myFile.html, to something meaningful: template.html.
  3. Combined the preview and createURL functions in a new function.
  4. Removed the fileChooser.onclick function: this function is done by the Reset button now.
  5. Added downloader.download = file.name; to the fileChooser.onchange function so the downloader download attribute has the same value as the imported file name. Now there's a logical relationship between the text field content, fileChooser value, and the downloader download attribute value.
  6. In the resize function, changed flex to flexGrow as flexShrink and flexBasis never change.
  7. Defined a new task for the Reset button so it not only resets the text field, but also the fileChooser and downloader download attribute values.
  8. Added a confirmation message on page exit if the text field is modified.
  9. Added a new option: Dark theme; made some code improvements.
  10. Added flex-wrap: wrap; to the header and footer so the flex items wrap if necessary.
  11. Added a run-stop toggle switch:
Added a font sizer; made some code improvements.
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
  1. Now Edge supports outputObject.value — changed indicator.textContent to indicator.value.
  2. Added a font sizer; made some code improvements.
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="Edit your HTML, CSS, and JavaScript code and monitor the instant live preview.">
  <title>HTML Editor: online HTML editor with real-time preview</title>
  <link rel="icon" href="favicon.ico">
  <style>
    html,
    body {
      margin: 0;
      padding: 0;
      height: 100%;
    }

    body {
      display: flex;
      flex-direction: column;
    }

    header,
    footer.shown:not([hidden]) {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: 5px;
      padding: 5px;
    }

    header {
      background: linear-gradient(#FFF, #CCC);
      row-gap: 5px;
    }

    label,
    #downloader,
    select,
    #resetter,
    #selector,
    #fileChooser,
    output,
    span {
      font: bold 11px Arial;
      color: #333;
    }

    [type="checkbox"] {
      margin: 0 10px5px 0 5px;0;
    }

    #resetter,
    #resizer[for="fontSizer"] {
      margin-left: 0 5px;
    }

    #selectorselect,
    button,
    #resizer {
      margin: 0;
    }

    #fileChooser {
      margin: 0 auto 0 5px;0;
    }

    #resizer,
    iframe {
      padding: 0;
    }

    output {
      margin-right: 10px;5px;
      font-family: monospace;
    }

    #footerToggler {
      width: 16px;
      height: 16px;
      margin: 0;
      border: 1px solid #777;#666;
      border-bottom-width: 5px;
      padding: 0;
      background: transparent;
    }

    #footerToggler.on {
      border-color: #333;
      background: #FFF;
    }

    main {
      flex: 1;
      display: flex;
    }

    main.horizontal {
      flex-direction: column;
    }

    div {
      flex: 0px;
      min-basiswidth: 0;
      positionmin-height: relative;0;
    }

    #viewerWrapper {
      border-left: 5px solid #CCC;
    }

    main.horizontal #viewerWrapper {
      border-left: 0;
      border-top: 5px solid #CCC;
    }

    div * {
      positiondisplay: absolute;block;
      width: 100%;
      height: 100%;
      margin: 0;
      border: 0;
      background: #FFF;
    }

    textarea {
      box-sizing: border-box;
      padding: 5px;
      outline: 0;
      resize: none;
      font-size: 14px;
      color: #333;
    }

    textarea.dark {
      background: #333;
      color: #FFF;
    }

    footer.shown {
      gap: 5px;
      background: linear-gradient(#CCC, #FFF);
    }

    img {
      display: block;
      width: 18px;
      height: 18px;
    }

    #copier {
      border: 0;
      padding: 0;
      background: transparent;
      cursor: pointer;
    }

    address {
      margin-left: auto;
      font-size: 16px;
     italic font-family:16px 'Times New Roman';
      color: #333;
    }

    address a {
      color: inherit;
    }
  </style>
</head>

<body>
  <header>
    <label for="runner">Run</label>
    <input type="checkbox" checkedid="runner" id="runner">checked>
    <a href="" download="template.html" title="Download the HTML document" id="downloader">Download</a>
    <input<label type="button"for="fontSizer">Font value="Reset"size</label>
 id="resetter">   <select id="fontSizer">
    <input  <option>12</option>
      <option>13</option>
      <option selected>14</option>
      <option>15</option>
      <option>16</option>
      <option>17</option>
      <option>18</option>
      <option>19</option>
      <option>20</option>
    </select>
    <button type="button" value="Select"id="resetter">Reset</button>
 id="selector">   <button type="button" id="selector">Select</button>
    <input type="file" accept="text/html" id="fileChooser">
    <label for="resizer">Editor size</label>
    <input type="range" id="resizer">
    <output for="resizer" id="indicator"><id="indicator">0.50</output>
    <label for="viewsToggler">Horizontal view</label>
    <input type="checkbox" id="viewsToggler">
    <label for="themesToggler">Dark theme</label>
    <input type="checkbox" id="themesToggler">
    <input<button type="button" value="‌" title="Toggle footer" id="footerToggler">id="footerToggler"></button>
  </header>
  <main id="main">
    <div id="editorWrapper">
      <textarea spellcheck="false" id="editor"><!DOCTYPE html>
<html lang="en">
  <head>
    <title>HTML Document Template</title>
  </head><style>
  <body>  p {
      font-family: Arial;
    }
  </style>
</head>
<body>
  <p>Hello, world!</p>
  <script>
    console.log(document.querySelector('p').textContent);
  </script>
</body>
</html></textarea>
    </div>
    <div id="viewerWrapper">
      <iframe id="viewer"></iframe>
    </div>
  </main>
  <footer hiddenid="footer" id="footer">hidden>
    <span>Share</span>
    <a href="https://www.linkedintwitter.com/sharing/share-offsiteintent/tweet?url=http%3A%2F%2Fhtmleditortext=HTML%20Editor%3A%20online%20HTML%20editor%20with%20real-time%20preview&url=https%3A%2F%2Fhtmleditor.gitlab.io" target="_blank" title="Share on LinkedIn"><imgtarget="_blank"><img src="images/linkedintwitter.svg" alt="LinkedIn"><width="16" height="16" alt="Twitter"></a>
    <a href="https://twitterwww.facebook.com/intent/tweetsharer.php?text=HTML%20Editor%3A%20online%20HTML%20editor%20with%20real-time%20preview&url=http%3A%2F%2Fhtmleditoru=https%3A%2F%2Fhtmleditor.gitlab.io" target="_blank" title="Share onio&t=HTML%20Editor%3A%20online%20HTML%20editor%20with%20real-time%20preview" Twitter"><imgtarget="_blank"><img src="images/twitterfacebook.svg" alt="Twitter"><width="16" height="16" alt="Facebook"></a>
    <a href="https://www.facebooklinkedin.com/dialogsharing/share-offsite/?app_id=664554287087112&display=page&href=http%3A%2F%2Fhtmleditorurl=https%3A%2F%2Fhtmleditor.gitlab.io" target="_blank"target="_blank"><img title="Sharesrc="images/linkedin.svg" onwidth="16" Facebook"><imgheight="16" alt="LinkedIn"></a>
    <a href="mailto:?subject=HTML%20Editor%3A%20online%20HTML%20editor%20with%20real-time%20preview&body=https%3A%2F%2Fhtmleditor.gitlab.io" target="_blank"><img src="images/facebookemail.svg" alt="Facebook"><width="16" height="16" alt="Email"></a>
    <button type="button" id="copier"><img src="images/link.svg" width="16" height="16" alt="Link"></button>
    <span id="notification" hidden>Copied!</span>
    <address><a href="https://codereview.stackexchange.com/questions/56106/html-editor-online-html-editor-with-real-time-preview" title="Code Review Stack Exchange">Feedback</a> | Created by <a href="https://mori.pages.dev" title="Mori" rel="author">Mori</a></address>
  </footer>
  <script>
    var runner = document.getElementById('runner'),
      editor = document.getElementById('editor'),
      downloader = document.getElementById('downloader'),
      fileChooser = document.getElementById('fileChooser'),
      resizer = document.getElementById('resizer'),
      viewsToggler = document.getElementById('viewsToggler'),
      themesToggler = document.getElementById('themesToggler');

    function preview() {
      if (runner.checked) {
        var viewer = document.getElementById('viewer');
        try {
          var viewerDoc = viewer.contentDocument;
          viewerDoc.open();
        srcdoc = viewerDoc.write(editor.value);
          viewerDoc.close();
        } catch (e) { // in case of iframe redirection to a different origin
          viewer.src = 'about:blank';
          setTimeout(preview, 4); // minimum delay
        }value;
      }
    }
 
    editor.addEventListener('input', preview);
    runner.addEventListener('change', preview);

    function['click', createURL'contextmenu'].forEach(event => downloader.addEventListener(event, function() {
      var blob = new Blob([editor.value], {
        type: 'text/html'
      });
      downloaderthis.href = window.URL.createObjectURL(blob);
    }
    editor.addEventListener('change', createURL));

    functiondocument.getElementById('fontSizer').addEventListener('change', previewAndCreateURLfunction() {
      preview();
  editor.style.fontSize = this.value + createURL();'px';
    });

    document.getElementById('resetter').addEventListener('click', function() {
      if (!editor.value || editor.value != editor.defaultValue &&function confirmresetFileChooserAndDownload('Your changes will be lost.\nAre you sure you want to reset?')) {
        downloader.download = 'template.html';
        fileChooser.value = '';
        downloader.download = 'template.html';
      }
      if (!editor.value || editor.value != editor.defaultValue && confirm('Your input will be lost.\nAre you sure you want to reset?')) {
        resetFileChooserAndDownload();
        editor.value = editor.defaultValue;
        previewAndCreateURLpreview();
      } else if (editor.value == editor.defaultValue) {
        downloader.download = 'template.html';
        fileChooser.value = '';resetFileChooserAndDownload();
      }
    });

    document.getElementById('selector').addEventListener('click', function() {
      editor.select();
    });

    fileChooser.addEventListener('change', async function() {
      var file = this.files[0],
        reader = new FileReader();files[0];
      if (file) { // to ensure that there's a file to read so Chrome, for example, doesn't run this function when you cancel choosing a new file
        downloader.download = file.name;
        reader.readAsText(file);
        reader.addEventListener('load', function() {
          editor.value = this.result;
         await previewAndCreateURLfile.text();
        }preview();
      }
    });

    functiondocument.getElementById('resizer').addEventListener('input', resizefunction() {
      var resizerVal = resizerthis.value;
      document.getElementById('editorWrapper').style.flexGrow = resizerVal;
      document.getElementById('viewerWrapper').style.flexGrow = 100 - resizerVal;
      document.getElementById('indicator').value = (resizerVal / 100).toFixed(2);
    }
    resizer.addEventListener('input', resize);

    functiondocument.getElementById('viewsToggler').addEventListener('change', toggleViewsfunction() {
      var main = document.getElementById('main');
      if (viewsToggler.checked) {
        main.className = 'horizontal';
      } else {
        mainclassList.className = '';
      }toggle('horizontal');
    }
    viewsToggler.addEventListener('change', toggleViews);

    function toggleThemesdocument.getElementById('themesToggler') {
      if.addEventListener('change', function(themesToggler.checked) {
        editor.className = 'dark';
      } else {
        editorclassList.className = '';
      }toggle('dark');
    }
    themesToggler.addEventListener('change', toggleThemes);

    document.getElementById('footerToggler').addEventListener('click', function() {
      this.classList.toggle('on');
      document.getElementById('footer').classListtoggleAttribute('hidden');
    });

    document.togglegetElementById('shown''copier').addEventListener('click', function() {
      navigator.clipboard.writeText('https://htmleditor.gitlab.io');
      function toggleNotification() {
        document.getElementById('notification').toggleAttribute('hidden');
      }
      toggleNotification();
      setTimeout(toggleNotification, 1500);
    });

    window.addEventListener('beforeunload', function(event) {
      if (editor.value && editor.value != editor.defaultValue) {
        event.returnValuepreventDefault();
 = 'Your changes may be lost  event.';returnValue = '';
      }
    });

    resize();
    toggleViews();
    toggleThemes();
    previewAndCreateURLpreview();
  </script>
</body>

</html>
  1. Now Edge supports outputObject.value — changed indicator.textContent to indicator.value.
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="Edit your HTML, CSS, and JavaScript code and monitor the instant live preview.">
  <title>HTML Editor: online HTML editor with real-time preview</title>
  <link rel="icon" href="favicon.ico">
  <style>
    html,
    body {
      margin: 0;
      padding: 0;
      height: 100%;
    }

    body {
      display: flex;
      flex-direction: column;
    }

    header,
    footer.shown {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      padding: 5px;
    }

    header {
      background: linear-gradient(#FFF, #CCC);
      row-gap: 5px;
    }

    label,
    #downloader,
    #resetter,
    #selector,
    #fileChooser,
    output {
      font: bold 11px Arial;
      color: #333;
    }

    [type="checkbox"] {
      margin: 0 10px 0 5px;
    }

    #resetter,
    #resizer {
      margin: 0 5px;
    }

    #selector {
      margin: 0;
    }

    #fileChooser {
      margin: 0 auto 0 5px;
    }

    #resizer,
    iframe {
      padding: 0;
    }

    output {
      margin-right: 10px;
      font-family: monospace;
    }

    #footerToggler {
      width: 16px;
      height: 16px;
      margin: 0;
      border: 1px solid #777;
      border-bottom-width: 5px;
      padding: 0;
      background: transparent;
    }

    #footerToggler.on {
      border-color: #333;
      background: #FFF;
    }

    main {
      flex: 1;
      display: flex;
    }

    main.horizontal {
      flex-direction: column;
    }

    div {
      flex-basis: 0;
      position: relative;
    }

    #viewerWrapper {
      border-left: 5px solid #CCC;
    }

    main.horizontal #viewerWrapper {
      border-left: 0;
      border-top: 5px solid #CCC;
    }

    div * {
      position: absolute;
      width: 100%;
      height: 100%;
      margin: 0;
      border: 0;
      background: #FFF;
    }

    textarea {
      box-sizing: border-box;
      padding: 5px;
      outline: 0;
      resize: none;
      color: #333;
    }

    textarea.dark {
      background: #333;
      color: #FFF;
    }

    footer.shown {
      gap: 5px;
      background: linear-gradient(#CCC, #FFF);
    }

    img {
      display: block;
      width: 18px;
      height: 18px;
    }

    address {
      margin-left: auto;
      font-size: 16px;
      font-family: 'Times New Roman';
      color: #333;
    }

    address a {
      color: inherit;
    }
  </style>
</head>

<body>
  <header>
    <label for="runner">Run</label>
    <input type="checkbox" checked id="runner">
    <a href="" download="template.html" title="Download the HTML document" id="downloader">Download</a>
    <input type="button" value="Reset" id="resetter">
    <input type="button" value="Select" id="selector">
    <input type="file" accept="text/html" id="fileChooser">
    <label for="resizer">Editor size</label>
    <input type="range" id="resizer">
    <output for="resizer" id="indicator"></output>
    <label for="viewsToggler">Horizontal view</label>
    <input type="checkbox" id="viewsToggler">
    <label for="themesToggler">Dark theme</label>
    <input type="checkbox" id="themesToggler">
    <input type="button" value="‌" title="Toggle footer" id="footerToggler">
  </header>
  <main id="main">
    <div id="editorWrapper">
      <textarea spellcheck="false" id="editor"><!DOCTYPE html>
<html lang="en">
  <head>
    <title>HTML Document Template</title>
  </head>
  <body>
    <p>Hello, world!</p>
  </body>
</html></textarea>
    </div>
    <div id="viewerWrapper">
      <iframe id="viewer"></iframe>
    </div>
  </main>
  <footer hidden id="footer">
    <a href="https://www.linkedin.com/sharing/share-offsite/?url=http%3A%2F%2Fhtmleditor.gitlab.io" target="_blank" title="Share on LinkedIn"><img src="images/linkedin.svg" alt="LinkedIn"></a>
    <a href="https://twitter.com/intent/tweet?text=HTML%20Editor%3A%20online%20HTML%20editor%20with%20real-time%20preview&url=http%3A%2F%2Fhtmleditor.gitlab.io" target="_blank" title="Share on Twitter"><img src="images/twitter.svg" alt="Twitter"></a>
    <a href="https://www.facebook.com/dialog/share?app_id=664554287087112&display=page&href=http%3A%2F%2Fhtmleditor.gitlab.io" target="_blank" title="Share on Facebook"><img src="images/facebook.svg" alt="Facebook"></a>
    <address><a href="https://codereview.stackexchange.com/questions/56106/html-editor-online-html-editor-with-real-time-preview" title="Code Review Stack Exchange">Feedback</a> | Created by <a href="https://mori.pages.dev" title="Mori" rel="author">Mori</a></address>
  </footer>
  <script>
    var runner = document.getElementById('runner'),
      editor = document.getElementById('editor'),
      downloader = document.getElementById('downloader'),
      fileChooser = document.getElementById('fileChooser'),
      resizer = document.getElementById('resizer'),
      viewsToggler = document.getElementById('viewsToggler'),
      themesToggler = document.getElementById('themesToggler');

    function preview() {
      if (runner.checked) {
        var viewer = document.getElementById('viewer');
        try {
          var viewerDoc = viewer.contentDocument;
          viewerDoc.open();
          viewerDoc.write(editor.value);
          viewerDoc.close();
        } catch (e) { // in case of iframe redirection to a different origin
          viewer.src = 'about:blank';
          setTimeout(preview, 4); // minimum delay
        }
      }
    }
    editor.addEventListener('input', preview);
    runner.addEventListener('change', preview);

    function createURL() {
      var blob = new Blob([editor.value], {
        type: 'text/html'
      });
      downloader.href = window.URL.createObjectURL(blob);
    }
    editor.addEventListener('change', createURL);

    function previewAndCreateURL() {
      preview();
      createURL();
    }

    document.getElementById('resetter').addEventListener('click', function() {
      if (!editor.value || editor.value != editor.defaultValue && confirm('Your changes will be lost.\nAre you sure you want to reset?')) {
        downloader.download = 'template.html';
        fileChooser.value = '';
        editor.value = editor.defaultValue;
        previewAndCreateURL();
      } else if (editor.value == editor.defaultValue) {
        downloader.download = 'template.html';
        fileChooser.value = '';
      }
    });

    document.getElementById('selector').addEventListener('click', function() {
      editor.select();
    });

    fileChooser.addEventListener('change', function() {
      var file = this.files[0],
        reader = new FileReader();
      if (file) { // to ensure that there's a file to read so Chrome, for example, doesn't run this function when you cancel choosing a new file
        downloader.download = file.name;
        reader.readAsText(file);
        reader.addEventListener('load', function() {
          editor.value = this.result;
          previewAndCreateURL();
        });
      }
    });

    function resize() {
      var resizerVal = resizer.value;
      document.getElementById('editorWrapper').style.flexGrow = resizerVal;
      document.getElementById('viewerWrapper').style.flexGrow = 100 - resizerVal;
      document.getElementById('indicator').value = (resizerVal / 100).toFixed(2);
    }
    resizer.addEventListener('input', resize);

    function toggleViews() {
      var main = document.getElementById('main');
      if (viewsToggler.checked) {
        main.className = 'horizontal';
      } else {
        main.className = '';
      }
    }
    viewsToggler.addEventListener('change', toggleViews);

    function toggleThemes() {
      if (themesToggler.checked) {
        editor.className = 'dark';
      } else {
        editor.className = '';
      }
    }
    themesToggler.addEventListener('change', toggleThemes);

    document.getElementById('footerToggler').addEventListener('click', function() {
      this.classList.toggle('on');
      document.getElementById('footer').classList.toggle('shown');
    });

    window.addEventListener('beforeunload', function(event) {
      if (editor.value && editor.value != editor.defaultValue) {
        event.returnValue = 'Your changes may be lost.';
      }
    });

    resize();
    toggleViews();
    toggleThemes();
    previewAndCreateURL();
  </script>
</body>

</html>
  1. Now Edge supports outputObject.value — changed indicator.textContent to indicator.value.
  2. Added a font sizer; made some code improvements.
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="Edit your HTML, CSS, and JavaScript code and monitor the instant live preview.">
  <title>HTML Editor: online HTML editor with real-time preview</title>
  <link rel="icon" href="favicon.ico">
  <style>
    html,
    body {
      margin: 0;
      padding: 0;
      height: 100%;
    }

    body {
      display: flex;
      flex-direction: column;
    }

    header,
    footer:not([hidden]) {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: 5px;
      padding: 5px;
    }

    header {
      background: linear-gradient(#FFF, #CCC);
    }

    label,
    #downloader,
    select,
    #resetter,
    #selector,
    #fileChooser,
    output,
    span {
      font: bold 11px Arial;
      color: #333;
    }

    [type="checkbox"] {
      margin: 0 5px 0 0;
    }

    [for="fontSizer"] {
      margin-left: 5px;
    }

    select,
    button,
    #resizer {
      margin: 0;
    }

    #fileChooser {
      margin: 0 auto 0 0;
    }

    #resizer,
    iframe {
      padding: 0;
    }

    output {
      margin-right: 5px;
      font-family: monospace;
    }

    #footerToggler {
      width: 16px;
      height: 16px;
      border: 1px solid #666;
      border-bottom-width: 5px;
      padding: 0;
      background: transparent;
    }

    #footerToggler.on {
      border-color: #333;
      background: #FFF;
    }

    main {
      flex: 1;
      display: flex;
    }

    main.horizontal {
      flex-direction: column;
    }

    div {
      flex: 0px;
      min-width: 0;
      min-height: 0;
    }

    #viewerWrapper {
      border-left: 5px solid #CCC;
    }

    main.horizontal #viewerWrapper {
      border-left: 0;
      border-top: 5px solid #CCC;
    }

    div * {
      display: block;
      width: 100%;
      height: 100%;
      margin: 0;
      border: 0;
      background: #FFF;
    }

    textarea {
      box-sizing: border-box;
      padding: 5px;
      outline: 0;
      resize: none;
      font-size: 14px;
      color: #333;
    }

    textarea.dark {
      background: #333;
      color: #FFF;
    }

    footer {
      background: linear-gradient(#CCC, #FFF);
    }

    img {
      display: block;
    }

    #copier {
      border: 0;
      padding: 0;
      background: transparent;
      cursor: pointer;
    }

    address {
      margin-left: auto;
      font: italic 16px 'Times New Roman';
      color: #333;
    }

    address a {
      color: inherit;
    }
  </style>
</head>

<body>
  <header>
    <label for="runner">Run</label>
    <input type="checkbox" id="runner" checked>
    <a href="" download="template.html" title="Download the HTML document" id="downloader">Download</a>
    <label for="fontSizer">Font size</label>
    <select id="fontSizer">
      <option>12</option>
      <option>13</option>
      <option selected>14</option>
      <option>15</option>
      <option>16</option>
      <option>17</option>
      <option>18</option>
      <option>19</option>
      <option>20</option>
    </select>
    <button type="button" id="resetter">Reset</button>
    <button type="button" id="selector">Select</button>
    <input type="file" accept="text/html" id="fileChooser">
    <label for="resizer">Editor size</label>
    <input type="range" id="resizer">
    <output for="resizer" id="indicator">0.50</output>
    <label for="viewsToggler">Horizontal view</label>
    <input type="checkbox" id="viewsToggler">
    <label for="themesToggler">Dark theme</label>
    <input type="checkbox" id="themesToggler">
    <button type="button" title="Toggle footer" id="footerToggler"></button>
  </header>
  <main id="main">
    <div id="editorWrapper">
      <textarea spellcheck="false" id="editor"><!DOCTYPE html>
<html lang="en">
<head>
  <title>HTML Document Template</title>
  <style>
    p {
      font-family: Arial;
    }
  </style>
</head>
<body>
  <p>Hello, world!</p>
  <script>
    console.log(document.querySelector('p').textContent);
  </script>
</body>
</html></textarea>
    </div>
    <div id="viewerWrapper">
      <iframe id="viewer"></iframe>
    </div>
  </main>
  <footer id="footer" hidden>
    <span>Share</span>
    <a href="https://twitter.com/intent/tweet?text=HTML%20Editor%3A%20online%20HTML%20editor%20with%20real-time%20preview&url=https%3A%2F%2Fhtmleditor.gitlab.io" target="_blank"><img src="images/twitter.svg" width="16" height="16" alt="Twitter"></a>
    <a href="https://www.facebook.com/sharer.php?u=https%3A%2F%2Fhtmleditor.gitlab.io&t=HTML%20Editor%3A%20online%20HTML%20editor%20with%20real-time%20preview" target="_blank"><img src="images/facebook.svg" width="16" height="16" alt="Facebook"></a>
    <a href="https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fhtmleditor.gitlab.io" target="_blank"><img src="images/linkedin.svg" width="16" height="16" alt="LinkedIn"></a>
    <a href="mailto:?subject=HTML%20Editor%3A%20online%20HTML%20editor%20with%20real-time%20preview&body=https%3A%2F%2Fhtmleditor.gitlab.io" target="_blank"><img src="images/email.svg" width="16" height="16" alt="Email"></a>
    <button type="button" id="copier"><img src="images/link.svg" width="16" height="16" alt="Link"></button>
    <span id="notification" hidden>Copied!</span>
    <address><a href="https://codereview.stackexchange.com/questions/56106/html-editor-online-html-editor-with-real-time-preview" title="Code Review Stack Exchange">Feedback</a> | Created by <a href="https://mori.pages.dev" rel="author">Mori</a></address>
  </footer>
  <script>
    var runner = document.getElementById('runner'),
      editor = document.getElementById('editor'),
      downloader = document.getElementById('downloader'),
      fileChooser = document.getElementById('fileChooser');

    function preview() {
      if (runner.checked) {
        document.getElementById('viewer').srcdoc = editor.value;
      }
    }
 
    editor.addEventListener('input', preview);
    runner.addEventListener('change', preview);

    ['click', 'contextmenu'].forEach(event => downloader.addEventListener(event, function() {
      var blob = new Blob([editor.value], {type: 'text/html'});
      this.href = URL.createObjectURL(blob);
    }));

    document.getElementById('fontSizer').addEventListener('change', function() {
      editor.style.fontSize = this.value + 'px';
    });

    document.getElementById('resetter').addEventListener('click', function() {
      function resetFileChooserAndDownload() {
        fileChooser.value = '';
        downloader.download = 'template.html';
      }
      if (!editor.value || editor.value != editor.defaultValue && confirm('Your input will be lost.\nAre you sure you want to reset?')) {
        resetFileChooserAndDownload();
        editor.value = editor.defaultValue;
        preview();
      } else if (editor.value == editor.defaultValue) {
        resetFileChooserAndDownload();
      }
    });

    document.getElementById('selector').addEventListener('click', function() {
      editor.select();
    });

    fileChooser.addEventListener('change', async function() {
      var file = this.files[0];
      if (file) { // to ensure that there's a file to read so Chrome, for example, doesn't run this function when you cancel choosing a new file
        downloader.download = file.name;
        editor.value = await file.text();
        preview();
      }
    });

    document.getElementById('resizer').addEventListener('input', function() {
      var resizerVal = this.value;
      document.getElementById('editorWrapper').style.flexGrow = resizerVal;
      document.getElementById('viewerWrapper').style.flexGrow = 100 - resizerVal;
      document.getElementById('indicator').value = (resizerVal / 100).toFixed(2);
    });

    document.getElementById('viewsToggler').addEventListener('change', function() {
      document.getElementById('main').classList.toggle('horizontal');
    });

    document.getElementById('themesToggler').addEventListener('change', function() {
      editor.classList.toggle('dark');
    });

    document.getElementById('footerToggler').addEventListener('click', function() {
      this.classList.toggle('on');
      document.getElementById('footer').toggleAttribute('hidden');
    });

    document.getElementById('copier').addEventListener('click', function() {
      navigator.clipboard.writeText('https://htmleditor.gitlab.io');
      function toggleNotification() {
        document.getElementById('notification').toggleAttribute('hidden');
      }
      toggleNotification();
      setTimeout(toggleNotification, 1500);
    });

    window.addEventListener('beforeunload', function(event) {
      if (editor.value && editor.value != editor.defaultValue) {
        event.preventDefault();
        event.returnValue = '';
      }
    });

    preview();
  </script>
</body>

</html>
deleted 51 characters in body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
added 1 character in body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
edited body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
added 18 characters in body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
deleted 9 characters in body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
added 32 characters in body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
A new footer toggle icon
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
edited body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
deleted 78 characters in body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
added 8 characters in body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
deleted 93 characters in body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
Used his post link
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
Just a small change in my Google+ title
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
Making it mobile-friendly
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
adding a "lang" attribute to the "html" start tag to declare the language of the HTML document template
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
Explained what the Run checkbox can do
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
added 57 characters in body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
added 1276 characters in body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
Improved the title and meta description tags
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
Improve the meta description — it was too short!
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
Some minor CSS and JavaScript improvements
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading
deleted 12 characters in body
Source Link
Mori
  • 197
  • 1
  • 5
  • 20
Loading