Suraj Pawar
Suraj Pawar

Reputation: 239

How to insert link for hashtags and mentions in react quill?

I am using react quill as rich text editor and I have used quill mention for adding hashtags and people mention in editor. I have went through the docs of quill mention but there is no example for adding links to inserted "hashtag" or "mention".

There is prop, "linkTarget" for adding link but there is no example for addition of link to hashtag and mention.

Hashvalues and atvalues from database:

hashvalues:[{
id:1,
value:"newHashtag"
}]

atvalues:[{
id:1,
value:"Jhon"
}]

So my expected output is: for hashtag:

<a href:`/#/hashtags/${id}`>#{value}</a>

for people mention:

<a href:`/#/people/${id}`>@{value}</a>

Here's my code for text editor and mention module:

import React, { useEffect, useState } from "react";
import ReactQuill, { Quill } from "react-quill";
import * as Emoji from "quill-emoji";
import "react-quill/dist/quill.snow.css";
import "quill-emoji/dist/quill-emoji.css";
import "quill-mention/dist/quill.mention.css";
import "quill-mention";

//Add https to link if https is not present
const Link = Quill.import("formats/link");
Link.sanitize = function (url) {
  // quill by default creates relative links if scheme is missing.
  if (!url.startsWith("http://") && !url.startsWith("https://")) {
    return `http://${url}`;
  }
  return url;
};
Quill.register(Link, true);
Quill.register("modules/emoji", Emoji);

// Add sizes to whitelist and register them
const Size = Quill.import("formats/size");
Size.whitelist = ["extra-small", "small", "medium", "large"];
Quill.register(Size, true);

// Add fonts to whitelist and register them
const Font = Quill.import("formats/font");
Font.whitelist = [
  "arial",
  "comic-sans",
  "courier-new",
  "georgia",
  "helvetica",
  "lucida",
];
Quill.register(Font, true);

let atValues = [];
let hashValues = [];


const mention = {
  allowedChars: /^[A-Za-z\sÅÄÖåäö]*$/,
  mentionDenotationChars: ["@", "#"],
  linkTarget:"https://www.google.com",
  source: function (searchTerm, renderList, mentionChar, ) {
    let values;

    if (mentionChar === "@") {
      values = atValues;
    } else {
      values = hashValues;
    }

    if (searchTerm.length === 0) {
      renderList(values, searchTerm);
    } else {
      const matches = [];
      for (let i = 0; i < values.length; i++)
        if (~values[i].value.toLowerCase().indexOf(searchTerm.toLowerCase()))
          matches.push(values[i]);
      renderList(matches, searchTerm);
    }
  },
};

function Editor(props) {
  const [editorHtml, setEditorHtml] = useState("");

  const handleChange = (html) => {
    setEditorHtml(html);
    props.changeHandler(html);
  };

  useEffect(() => {
    if (props.value) {
      setEditorHtml(props.value);
    } else {
      setEditorHtml("");
    }
    if(props.values){
      let hash=props.values
      hash.map((v) => {
        v["value"] = v["display"]
      })
      hashValues=hash
    }
    if(props.people){
      let peoples = props.people
      peoples.map((v) => {
        v["value"] = v["display"]
      })
      atValues=peoples
    }
  }, [props.value]);

  return (
    <div>
      <ReactQuill
        onChange={handleChange}
        value={editorHtml}
        modules={modules}
        formats={formats}
        bounds={".app"}
        placeholder={props.placeholder}
      />
    </div>
  );
}

const modules = {
  toolbar: [
    [{ header: [1, 2, 3, 4, 5, 6, false] }],

    [{ list: "ordered" }, { list: "bullet" }],
    ["bold", "italic", "underline"],
    [{ color: [] }, { background: [] }],
    // [{ script: 'sub' }, { script: 'super' }],
    [{ align: [] }],
    ["link", "blockquote", "emoji"],
    ["clean"],
  ],
  clipboard: {
    // toggle to add extra line breaks when pasting HTML:
    matchVisual: false,
  },
  mention,
  "emoji-toolbar": true,
  "emoji-textarea": false,
  "emoji-shortname": true,
};

const formats = [
  "header",
  "font",
  "size",
  "bold",
  "italic",
  "underline",
  "strike",
  "blockquote",
  "list",
  "bullet",
  "indent",
  "link",
  "mention",
  "emoji",
];

export default function EMTextArea({
  placeHolder,
  name,
  value,
  changeHandler,
  hash,
  peopleMention
}) {
  return (
    <div className="custom-toolbar-example">
      <Editor
        placeholder={placeHolder}
        name={name}
        value={value}
        changeHandler={changeHandler}
        values={hash}
        people={peopleMention}
      />
    </div>
  );
}

How can I achieve this? Thank You!

Upvotes: 2

Views: 6471

Answers (1)

Suraj Pawar
Suraj Pawar

Reputation: 239

I solved it, I had to add "link" key in atvalues and hashvalues array of objects.

New hashvalues:

hashvalues:[{
id:1,
value:"hashtag",
link:"/#/users/hashtags/1"}]

And in mention module:

const mention = {
  allowedChars: /^[A-Za-z\sÅÄÖåäö]*$/,
  mentionDenotationChars: ["@", "#"],
  linkTarget: '_self',
  source: function (searchTerm, renderList, mentionChar, ) {
    let values;

    if (mentionChar === "@") {
      values = atValues;
    } else {
      values = hashValues;
    }

    if (searchTerm.length === 0) {
      renderList(values, searchTerm);
    } else {
      const matches = [];
      for (let i = 0; i < values.length; i++)
        if (~values[i].value.toLowerCase().indexOf(searchTerm.toLowerCase()))
          matches.push(values[i]);
      renderList(matches, searchTerm);
    }
  },
};

Thanks, anyway.

Upvotes: 1

Related Questions