22
\$\begingroup\$

Note

Please review the new question and ignore the following.


Overview

HTML Editor is an online HTML editor with a minimalist approach. Edit your HTML, CSS, and JavaScript code and monitor the instant live preview. It can also create, open and edit other types of text files such as .txt, .css, .js, .svg, etc.

Please review the latest source code and provide feedback.

Original source code

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="description" content="An online HTML editor with real-time preview">
    <title>HTML Editor</title>
    <link rel="icon" href="favicon.ico" type="image/x-icon">
    <base target="_blank">
    <style>
        html,
        body {
            margin: 0;
            padding: 0;
            height: 100%;
        }
        body {
            display: -webkit-flex;
            /* WebKit prefixes are added to support Safari. */
            display: flex;
            -webkit-flex-direction: column;
            flex-direction: column;
        }
        header,
        .shown {
            display: -webkit-flex;
            display: flex;
            -webkit-align-items: center;
            align-items: center;
            padding: 5px;
        }
        header {
            background: linear-gradient(#FFF, #CCC);
        }
        #fileSaver,
        [type="button"],
        #fileChooser,
        label,
        span {
            font: bold 11px arial;
            color: #333;
        }
        #selector,
        #resizer,
        #viewsToggle,
        [title$="Twitter"] {
            margin-right: 5px;
            margin-left: 5px;
        }
        #fileSaver {
            margin-right: 5px;
        }
        #fileChooser,
        [title$="Facebook"] {
            margin-right: auto;
        }
        #resizer {
            margin-top: 0;
            margin-bottom: 0;
            padding: 0;
        }
        /* to remove the extra margins and padding in some browsers, e.g. IE11 */
        span {
            width: 35px;
        }
        #footerToggle {
            margin-right: 0;
            margin-left: 5px;
            border: 0;
            padding: 0;
            background: transparent;
        }
        main {
            display: -webkit-flex;
            display: flex;
            -webkit-flex: 1;
            flex: 1;
        }
        .horizontal {
            -webkit-flex-direction: column;
            flex-direction: column;
        }
        main * {
            margin: 0;
            -webkit-flex: 50;
            flex: 50;
            background: #FFF;
            min-height: 100%;
            /* to ensure that the flex items are stretched to use available space; IE11, for example, doesn't stretch the iframe. */
        }
        .horizontal * {
            min-width: 100%;
            min-height: 0;
            /* to get back to the initial value */
        }
        textarea {
            box-sizing: border-box;
            border: 0;
            outline: 0;
            padding: 5px;
            resize: none;
            overflow: auto;
            /* to remove the default scrollbar in IE11 */
        }
        .minSize {
            padding: 0;
        }
        iframe {
            border: solid #CCC;
            border-width: 0 0 0 5px;
            padding: 0;
        }
        .horizontal iframe {
            border-width: 5px 0 0;
        }
        .shown {
            background: linear-gradient(#CCC, #FFF);
        }
        img {
            display: block;
            width: 20px;
            height: 20px;
        }
        address,
        address a {
            color: #333;
        }
    </style>
</head>

<body>
    <header>
        <a download="myFile.html" title="Save as..." id="fileSaver">Save as...</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">Text field size</label>
        <input type="range" id="resizer">
        <span id="indicator">50%</span> 
        <!-- The semantic element to use instead of span is output. But it's not supported in IE11. -->
        <label for="viewsToggle">Horizontal view</label>
        <input type="checkbox" id="viewsToggle">
        <input type="button" value="▲" title="Show footer" id="footerToggle">
    </header>
    <main id="main">
        <textarea spellcheck="false" id="editor"><!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>HTML Document Template</title>
  </head>
  <body>
    <p>Hello, world!</p>
  </body>
</html></textarea>
        <iframe id="viewer"></iframe>
    </main>
    <footer hidden id="footer">
        <a href="https://plus.google.com/share?url=http%3A%2F%2Fhtmleditor.gitlab.io%2F" title="Share on Google+">
            <img src="images/google+.png" alt="Google+">
        </a>
        <a href="https://twitter.com/share?text=HTML%20Editor&amp;url=http%3A%2F%2Fhtmleditor.gitlab.io%2F" title="Share on Twitter">
            <img src="images/twitter.png" alt="Twitter">
        </a>
        <a href="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fhtmleditor.gitlab.io%2F" title="Share on Facebook">
            <img src="images/facebook.png" alt="Facebook">
        </a>
        <address><a href="feedback.html" title="Feedback">Feedback</a> / Created by <a href="https://plus.google.com/+MortezaMirmojarabian?rel=author" title="Google+ profile" rel="author">Mori</a></address>
    </footer>
    <script>
        var editor = document.getElementById('editor'),
            viewer = document.getElementById('viewer'),
            fileChooser = document.getElementById('fileChooser'),
            resizer = document.getElementById('resizer');

        function preview() {
            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
            }
        }
        preview();
        editor.oninput = preview;

        function createURL() {
            var blob = new Blob([editor.value], {
                type: 'text/html'
            });
            document.getElementById('fileSaver').href = window.URL.createObjectURL(blob);
        }
        createURL();
        editor.onchange = createURL;
        fileChooser.onclick = function () { // to empty the fileList so you can rechoose the same file
            this.value = '';
        };
        fileChooser.onchange = function () {
            var file = this.files[0],
                reader = new FileReader();
            if (file) { // to ensure that there's a file to read so IE11 doesn't run this function on clicking fileChooser before you choose a file
                reader.readAsText(file);
                reader.onload = function () {
                    editor.value = this.result;
                    preview();
                    createURL();
                };
            }
        };
        document.getElementById('viewsToggle').onchange = function () {
            document.getElementById('main').classList.toggle('horizontal');
        };
        resizer.oninput = resizer.onchange = function () { // The onchange property is added to support IE11.
            var resizerVal = this.value;
            editor.style.webkitFlex = resizerVal;
            editor.style.flex = resizerVal;
            viewer.style.webkitFlex = 100 - resizerVal;
            viewer.style.flex = 100 - resizerVal;
            document.getElementById('indicator').textContent = resizerVal + '%';
            if (resizerVal == 0) {
                editor.className = 'minSize';
            } else {
                editor.className = '';
            }
        };
        document.getElementById('selector').onclick = function () {
            editor.select();
        };
        document.getElementById('resetter').onclick = function () {
            if (!editor.value || editor.value != editor.defaultValue && confirm('Are you sure?')) {
                editor.value = editor.defaultValue;
                preview();
                createURL();
            }
        };
        document.getElementById('footerToggle').onclick = function () {
            var footerClasses = document.getElementById('footer').classList;
            footerClasses.toggle('shown');
            if (footerClasses.length) {
                this.value = '▼';
                this.title = 'Hide footer';
            } else {
                this.value = '▲';
                this.title = 'Show footer';
            }
        };
    </script>
