-2

I've the below JQuery code, that make coloring for the SQL statement entered in the editable html text: enter image description here

// SQL keywords
    var keywords = ["SELECT","FROM","WHERE","LIKE","BETWEEN", "UNION",
    "FALSE","NULL","FROM","TRUE","NOT", "ORDER", "GROUP", "BY", "NOT", "IN"];
    // Keyup event
    $("#editor").on("keyup", function(e){
    // Space key pressed
    if (e.keyCode == 32){
        var newHTML = "";
        // Loop through words
        $(this).text().replace(/[\s]+/g, " ").trim().split(" ").forEach(function(val){
        // If word is statement
        if (keywords.indexOf(val.trim().toUpperCase()) > -1)
            newHTML += "<span class='statement'>" + val + "&nbsp;</span>";
        else
            newHTML += "<span class='other'>" + val + "&nbsp;</span>"; 
        });
        $(this).html(newHTML);

        // Set cursor postion to end of text
        var child = $(this).children();
        var range = document.createRange();
        var sel = window.getSelection();
        range.setStart(child[child.length-1], 1);
        range.collapse(true);
        sel.removeAllRanges();
        sel.addRange(range);
        this.focus();
        }
    });
        #editor {
            width: 400px;
            height: 100px;
            padding: 10px;
            background-color: #444;
            color: white;
            font-size: 14px;
            font-family: monospace;
        }
        .statement {
            color: orange;
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="editor" contenteditable="true"></div>

I tried to make it as below: but it failed:

    // SQL keywords
    var keywords = ["SELECT","FROM","WHERE","LIKE","BETWEEN", "UNION",
    "FALSE","NULL","FROM","TRUE","NOT", "ORDER", "GROUP", "BY", "NOT", "IN"];
    // Keyup event
    document.querySelector('#editor').addEventListener('keyup', e => {
    // Space key pressed
    if (e.keyCode == 32){
        var newHTML = "";
        // Loop through words
        str = e.target.innerHTML
        str.replace(/[\s]+/g, " ").trim().split(" ").forEach(val => {
        // If word is statement
        if (keywords.indexOf(val.trim().toUpperCase()) > -1)
            newHTML += "<span class='statement'>" + val + "&nbsp;</span>";
        else
            newHTML += "<span class='other'>" + val + "&nbsp;</span>"; 
        });
        e.target.innerHTML = newHTML;

        // Set cursor postion to end of text

        var el =  e.target; 
        el.focus()
        if (typeof el.selectionStart == "number") {
            el.selectionStart = el.selectionEnd = el.value.length;
        } else if (typeof el.createTextRange != "undefined") {           
            var range = el.createTextRange();
            range.collapse(false);
            range.select();
        }
    }
    });
       #editor {
            width: 400px;
            height: 100px;
            padding: 10px;
            background-color: #444;
            color: white;
            font-size: 14px;
            font-family: monospace;
        }
        .statement {
            color: orange;
        }
<div id="editor" contenteditable="true"></div>

I think my mistake is in returning the cursor to the end of the text field though I tried to implement this

Hasan A Yousef
  • 22,789
  • 24
  • 132
  • 203

2 Answers2

0

Here is my answer.

// SQL keywords
var keywords = ["SELECT", "FROM", "WHERE", "LIKE", "BETWEEN", "UNION", "FALSE", "NULL", "FROM", "TRUE", "NOT", "ORDER", "GROUP", "BY", "NOT", "IN"];
// Keyup event
document.querySelector('#editor').addEventListener('keyup', e => {
    // Space key pressed
    if (e.keyCode == 32) {
        var newHTML = "";
        // Loop through words
        str = e.target.innerText;
        str.replace(/[\s]+/g, " ").trim().split(" ").forEach(val => {
            // If word is statement
            if (keywords.indexOf(val.trim().toUpperCase()) > -1)
                newHTML += "<span class='statement'>" + val + "&nbsp;</span>";
            else
                newHTML += "<span class='other'>" + val + "&nbsp;</span>";
        });
        console.log(newHTML);
        e.target.innerHTML = newHTML;

        // Set cursor postion to end of text
        //    document.querySelector('#editor').focus()
        var child = e.target.children;
        var range = document.createRange();
        var sel = window.getSelection();
        range.setStart(child[child.length - 1], 1);
        range.collapse(true);
        sel.removeAllRanges();
        sel.addRange(range);
        this.focus();
            
    }
});
#editor {
    width: 400px;
    height: 100px;
    padding: 10px;
    background-color: #444;
    color: white;
    font-size: 14px;
    font-family: monospace;
}
.statement {
    color: orange;
}
<div id="editor" contenteditable="true"></div>

