2

How do i insert a div inside the content of another content-editable div? The parent div is a content-editable one and its contains string content. I want to insert another content-editable div when i type '@' at the cursor position.

for example,

 <div id="target" class="text-area" contenteditable='true'>This text can be anything... how to insert a div when i type start typing @... </div>

I want to insert another div when i type '@'? How can i achieve this?

Here is what i tried out JSBIN

Please help me. Thanks in advance

selvagsz
  • 3,852
  • 1
  • 24
  • 34

4 Answers4

2

This seemed to work for me. I just added in a $(this).append(...)

$("#target").keydown(function(e) {

//  console.log(e, String.fromCharCode(e.which));

  if(e.which === 50 && e.shiftKey === true ){
      if(flag === true){
        flag = false;      
        return;
      }      
      flag = true;
    $(this).append('<div id="target2" contenteditable="true">New Div</div>');
      //console.log($('#target'),$('#target').prop('selectionStart'));
    } 
});
Brian Hoover
  • 7,861
  • 2
  • 28
  • 41
  • Using append() will not position the div at the cursor point... The new div will be appended as a childnode rather than appending at the cursor position... If i type '@' anywhere in between the string, i want the new div to be appended at the cursor position. Is there a way ?? – selvagsz Jun 25 '13 at 15:16
1

One option would be to detect the keydown event on the '@' character and then place an absolutely positioned div at the current cursor location.

Getting the cursor position is a decent bit of code. Luckily, someone already wrote it. The code is as follows:

function getTextAreaXandY() {



   // Don't do anything if key pressed is left arrow
    if (e.which == 37) return;     

    // Save selection start
    var selection = $(this).getSelection();
    var index = selection.start;

    // Copy text to div
    $(this).blur();
    $("div").text($(this).val());

    // Get current character
    $(this).setSelection(index, index + 1);
    currentcharacter = $(this).getSelection().text;

    // Get previous character
    $(this).setSelection(index - 1, index)
    previouscharacter = $(this).getSelection().text;

    var start, endchar;
    var end = 0;
    var range = rangy.createRange();

    // If current or previous character is a space or a line break, find the next word and wrap it in a span
    var linebreak = previouscharacter.match(/(\r\n|\n|\r)/gm) == undefined ? false : true;

    if (previouscharacter == ' ' || currentcharacter == ' ' || linebreak) {
        i = index + 1; // Start at the end of the current space        
        while (endchar != ' ' && end < $(this).val().length) {
            i++;
            $(this).setSelection(i, i + 1)
            var sel = $(this).getSelection();
            endchar = sel.text;
            end = sel.start;
        }

        range.setStart($("div")[0].childNodes[0], index);
        range.setEnd($("div")[0].childNodes[0], end);
        var nextword = range.toHtml();
        range.deleteContents();
        var position = $("<span id='nextword'>" + nextword + "</span>")[0];
        range.insertNode(position);
        var nextwordtop = $("#nextword").position().top;
    }

    // Insert `#caret` at the position of the caret
    range.setStart($("div")[0].childNodes[0], index);
    var caret = $("<span id='caret'></span>")[0];
    range.insertNode(caret);
    var carettop = $("#caret").position().top;

    // If preceding character is a space, wrap it in a span
    if (previouscharacter == ' ') {
        range.setStart($("div")[0].childNodes[0], index - 1);
        range.setEnd($("div")[0].childNodes[0], index);
        var prevchar = $("<span id='prevchar'></span>")[0];
        range.insertNode(prevchar);
        var prevchartop = $("#prevchar").position().top;
    }

    // Set textarea selection back to selection start
    $(this).focus();
    $(this).setSelection(index, selection.end);

    // If the top value of the previous character span is not equal to the top value of the next word,
    // there must have been some wrapping going on, the previous character was a space, so the wrapping
    // would have occured after this space, its safe to assume that the left and top value of `#nextword`
    // indicate the caret position
    if (prevchartop != undefined && prevchartop != nextwordtop) {
        $("label").text('X: ' + $("#nextword").position().left + 'px, Y: ' + $("#nextword").position().top);
        $('ul').css('left', ($("#nextword").position().left) + 'px');
        $('ul').css('top', ($("#nextword").position().top + 13) + 'px');
    }
    // if not, then there was no wrapping, we can take the left and the top value from `#caret`    
    else {
        $("label").text('X: ' + $("#caret").position().left + 'px, Y: ' + $("#caret").position().top);
        $('ul').css('left', ($("#caret").position().left) + 'px');
        $('ul').css('top', ($("#caret").position().top + 14) + 'px');
    }

    $('ul').css('display', 'block');
}

$("textarea").click(getTextAreaXandY);
$("textarea").keyup(getTextAreaXandY);

Their fiddle is here, and it was written in response to this question.

The fiddle includes placing a new div at the current cursor position.

Community
  • 1
  • 1
ckersch
  • 7,507
  • 2
  • 37
  • 44
0

I modified the onKeyDown event listener. Binding the keydown event to div which id equal to target.

Hope this is helpful for you. http://jsbin.com/ilikay/4/edit

Chickenrice
  • 5,727
  • 2
  • 22
  • 21
-1

Finally had a way to reach it... This is how i did it ...

  1. Get the string index at the cursor position in the textarea by using selectionStart
  2. slice the string from index 0 to the cursor position
  3. Insert it into a span (since span has multiple border boxes)
  4. Get the dimensions of the border box using element.getClientRects() relative to the view port. (here is the MDN Reference)
  5. Calculate the top and left and feed it to the dropdown

This works in all latest browsers. haven't tested at old ones

Here is Working bin

selvagsz
  • 3,852
  • 1
  • 24
  • 34