Javascript in c++

The problem that I had with laying down javascript functions in c++ was very similar in nature to the problem one of html; i.e. having escape characters all over the place or producing virtually unreadable code.  Thankfully the problem was much easier to solve with a class of less than 100 lines of code; And while it is fairly dumb, it will suffice for what I need to do with it.

#include "jsfunction.h"
#include "ic_core.h"

using std::string;

jsfunction::jsfunction(string fcnDeclaration)
    :
      m_fcnDeclaration(fcnDeclaration) {
}

void jsfunction::add_line(std::string lineString) { m_fcnLines.push_back(lineString);}
void jsfunction::add_line_break() { m_fcnLines.push_back("");}


string jsfunction::js_function(int indent, bool appendNewLine) {

    string jFcn("\n");

    int tabstops = 0;
    if(indent)
        jFcn.append(indent, '\t');

    jFcn.append("function " + m_fcnDeclaration + " {\n\n");

    for(string &it : m_fcnLines) {

        it = cleanstring(it);

        //SORT OUT INDENTATION
        if((it.back() == '}') && (it.front() != '{')) --tabstops;

        if(indent) {
            jFcn.append(indent + tabstops +1, '\t');
            jFcn.append(it + "\n");
        }
        else {
            jFcn.append("\t" +it + "\n");
        }

        if(it.back() == '{') ++tabstops;
    }


    jFcn.append("\n");

    if(indent)
        jFcn.append(indent, '\t');

    jFcn.append("}");

    if(appendNewLine)
        jFcn.append("\n\n");

    return(jFcn);
}


This is quite literally it, and to use it you simply create an instance with a javascript function name, add lines with the add_line() method and add line brakes using the add_line_break() method.  When you are done you call js_function() with the desired number of indents and you have a string that you can put in a node of your formatted html_tree.

The add_line() method adds each line literally, this class purely handles the formatting so

jsfunction nav("nav(name, value, url)");
        nav.add_line("var form = document.createElement(\"form\");");
        nav.add_line("form.setAttribute(\"method\", \"post\");");
        nav.add_line("form.setAttribute(\"action\", url);");
        nav.add_line_break();
        nav.add_line("var jobId = document.createElement(\"input\");");
        nav.add_line_break();
        nav.add_line("jobId.setAttribute(\"type\", \"hidden\");");
        nav.add_line("jobId.setAttribute(\"name\", name);");
        nav.add_line("jobId.setAttribute(\"value\", value);");
        nav.add_line_break();
        nav.add_line("form.appendChild(jobId);");
        nav.add_line("document.body.appendChild(form);");
        nav.add_line("form.submit();");

nav.jsfunction();

will create a function that will look like:

function nav(name, value, url) {
    var form = document.createElement("form");
    form.setAttribute("method", "post");
    form.setAttribute("action", url);
				
    var jobId = document.createElement("input");
				
    jobId.setAttribute("type", "hidden");
    jobId.setAttribute("name", name);
    jobId.setAttribute("value", value);
				
    form.appendChild(jobId);
    document.body.appendChild(form);
    form.submit();

}

The class can easily handle more complex function with brackets “{” and “}” and will indent your code in a reasonable manner. without the need for spacing.

jsfunction cbState("resolved_state()");
cbState.add_line("var resolved = \""+ std::to_string(faults::PENDING) + "\";");
cbState.add_line("if(document.getElementById(\"faultstat\").checked) {");
cbState.add_line("resolved = \"" + std::to_string(faults::RESOLVED_EXT) + "\";");
cbState.add_line("}");
cbState.add_line_break();
cbState.add_line("return(resolved);");

will produce

function resolved_state() {
    var resolved = "pending";
    if(document.getElementById(\"faultstat\").checked) {
        resolved = resolved;
    }
    return(resolved);
}

It is not idea, but then again, I don’t suppose writing javascript functions in c++ could ever be ideal and it is a little better than the alternatives of raw strings containing c++ variables, or strings littered with escape characters.

 

Event Listeners:

This is a function that was thrown together that has not been exhaustively tested.  it is not part of the jsfunction class although it does rely on it.  jsevent takes a number of arguments in order to create an event listener.

    string jsevent::jsevent(
            std::string element,
            std::string event,
            jsfunction &function,
            bool useCapture,
            unsigned indent
        ) {
    string strEvent(element + ".addEventListener(\n");

    strEvent.append(indent + 1, '\t');
    strEvent.append("'" + event + "',\n");
    strEvent.append(function.js_function(indent +1, false) + ",\n");
    strEvent.append(indent + 1, '\t');
    strEvent.append(useCapture ? "true\n" : "false\n");
    strEvent.append(indent, '\t');
    strEvent.append(");\n\n");

    return(strEvent);

}

In order to create an event, first you need to create the event function using the jsfunction class eg.

    jsfunction e("(event)");
    e.add_line("if (event.target.id.toLowerCase() !== 'faulttext') {");
    e.add_line("return;");
    e.add_line("}");
    e.add_line("autoExpand(event.target);");

Then all you need to do is call jsevent in order to grab the event string

    string onInput = jsevent::jsevent(
                "document",
                "input",
                e,
                false,
                2
                );

Will create an event listener like

document.addEventListener(
    'input',
    function (event) {
        if (event.target.id.toLowerCase() !== 'faulttext') {
            return;
        }
        autoExpand(event.target);
    },
    false
);