HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Simple syntax highlighter in Javascript - SQL highlighting

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
simplejavascriptsqlhighlightingsyntaxhighlighter

Problem

Yesterday and today I've made a very basic syntax highlight.

It creates a function in the window object that handles part of the job:

(function(window){

    var f=window.highlight = function(lang, element){

        var lang_defs = f[lang];

        if(!lang_defs)
        {
            throw new TypeError( 'The language "' + lang + '" was not yet defined' );
        }

        if(!(element instanceof Element))
        {
            throw new TypeError( 'The 2nd parameter must be an Element' );
        }

        element.className += ' highlight ' + lang;

        for(var i = 0, l = lang_defs.length; i' +
                                        lang_defs[i].replace.text +
                                    ''
                        );
                }
                else
                {
                    html += element.childNodes[j].outerHTML;
                }
            }
            element.innerHTML = html;

            if('function' === typeof lang_defs[i].patch)
            {
                var returned = lang_defs[i].patch.call( element );
                if('string' === typeof returned)
                {
                    element.innerHTML = returned;
                }
            }
        }
    };

    //default replace object
    f.default_replace = {'tag': 'span', 'text': '$1'};

})(Function('return this')());//just be sure that we have the real window


Each language is a property in the function, which is then read (sql example):

```
(function(window){

if('function' === typeof window.highlight)
{
window.highlight.sql=[
{
'class':'string',
'match':/([bn]?"(?:[^"]|[\\"]")"|[bn]?'(?:[^']|[\\']')')(?=[\b\s\(\),;\$#\+\-\*\/]|$)/g,
'replace':window.highlight.default_replace
},
{
'class':'comment',
'match':/((?:\/\/|\-\-\s|#)[^\r\n]|\/\(?:[^]|\[^\/])(?:\\/|$))/g,
'replace':window.

Solution

After closely watching the code, I realized that I've made a few mistakes:

Mistake 1:

The languages are being added directly as a property in the function. That's just begging for trouble!

I've added an object where all the languages will be added.

Mistake 2:

To generate the new HTML to search for the text nodes (the un-highlighted text), I was refreshing the element itself.

That means that all the styles related with that element were being refreshed over and over and over again.

Now, with a document fragment, the number of reflows was reduced to 2!

Mistake 3 (or 2.5?):

Since I was setting the class at the beggining, before any code, which was helping in the number of reflows.

This is a total waste of time for the CPU. This reflow was moved before doing any direct changes in the code, but before adding the new HTML.

Mistake 4:

The lack of 'stricness' disturbed some people.

And it is a good point!

Now, 'use strict'; is present in the code.

Now, with all the mistakes sorted out, I've also made some changes:

Change 1:

The language now can be set directly in the element, or as an optional parameter in the function.

Change 2:

If you forget to set a language, both on the element and in the parameter, it throws a friendly exception.

Also, the exception about the language being missing was adjusted.

Change 3:

You can now pass a set of elements (NodeList or HTMLCollection) and the elements will be highlighted.

The exceptions that are thrown will be handled differently, giving the other elements a chance.

The individual results for each element are returned in the form of an array.

Change 4:

@Mast pointed out something very simple and small.

The initialization had the following line:

var f=window.highlight = function(element, lang){//...


At first, it is completely unclear what f is doing.

I've changed it's name to fn, and added a description of what that variable is doing there.

After all the changes, this is the final result:

(function(window){

'use strict';

//fn keeps an internal reference to avoid problems with rewritting the window.highlight
var fn = window.highlight = function(element, lang){

'use strict';

if(element instanceof NodeList || element instanceof HTMLCollection)
{
for(var i = 0, l = element.length, results = []; i' +
lang_defs[i].replace.text +
''
);
}
else
{
html += div.childNodes[j].outerHTML;
}
}

//refreshes the HTML, before doing anything else
div.innerHTML = html;

if('function' === typeof lang_defs[i].patch)
{
var returned = lang_defs[i].patch.call( div );
if('string' === typeof returned)
{
div.innerHTML = returned;
}
}
}

//only change at the end, to avoid unnecessary reflows
element.className += ' highlight ' + lang;
element.innerHTML = div.innerHTML;

return true;
};

//default replace object
fn.default_replace = {'tag': 'span', 'text': '$1'};

//all the languages will be added here
fn.langs = {};

})(Function('return this')());//just be sure that we have the real window


Example of an execution (same HTML and CSS):



`//main file, containing the main function

(function(window){

'use strict';

//fn keeps an internal reference to avoid problems with rewritting the window.highlight
var fn = window.highlight = function(element, lang){

'use strict';

if(element instanceof NodeList || element instanceof HTMLCollection)
{
for(var i = 0, l = element.length, results = []; i' +
lang_defs[i].replace.text +
''
);
}
else
{
html += div.childNodes[j].outerHTML;
}
}

//refreshes the HTML, before doing anything else
div.innerHTML = html;

if('function' === typeof lang_defs[i].patch)
{
var returned = lang_defs[i].patch.call( div );
if('string' === typeof returned)
{
div.innerHTML = returned;
}
}
}


//only change at the end, to avoid unnecessary reflows
element.className += ' highlight ' + lang;
element.innerHTML = div.innerHTML;

return true;
};

//default replace object
fn.default_replace = {'tag': 'span', 'text': '$1'};

//all the languages will be added here
fn.langs = {};

})(Function('return this')());//just be sure that we have the real window

//==========================================================

// sql syntax highlight, anothed different file

(function(window){
'use strict';
if('function' === typeof window.highlight)
{
window.highlight.langs.sql=[
{
'class':'string',
'match':/([bn]?"(?:[^"]|[\\"]")"|[bn]?'(?:[^']|[\\']')')(?=[\b\s\(\),;\$#

Code Snippets

var f=window.highlight = function(element, lang){//...

Context

StackExchange Code Review Q#90938, answer score: 7

Revisions (0)

No revisions yet.