I've used

var child = e.target.children;
var range = document.createRange();
var sel = window.getSelection();
range.setStart(child[child.length - 1], 1);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
this.focus();

instead of

var el = e.target;
el.focus()
if (typeof el.selectionStart == "number") {
    el.selectionStart = el.selectionEnd = el.value.length;
} else if (typeof el.createTextRange != "undefined") {
    var range = el.createTextRange();
    range.collapse(false);
    range.select();
}
  • 2
    Please update your answer with a summary of what the answer is...not just code. – devlin carnate Sep 24 '20 at 20:15
  • Just for your notice: while this works *as you type* it doesn't apply proper highlight on edit. E.g. if you made a typo in 'select' and than noticed that and fixed, your code doesn't recognize that as a valid keyword. – Yevhen Horbunkov Sep 24 '20 at 20:20
  • @YevgenGorbunkov why you deleted your answer, I liked the way you made it, thought is given 100% solution, I'm not the one who downvoted it. – Hasan A Yousef Sep 24 '20 at 20:29
  • @YevgenGorbunkov actually it is doing the highlight upon the first `space` you do after correcting the error – Hasan A Yousef Sep 24 '20 at 20:31
  • Thanks, can you pls explain the code the make the cursor go to the end – Hasan A Yousef Sep 24 '20 at 20:33
  • 1
    Line2: Create the new range object. Line3: Here 'sel' is created object for window Line4: Setting start position of a Range Line5: Collapses the Range to one of its Line6,7: Remove all old range and add new range Line8: Focus the element –  Sep 24 '20 at 20:36
0

Building on both answers, the accepted one, and the deleted one from @Yevgen, I preferred the below code, @Yevgen functional approach handle "group by" in a good way, while the other approach is not:

    // SQL keywords
    var keywords = ["SELECT", "FROM", "WHERE", "LIKE", "BETWEEN", "UNION", "FALSE", "NULL", "FROM", "TRUE", "NOT", "ORDER", "GROUP BY", "NOT", "IN"];
    // Keyup event
    document.querySelector('#editor').addEventListener('keyup', e => {
    // Space key pressed
    if (e.keyCode == 32) {
        var newHTML = "";
        // Loop through words
        str = e.target.innerText;
        chunks = str
          .split(RegExp(keywords.map(w => `(${w})`).join('|'), 'i'))
          .filter(Boolean)
        markup = chunks.reduce((acc, chunk) => {
          acc += keywords.includes(chunk.toUpperCase()) ?
          `<span class="statement">${chunk}</span>` :
          `<span class='other'>${chunk}</span>`
          return acc
        }, '')      
        e.target.innerHTML = markup;

        // Set cursor postion to end of text
        var child = e.target.children;
// Create the new range object. 
        var range = document.createRange();
// Here 'sel' is created object for window 
        var sel = window.getSelection();
// Setting start position of a Range 
        range.setStart(child[child.length - 1], 1);
// Collapses the Range to one of its 
        range.collapse(true);
// Remove all old range 
        sel.removeAllRanges();
// Add new range
        sel.addRange(range);
// Focus the element 
        this.focus();
            
        }
    });
        #editor {
            width: 400px;
            height: 100px;
            padding: 10px;
            background-color: #444;
            color: white;
            font-size: 14px;
            font-family: monospace;
        }
        .statement {
            color: orange;
        }
<div id="editor" contenteditable="true"></div>
Hasan A Yousef
  • 22,789
  • 24
  • 132
  • 203