</body>

</html>
\$\endgroup\$
4
  • 1
    \$\begingroup\$ If you want a review of the updated code then it would perhaps be best to put that in a new question. Otherwise it would be akin to putting code on a third party site and simply putting a link to the site in a question - a primary reason questions are closed. \$\endgroup\$ Commented May 10, 2023 at 12:53
  • \$\begingroup\$ @SᴀᴍOnᴇᴌᴀ: Thanks for the hint! I'll post a new question right now. I just wish I'd known that before starting a bounty. Is there possibly a way to transfer it to the new thread? \$\endgroup\$
    – Mori
    Commented May 10, 2023 at 17:48
  • \$\begingroup\$ I've refunded it so it can be applied to another post \$\endgroup\$ Commented May 10, 2023 at 17:49
  • \$\begingroup\$ @SᴀᴍOnᴇᴌᴀ: You're an angel! And I'd really appreciate it if you reviewed my code as well! 🌹 \$\endgroup\$
    – Mori
    Commented May 10, 2023 at 17:57

3 Answers 3

16
\$\begingroup\$
  • Consider escaping the content of the textarea. Seeing the differently-indented </html> made me stumble in my scan-through, whereas &lt;/html&gt would not have. It's also good practice... Incidentally, is there a reason why your code is indented with 4 spaces, but your default textarea value uses 2?

  • Some people like to indent with tabs. You need to capture the keypress.

  • Internet Explorer 9 and under does not have support for <input type="range" />. Your panes will not be resizeable in that case, and the Text field size control will be confusing (though functional).

    • Upon further review, this isn't very relevant because your site is completely broken in IE9. Blob is unavailable, and halts execution of the script. At the very least, you should display a message indicating that the browser is unsupported.

