emoji-mart-vue icon indicating copy to clipboard operation
emoji-mart-vue copied to clipboard

Docs: using with contenteditable

Open keligijus opened this issue 7 years ago • 9 comments

I can't figure out the example of using <emoji> component inside contenteditable. It seems that the example has been taken from original React lib and is a React example.

Is it possible to achieve similar in Vue?

keligijus avatar Jun 13 '18 13:06 keligijus

You're right, that example did come from React and I haven't been able to recreate the functionality. I've temporarily removed that section of the readme to prevent confusion. Will update this issue if I'm able to figure it out.

jm-david avatar Jul 25 '18 23:07 jm-david

@jm-david @keligijus did you guys get any solution for this ? Thank you .

bujji1 avatar Jan 11 '19 23:01 bujji1

Nope, no luck, if I remember well, I had to take a different approach.

keligijus avatar Jan 13 '19 12:01 keligijus

@keligijus - No luck for me . I tried

  1. Getting the current carrot position of div
  2. Saving the position
  3. Getting the contents of the clicked emoji
  4. Inserting the contents of the clicked emoji at the saved position in the 2nd step .

But this is all messing up . You said you took a different approach . If you don't mind can I know the approach that you took .

Thanks

bujji1 avatar Feb 24 '19 17:02 bujji1

@bujji1 what is failing in your solution?

keligijus avatar Feb 25 '19 14:02 keligijus

It is not consistent and also I can not able to delete it id user wants to delete it with Backspace. The approach I took is kind of fake .

You can see the first "tempId" below , this is what holds the current emoji whatever user selected . I read the content from this Div and add it to my "ContentEditable " Div . :)

    <div
      id="tempId"
      style="position:fixed;top:-30px;"
    >
      <emoji
        :emoji="currentEmoji"
        set="twitter"
        :size="25"
      />
    </div>
` getNodeIndex(n) {
      var i = 0;
      while ((n = n.previousSibling)) i++;
      return i;
    },

    saveRangePosition() {
      try {
        var range = window.getSelection().getRangeAt(0);
        var sC = range.startContainer,
          eC = range.endContainer;

        let A = [];
        while (sC !== k1Editor) {
          A.push(this.getNodeIndex(sC));
          sC = sC.parentNode;
        }
        let B = [];
        while (eC !== k1Editor) {
          B.push(this.getNodeIndex(eC));
          eC = eC.parentNode;
        }
        window.rp = {
          sC: A,
          sO: range.startOffset,
          eC: B,
          eO: range.endOffset
        };
      } catch (err) {}
    },

    restoreRangePosition() {
      try {
        let k1Editor = document.getElementById("k1Editor");
        k1Editor.focus();
        var sel = window.getSelection(),
          range = sel.getRangeAt(0);
        var x,
          C,
          sC = k1Editor,
          eC = k1Editor;

        C = rp.sC;
        x = C.length;
        while (x--) sC = sC.childNodes[C[x]];
        C = rp.eC;
        x = C.length;
        while (x--) eC = eC.childNodes[C[x]];

        range.setStart(sC, rp.sO);
        range.setEnd(eC, rp.eO);
        sel.removeAllRanges();
        sel.addRange(range);
      } catch (err) {}
    },

    insertTextAtCursor(text) {
      self=this;
      var sel, range, html;
      sel = window.getSelection();
      range = sel.getRangeAt(0);
      range.deleteContents();
      var textNode = document.createTextNode("\u00A0");

      setTimeout(function() {
        var MyDiv1 = document.getElementById("tempId").innerHTML;

        var nnode = document.createElement("b");
        nnode.innerHTML = MyDiv1;
        range.insertNode(nnode);
        range.setStartAfter(nnode);

        range.insertNode(textNode);
        range.setStartAfter(textNode);
        sel.removeAllRanges();
        sel.addRange(range);
        self.saveRangePosition();
      }, 100);
    },

    addEmoji(emoji) {
      self = this;
      this.restoreRangePosition();
      console.log(emoji);
      this.currentEmoji = emoji.id;
      this.count++;
      this.insertTextAtCursor(emoji.native);
      setTimeout(function() {
        self.dataHTML = document.getElementById("k1Editor").innerHTML;
        self.$emit("dataHTML", self.dataHTML);
      }, 100);
    },`

bujji1 avatar Feb 25 '19 14:02 bujji1

@bujji1 this seems like a Stack Overflow type of question. Managing caret position is really messy in content editable.

If I recall correctly, my solution was to deal with native emojis when inserting them. This way it's just another text node and caret position seems a lot easier to manage when you only care about text nodes.

Sorry, I am not sure if I can help you more. This lib is not dealing with caret positioning, that's something we need to do ourselves :|

keligijus avatar Feb 25 '19 14:02 keligijus

I have the same issue and I need to use custom emojis so I need to insert images into contenteditable, for now I couldn't figure out how to make it work correctly. Currently I'm trying to render EmojiNimble component into a string and insert that into contenteditable, but couldn't figure out how to render VNode into a string.

vedmant avatar Jun 24 '19 10:06 vedmant

You can look at this article Thank you Konstantin Münster

https://javascript.plainenglish.io/how-to-find-the-caret-inside-a-contenteditable-element-955a5ad9bf81

https://9tq3o.csb.app/

agb avatar Feb 18 '22 05:02 agb