Aside from that, the code seems pretty good. However, from a user standpoint:

  • The Save as... control is a link, but all the others are buttons. This seems a bit inconsistent.

  • If I choose a file and then reset, I expect that it resets to the file I had selected. If this is not the case, then the form control should reset to no value, so I see "No file chosen" rather than my file name.

  • The footer shower/hider triangle doesn't make much sense to me. There's little reason to hide the footer, and even less so to show it if it's hidden by default. Even if there was, I'd prefer for the hide button to be on the footer itself.

  • It would be nice if the panes could be resized with the separator instead of the range input.


After your edit, I took another look and noticed a few more things:

  • Although your file input has accept="text/html", the user can still choose to upload any file. Consider validating file.type in fileChooser.onchange().

  • It would be nice if before choosing a file, if I have unsaved changes, I get a confirmation message.

  • In the same vein, if I have unsaved changes, maybe set an onbeforeunload?

The following would implement the last two points. Note that save detection is naive, since as far as I'm aware, there's no way to conclusively determine if a user has saved the file to disk. (You'd also have to set changed = false in reader.onload() and resetter.onclick().)

var changed = false;
editor.oninput = function() {
    changed = true;
    preview();
}
fileChooser.onclick = function() {
    return changed && confirm("Your changes will be lost if you select another file. Are you sure you want to continue?");
}
window.onbeforeunload = function() {
    return changed ? "You have unsaved changes. Are you sure you want to leave this page?" : undefined;
}
fileSaver.onclick = function() {
    changed = false;
}
\$\endgroup\$
13
  • 3
    \$\begingroup\$ At the very least, you should display a message indicating that the browser is unsupported: it would be even better if @Mori detected the capability for the features, instead of detecting browser+version. \$\endgroup\$
    – ANeves
    Commented Jul 8, 2014 at 18:27
  • 2
    \$\begingroup\$ @Mori the percentage of IE9 users is bigger than you think. Caniuse claims IE9 is at 2.6% while Safari (which you specifically mention in comments) is only at 1.64%. Sad truth is, IE8 is even more popular at 4.46%. That's an unacceptably large number of users to give the finger to. Plus, if it is supposed to be a tool for allowing users to design prototypes, the fact that some browsers cannot be tested with it is a big deal. \$\endgroup\$
    – cimmanon
    Commented Jul 14, 2014 at 11:09
  • 1
    \$\begingroup\$ @Schism: Thanks for the suggestion, but I want nothing extra/distracting in the editor, let alone in the viewer, where you see the result of your coding: the preview should be pure. \$\endgroup\$
    – Mori
    Commented Jan 10, 2016 at 3:18
  • 1
    \$\begingroup\$ "If this is not the case, then the form control should reset to no value, so I see "No file chosen" rather than my file name." Makes sense! Corrected! "The footer shower/hider triangle doesn't make much sense to me." I couldn't find a better way to hide & show the footer. I decided to hide the footer as I find it rather distracting and not directly relevant to the main task of HTML Editor. Besides, it takes up some space that you can use for coding. Things on the footer, e.g. my Google+ profile, aren't things you need all the time. They're probably used only once. \$\endgroup\$
    – Mori
    Commented May 22, 2017 at 16:52
  • 1
    \$\begingroup\$ @Schism: According to the spec, the accept attribute may be specified to provide user agents with a hint of what file types will be accepted. The accept attribute filters the files you see in the Open dialog so you can easily find and work with the desired files among the clutter while you can still select All Files and see/select other files. Then this attribute isn't meant to be a validation tool. Although HTML Editor is an HTML ediotr, you can use it to open, edit and save any text file. \$\endgroup\$
    – Mori
    Commented May 22, 2017 at 17:04
12
\$\begingroup\$

In all, quite impressive code, here are some pointers:

  • Besides the suggestion to compare with 0 via ===, JsHint could not find anything
  • Consider using addEventListener instead of the old skool onxxx
  • I would put preview(); and createURL(); together instead of having them in the middle of event handler assignments, either right after the var assignments or at the very bottom.
  • Or you could even consider faking a click on 'resetter' which does all that, if you dont use addEventListener, you could simply do

    document.getElementById('resetter').onclick();  
    
  • Ternary can be your friend here:

     if (resizerVal == 0) {
         editor.className = 'minSize';
     } else {
         editor.className = '';
     }
    

    can be

     editor.className = resizerVal ? '' : 'minSize';
    
\$\endgroup\$
7
  • \$\begingroup\$ "I would put preview(); and createURL(); together" I've called these functions immediately after defining them for a better code human-readability. "Or you could even consider faking a click on 'resetter' which does all that" I'm not sure what you mean. Would you mind providing a sample? "Ternary can be your friend here" I'm not familiar with Ternary and should search for it. Thanks for the suggestion! \$\endgroup\$
    – Mori
    Commented Jul 9, 2014 at 9:01
  • \$\begingroup\$ Ternary is a link now, full name is ternary operator. Added a ( hackish ) example of what I mean for faking a click. The Google should help you in case you want to use addEventListener. \$\endgroup\$
    – konijn
    Commented Jul 9, 2014 at 13:01
  • \$\begingroup\$ Just learned about ternary operator. It should be editor.className = resizerVal == 0 ? 'minSize' : '';. \$\endgroup\$
    – Mori
    Commented Jul 10, 2014 at 9:32
  • \$\begingroup\$ I my example I evaluate resizerVal itself, if it is not 0 it will be truthy, if it is 0 it will be falsy, try it. \$\endgroup\$
    – konijn
    Commented Jul 10, 2014 at 12:58
  • \$\begingroup\$ I tried it to no avail. I think that's because an <input> value is a string and can never be falsy, even if you set it to zero. \$\endgroup\$
    – Mori
    Commented Jul 11, 2014 at 0:19
3
\$\begingroup\$

Main updates

  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.

Latest source code

<!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>
\$\endgroup\$
4
  • \$\begingroup\$ I apologize for the hassle again. The FAQ also states that you should mention what was updated, so that it's still a valid code review. It should then be marked as Community Wiki. \$\endgroup\$
    – Jamal
    Commented Jul 29, 2014 at 5:04
  • \$\begingroup\$ "you should mention what was updated" Mmm... Actually, I'm a little puzzled: haven't I mentioned it in my post? I've clearly stated that the reset function, for example, is changed. If you mean something else, would you mind doing it on behalf of me? Thanks, again! \$\endgroup\$
    – Mori
    Commented Jul 29, 2014 at 5:08
  • \$\begingroup\$ I mean the individual changes made for each update (or just mentioning one or more answers if all advice was taken from them). \$\endgroup\$
    – Jamal
    Commented Jul 29, 2014 at 5:09
  • \$\begingroup\$ Got it! I will. \$\endgroup\$
    – Mori
    Commented Jul 29, 2014 at 5:34

Not the answer you're looking for? Browse other questions tagged or ask your own question.