/**
 * Imports necessary components and utilities for the edit.js file.
 * This includes components for handling allowed blocks, the board, non-text comments, and various utility functions.
 * It also imports necessary WordPress packages and initializes a NonTextComments instance.
 */

// Import necessary components and utilities
import allowedBlocks from "../common/component/compatibility/allowedBlocks";
import Board from "../comment/board";
import NonTextComments from "../comment/component/nonTextComments";
import PropTypes from "prop-types";
import { getBoardIds, openCommentBoardSidebar, removeBlankPopup, showNotice } from '../common/utils';

// Import WordPress packages
const { __ } = wp.i18n;
const { applyFormat, removeFormat } = wp.richText; // eslint-disable-line
const { BlockControls, RichTextShortcut } = wp.blockEditor; // eslint-disable-line
const { Component, createRoot, Fragment } = wp.element; // eslint-disable-line
const { dispatch, select } = wp.data; // eslint-disable-line
const { displayShortcut } = wp.keycodes;
const { ToolbarButton, ToolbarGroup } = wp.components; // eslint-disable-line
const { toggleFormat } = wp.richText; // eslint-disable-line

// Initialize NonTextComments instance
const NonTextComment = new NonTextComments();  

// Initialize container variable
let container = null;

// Define the mdComment object
export const mdComment = {
  name: "multidots/comment",
  title: __("Comment", "commenting-feature"),
  tagName: "mdspan",
  className: "mdspan-comment",
  attributes: {
    datatext: "datatext",
  },
  edit: class toggleComments extends Component {
    constructor(props) {
      super(props);
      // Bind methods to the class instance
      this.onToggle = this.onToggle.bind(this);
      this.onApply = this.onApply.bind(this);
      this.getSelectedText = this.getSelectedText.bind(this);
      this.floatComments = this.floatComments.bind(this);
      // Initialize component state
      this.state = {
        suggestionToggle: false,
      };
      
      // Typecheck for props
      toggleComments.propTypes = {
        value: PropTypes.object,
        activeAttributes: PropTypes.object,
        onChange: PropTypes.func,
        isActive: PropTypes.bool,
      };
    }

    /**
     * Toggles the comment functionality for the selected text or block.
     *
     * This method is responsible for handling the logic of adding a comment to the selected text or block. It checks various conditions to ensure that the comment can be added, such as whether the selected text is within a reusable block, whether there are already comments on the same block, and whether the selected text is valid for commenting. It then creates a new comment node, appends it to the comment container, and applies the comment format to the selected text.
     *
     */
    async onToggle() {
      
      const { value, onChange, activeAttributes, contentRef } = this.props;
      const { suggestionToggle } = this.state;
      let { text, start, end } = value;
      let commentedOnText = text.substring(start, end);
      const block = select("core/block-editor").getSelectedBlock();

      let suggestionFlag = false;
      if (true === suggestionToggle) {
        dispatch("core/editor")
          .editPost({ meta: { _sb_is_suggestion_mode: false } });
        suggestionFlag = true;
      }

      // Prevent comment in reusable block inside text/html. @author: Nirav Soni.
      if( true === contentRef.current?.parentNode?.parentNode?.classList?.contains('is-reusable') || true === contentRef.current?.parentNode?.classList?.contains('is-reusable') ) {
        return;
      }

      // If text is not selected, show notice.
      //change code to support whole block comment/@author:Pooja/since 3.4
      if (
        start === end &&
        (allowedBlocks.media.includes(block?.name) ||
          "figcaption" === contentRef?.current?.localName)
      ) {
        showNotice(__("Please select a block, text or media to comment on.", "commenting-feature"));
        return;
      }
      await openCommentBoardSidebar();

      //If comment box already open, show notice.
      var activeDataText = activeAttributes.datatext;
      const getBoardDataText = document.getElementById('cf-comment-board-wrapper');
      const openBoardDataText = getBoardDataText?.querySelector('.is-open')?.getAttribute('id');

      if (start !== end) { // Removed table condition to fix Git issue #1409
        if (activeDataText === openBoardDataText && openBoardDataText !== undefined) {
          showNotice(__("Multiple comments are not possible on the same block.", "commenting-feature"));
          // Added condition to resolve GitHub issue #1205
          return;
        }
      }

      var html = getSelectionHtml();
      let already_commented = false;
      const parentElementOfFloatingButton = document.querySelector('.cf-floating-wrapper-main');
      if (parentElementOfFloatingButton) {
        already_commented = parentElementOfFloatingButton.querySelector(".cf-floating-wrapper__btn ul li:first-child")?.getAttribute("already_commented");
      }
      if (null !== html.match(/td/g)  && "core/table" === block?.name) { //To Fix Git issue #1424 to restrict multiple cell comments
        showNotice(__("Comments are not posible on multiple cells.", "commenting-feature"));
        return;
      }

      if (null !== html.match(/mdspan/g) || "true" === already_commented) {
        showNotice(__("Multiple comments are not possible on the same block.", "commenting-feature"));
        // Set _sb_is_suggestion_mode true if Multiple comments notice display. Github issue: 1087
        setTimeout(() => {
          if (true === suggestionFlag) {
            dispatch("core/editor")
              .editPost({ meta: { _sb_is_suggestion_mode: true } });
          }
        }, 2000);
        return;
      }
      //commented on text for inline image
      var srcMatch = html.match(/\<img.+src\=(?:\"|\')(.+?)(?:\"|\')(?:.+?)\>/);
      if (null !== srcMatch) {
        var srcText = srcMatch[1].split("/");
        srcText = srcText[srcText.length - 1];
        commentedOnText = srcText;
      }
      var currentTime = Date.now();
      currentTime = "el" + currentTime;
      var newNode = document.createElement("div");
      newNode.setAttribute("id", currentTime);
      newNode.setAttribute("class", "cls-board-outer draftComment cm-board");
      var referenceNode = document.getElementById("cf-comment-board-wrapper");
      if (null === referenceNode) {
        createCommentNode();
        referenceNode = document.getElementById("cf-comment-board-wrapper");
      }

      referenceNode.appendChild(newNode);

      //Activate Show All comment button in setting panel
      if (false === select("mdstore").getShowComments()) {
        dispatch("mdstore").setShowComments(true);
        const componentsToggle = document.querySelectorAll(".comment-toggle .components-form-toggle");
        componentsToggle.forEach(cmt => {
          cmt.classList.remove("is-checked");
        });
      }
      
      container = document.getElementById(currentTime);
      const root = createRoot(container); // createRoot(container!) if you use TypeScript

      onChange(
        toggleFormat(value, { type: mdComment.name }),
        root.render(
          <Board
              datatext={currentTime}
              onChanged={onChange}
              lastVal={value}
              freshBoard={1}
              commentedOnText={commentedOnText}
            />
        )
      );
      removeFloatingIcon();

      onChange(
        applyFormat(value, {
          type: mdComment.name,
          attributes: { datatext: currentTime },
        })
      );
      // Toogle hide-comments class if the comments is hidden when try to add new one.
      if (document.body.classList.contains("hide-comments")) {
        document.body.classList.remove("hide-comments");
        dispatch("core/editor").editPost({
          meta: { _sb_show_comment_boards: false },
        });
      }
     
      const eventEditorLayoutUpdate = new CustomEvent("editorLayoutUpdate");
      document.dispatchEvent(eventEditorLayoutUpdate);
  
    }

    /**
     * Handles the application of a comment to the currently selected block.
     *
     * This function checks the type of the currently selected block and applies the appropriate comment action. If the selected block is a text block or a figcaption, it clicks the "toolbar-button-with-text" button to apply the comment. Otherwise, it clicks the "toolbar-button-with-nontext" button.
     */
    onApply() {
      const iframe = cfGetIframe();
      const iframeDocument = iframe ? iframe.contentWindow.document : null;
      var block = select("core/block-editor").getSelectedBlock();

      let focusedElement;
      let isRichClassExist;
      if( iframeDocument ){
        focusedElement = iframeDocument.activeElement.localName;
        isRichClassExist = iframeDocument.activeElement.classList.contains("rich-text");
      } else {
        focusedElement = document.activeElement.localName;
        isRichClassExist = document.activeElement.classList.contains("rich-text");
      }
      if (
        allowedBlocks.text.includes(block?.name) ||
        "figcaption" === focusedElement ||
        isRichClassExist
      ) {
        const buttonWithText = document.querySelector(".toolbar-button-with-text.comment-group-button");
        if (buttonWithText) {
          buttonWithText.click();
        }
      } else {
        const buttonWithNonText = document.querySelector(".toolbar-button-with-nontext");
        if (buttonWithNonText) {
          buttonWithNonText.click();
        }
      }
    }

    /**
     * Handles the selection of text in the editor and applies the appropriate comment actions.
     *
     * This function performs the following tasks:
     * - Checks if the selected text is part of a reusable block and hides/shows the appropriate toolbar buttons.
     * - Extracts the selected text and any associated formatting attributes.
     * - Checks if the selected text has any existing comments and handles the display of the comment boards accordingly.
     * - Applies the appropriate comment action based on the type of the selected block (text block, figcaption, or other).
     * - Synchronizes the comment popups with the highlighted text.
     * - Handles the display of the comment history toggle button.
     */
    getSelectedText() {
      
      const { onChange, value, activeAttributes, contentRef } = this.props;
      const selectedBlockID = select("core/block-editor").getSelectedBlock()?.clientId;
      const activeFormats = value.activeFormats;
      const replacements = value.replacements;
      const iframe = cfGetIframe();
      const iframeDocument = iframe ? iframe.contentWindow.document : null;

      if(activeAttributes.datatext ){
         openCommentBoardSidebar();
       }else{
        if (undefined !== activeFormats && activeFormats.length > 0) {
            activeFormats.some((activeFormat) => {
                if (activeFormat.attributes) {
                  const boardIds = select('mdstore').getBoardIds();
                  if(boardIds.length > 0){
                    openCommentBoardSidebar();
                  }
                  return true; // Exit the loop
                }
                return false;
            });
        }
      }

      let mdspanElements;
      let commentWholeBlockElements;
      let suggestionElements;
      if(iframeDocument){
        mdspanElements = iframeDocument.getElementsByTagName("mdspan");
        commentWholeBlockElements = iframeDocument.querySelectorAll('.cf-icon-wholeblock__comment');
        suggestionElements = iframeDocument.querySelectorAll('ins.mdadded, ins.mdmodified, ins.mdremoved, del.mdremoved');
      }else{
        mdspanElements = document.getElementsByTagName("mdspan");
        commentWholeBlockElements = document.querySelectorAll('.cf-icon-wholeblock__comment');
        suggestionElements = document.querySelectorAll('ins.mdadded, ins.mdmodified, ins.mdremoved, del.mdremoved');
      }
      for (let i = 0; i < mdspanElements.length; i++) {
        mdspanElements[i].removeAttribute("data-rich-text-format-boundary");
      }
      // Loop through each element and remove the 'focus' class if present
      commentWholeBlockElements.forEach(element => {
          if (element.classList.contains('focus')) {
              element.classList.remove('focus');
          }
      });

      suggestionElements.forEach(element => {
        element.removeAttribute("data-rich-text-format-boundary");
      });

      // Prevent comment in reusable block inside text/html. @author: Nirav Soni.
      if( true === contentRef.current?.parentNode?.parentNode?.classList?.contains('is-reusable') || true === contentRef.current?.parentNode?.classList?.contains('is-reusable') ) {
          setTimeout(function () {
            // Hide parent elements of elements with class 'toolbar-button-with-text'
            const textButtons = document.getElementsByClassName('toolbar-button-with-text');
            for (let i = 0; i < textButtons.length; i++) {
              const parent = textButtons[i].parentElement;
              if (parent) {
                parent.style.display = 'none';
              }
            }
            // Show parent elements of elements with class 'toolbar-button-with-nontext'
            const nonTextButtons = document.getElementsByClassName('toolbar-button-with-nontext');
            for (let i = 0; i < nonTextButtons.length; i++) {
              const parent = nonTextButtons[i].parentElement;
              if (parent) {
                parent.style.display = 'block';
              }
            }
          }, 50);
      }

      // check for text-block aling suggestion with git issue #337 /@author Nirav Soni/@since 4.6
      let floatText = [];
      if (undefined !== replacements && replacements.length > 0) {
        replacements.map((replacement) => {
          if (
            undefined !== replacement.attributes 
          ) {
            if (replacement.attributes.id) {
              selectedText = replacement.attributes.id;
              floatText.push(selectedText);
            }
          }
        });
      }

      if ((undefined === activeFormats || 0 === activeFormats.length) && 0 === floatText.length) {
        return;
      }
      let selectedText;
      //if copy URL exist remove from existing URL
      const queryString = window.location.search; //phpcs:ignore
      const urlParams = new URLSearchParams(queryString);
      const current_url = urlParams.get("current_url");
      let shareUrl = getCookie("current_url");

      if (current_url) {
        urlParams.delete("current_url");
        window.history.replaceState(
          {},
          "",
          `${location.pathname}?${urlParams}`
        );
      }
      if (shareUrl) {
        deleteCookie("current_url");
      }

      // Stripping out unwanted <mdspan> tags from the content.
      const findMdSpan = "mdspan";
      let findMdSpanElements;
      if(iframeDocument){
        findMdSpanElements = iframeDocument.querySelectorAll(findMdSpan);
      }else{
        findMdSpanElements = document.querySelectorAll(findMdSpan);
      }

      findMdSpanElements.forEach(spanElement => {
        const datatext = spanElement.getAttribute("datatext");
        if (datatext === null || datatext === undefined) {
          const textNode = document.createTextNode(spanElement.textContent);
          spanElement.parentNode.replaceChild(textNode, spanElement);
        }
      });

      // Prevent on locked mode + fix for unnecessary calls on hover.
      const clsBoardOuter = document.querySelector(".cls-board-outer");
      if (clsBoardOuter && clsBoardOuter.classList.contains("locked")) {
        return;
      }

      // Add condition to solve @ mentioned remove issue while enter after @ sign. @Author: Rishi Shah
      // Ignore unnecessary event calls on hover.
     
      const clsBoardOuterActiveAttributes = document.querySelector("#" + activeAttributes.datatext + ".cls-board-outer");
      const jsCfShareComment = document.querySelector(".js-cf-share-comment");

      if (
        clsBoardOuterActiveAttributes && clsBoardOuterActiveAttributes.classList.contains("focus") &&
        jsCfShareComment && jsCfShareComment.classList.contains("comment-focus")
      ) {
        return;
      }

      
      var referenceNode = document.getElementById("cf-comment-board-wrapper");
      // Remove tags if selected tag ID exist in 'remove-comment' attribute of body.
      let removedComments = document.body.getAttribute("remove-comment");
      if (
        undefined !== activeAttributes.datatext &&
        undefined !== removedComments &&
        removedComments !== null &&
        removedComments.indexOf(activeAttributes.datatext) !== -1
      ) {
        onChange(removeFormat(value, name));
      }

      if (undefined !== this.props.value.start && null !== referenceNode) {
        const clsBoardOuterElements = document.getElementsByClassName("cls-board-outer");
        for (let i = 0; i < clsBoardOuterElements.length; i++) {
          clsBoardOuterElements[i].classList.remove("has_text");
        }
        
        selectedText = activeAttributes.datatext;
        if (selectedText) {
          removeBlankPopup(selectedText);
        }

        // Just hide these popups and only display on CTRLz

        const cfSpanComments = document.getElementById("cf-comment-board-wrapper");
        if (cfSpanComments) {
          const clsBoardOuterElements = cfSpanComments.getElementsByClassName("cls-board-outer");
          for (let i = 0; i < clsBoardOuterElements.length; i++) {
            const element = clsBoardOuterElements[i];
            if (!element.classList.contains("has_text") && !element.hasAttribute("data-sid")) {
              // Remove visible
              const historyToggle = document.getElementById("history-toggle");
              if (historyToggle) {
                const count = document.getElementsByClassName("cls-board-outer").length;
                historyToggle.setAttribute("data-count", count);
              }
            }
          }
        }

        if (undefined !== activeFormats && activeFormats.length > 0) {
          {
            activeFormats.map((activeText) => {
              if (
                undefined !== activeText.attributes &&
                "core/link" !== activeText.type &&
                "core/underline" !== activeText.type
              ) {
                // added underline condition to resolve GitHub issue 441.
                if (activeText.attributes.id) {
                  selectedText = activeText.attributes.id;
                  floatText.push(selectedText);
                } else {
                  if (activeText.attributes.datatext) {
                    selectedText = activeText.attributes.datatext;
                    floatText.push(selectedText);
                  }
                }
              } else {
                var html = getSelectionHtml();
                if (html.match(/mdmodified/g)) {
                  var tmpDiv = document.createElement("div");
                  tmpDiv.appendChild(document.createRange().createContextualFragment(html));
                  floatText.push(
                    tmpDiv?.querySelector(".mdmodified")?.getAttribute("id")
                  );
                }
              }
            });
          }
        }

        // Float comments column.
        this.floatComments(floatText, selectedBlockID);
      }
      
      const activityCentreElements = document.getElementsByClassName("js-activity-centre");
      for (let i = 0; i < activityCentreElements.length; i++) {
        const userDataRows = activityCentreElements[i].getElementsByClassName("user-data-row");
        for (let j = 0; j < userDataRows.length; j++) {
          userDataRows[j].classList.remove("active");
        }
      }
      const eventShowHideComments = new CustomEvent("showHideComments");
      document.dispatchEvent(eventShowHideComments);
    }

    /**
     * Floats the comments for the selected text within a block.
     *
     * This function is responsible for handling the display of comments associated with the selected text in a block. It performs the following tasks:
     * - Finds the relevant comment elements within the selected block and checks if they match the selected text.
     * - Removes the "focus", "is-open", "onGoing", and sets the opacity to 0.2 for all elements with the class "cls-board-outer".
     * - Removes the "focus" class from various comment-related icons within the "cf-wrapperblock__suggestion" elements.
     * - Hides the "comment-delete-overlay" and "btn-wrapper" elements if the post is not in real-time mode.
     * - Unchecks the "resolve-cb" checkbox in the "cf-comment-board-wrapper" element.
     * - Removes the "sg-format-class" class from the relevant comment spans.
     * - Handles the display and positioning of the comment elements based on whether there is a single or multiple selected texts.
     * - Scrolls the board to the position of the selected text(s).
     *
     * @param {Array<string>} selectedText - An array of IDs or "datatext" attributes of the selected text elements.
     * @param {?string} blockId - The ID of the selected block, or null if not provided.
     */
    floatComments(selectedText, blockId = null) {

      // Sort the selectedText array based on the 'el' prefix to display comment at first position.
      selectedText?.sort((a, b) => {
        if (a.startsWith('el') && !b.startsWith('el')) {
          return -1; // 'a' should come first
        }
        if (!a.startsWith('el') && b.startsWith('el')) {
          return 1; // 'b' should come first
        }
        return 0; // Keep the order of elements that both start or don't start with 'el'
      });
      
      //const selectedBlock = select("core/block-editor").getSelectedBlock();
      const iframe = cfGetIframe();
      const iframeDocument = iframe ? iframe.contentWindow.document : null;
      
      const getCFBoard = document.getElementById('cf-comments-suggestions-parent');
      if (getCFBoard && selectedText.length > 0) {
        // Reset all comments suggestions on the first iteration
        document.getElementById("cf-comment-board-wrapper")?.classList.remove("cf-unset-all");
        getCFBoard.querySelectorAll('.cls-board-outer').forEach(element => {
          element.classList.remove("focus", "is-open", "onGoing");
//          element.style.opacity = "0.2";
          element.style.top = '';
          const shareCommentContainer = element.querySelector('.shareCommentContainer');
          if (shareCommentContainer) {
              shareCommentContainer.removeAttribute("style");
          }
        });
      }
      let boardOuterHeight = 0;
      let topOfTextFirstBoard;
      // Remove duplicate values from selectedText array
      const uniqueSelectedText = [...new Set(selectedText)];
      // Loop through the unique selected text and process each board ID      
      uniqueSelectedText.forEach((singleBoardId, i) => {
        if (singleBoardId === undefined) return;
    
        const { singleBoardIdSuggestion, singleBoardIdComment, combineBoardId } = getBoardIds(singleBoardId);
        const elementcombineBoardId = document.getElementById(combineBoardId);
        // Apply styles and classes
        if (elementcombineBoardId) {
          elementcombineBoardId.parentElement.classList.add("cf-unset-all");
          //elementcombineBoardId.style.opacity = "1";
          elementcombineBoardId.classList.add("onGoing", "is-open");
          if( i === 0 ) {
            elementcombineBoardId.classList.add("focus");
          }

          let referenceElement = iframeDocument 
            ? (singleBoardId.match(/^el/m) === null 
                ? iframeDocument.getElementById(singleBoardId) 
                : iframeDocument.querySelector(`[datatext="${combineBoardId}"]`)) 
            : (singleBoardId.match(/^el/m) === null 
                ? document.getElementById(singleBoardId) 
                : document.querySelector(`[datatext="${combineBoardId}"]`));

          // Add the 'data-rich-text-format-boundary' attribute with value 'true'
          if (referenceElement) {
            referenceElement.dataset.richTextFormatBoundary = 'true';
          }

          let topOfTextSingleBoard;
          let singleBoardIdWithSg;

          if (iframeDocument) {
            // Inside the iframe
            if (singleBoardId.match(/^el/m) === null) {
              topOfTextSingleBoard = referenceElement ? referenceElement.getBoundingClientRect().top : 0;
              singleBoardIdWithSg = "sg" + singleBoardId;
              
              const cfElement = iframeDocument.getElementById(`cf-sg${singleBoardId}`);
              if (cfElement) {
                cfElement.classList.add("active");
              }
            } else {
              topOfTextSingleBoard = referenceElement ? referenceElement.getBoundingClientRect().top : 0;
              singleBoardIdWithSg = singleBoardId;
            }

            if(0 == i){
              topOfTextFirstBoard = topOfTextSingleBoard;
            }

            topOfTextSingleBoard = topOfTextFirstBoard + boardOuterHeight + 60;

            jQuery("#" + singleBoardIdWithSg).offset({
              top: topOfTextSingleBoard,
            });
            boardOuterHeight = boardOuterHeight + document.querySelector("#" + singleBoardIdWithSg)?.offsetHeight + 20 ;
          } else {
            if (singleBoardId.match(/^el/m) === null) {
              topOfTextSingleBoard = referenceElement ? referenceElement.getBoundingClientRect().top : 0;
              singleBoardIdWithSg = "sg" + singleBoardId;
              
              const cfElement = document.getElementById(`cf-sg${singleBoardId}`);
              if (cfElement) {
                cfElement.classList.add("active");
              }
            } else {
              topOfTextSingleBoard = referenceElement ? referenceElement.getBoundingClientRect().top : 0;
              singleBoardIdWithSg = singleBoardId;
            }

            if(0 == i){
              topOfTextFirstBoard = topOfTextSingleBoard;
            }

            topOfTextSingleBoard = topOfTextFirstBoard + boardOuterHeight;

            jQuery("#" + singleBoardIdWithSg).offset({
              top: topOfTextSingleBoard,
            });
            boardOuterHeight = boardOuterHeight + document.querySelector("#" + singleBoardIdWithSg)?.offsetHeight + 20 ;
          }
        }
      });    
    }

    /**
     * Lifecycle method that is called when the component is first mounted.
     * It retrieves the current value of the '_sb_is_suggestion_mode' meta field
     * from the post being edited and stores it in the component's state.
     */
    componentDidMount() {
      const suggestionToggle = select("core/editor").getEditedPostAttribute("meta")?._sb_is_suggestion_mode;
      this.setState({ suggestionToggle });
    }

    /**
     * Lifecycle method that is called when the component's props or state change.
     * It checks if the `datatext` prop has changed, and if so, it dispatches an action to clear the `datatext` value in the `mdstore`.
     * It also checks if the `suggestionToggle` state has changed, and if so, it dispatches an action to update the `_sb_is_suggestion_mode` meta field of the post being edited.
     *
     * @param {object} prevProps - The previous props of the component.
     * @param {object} prevState - The previous state of the component.
     */
    componentDidUpdate(prevProps, prevState) {
      if (this.props.activeAttributes.datatext !== prevProps.activeAttributes.datatext) {
        dispatch("mdstore").setDataText("");
      }
      if (prevState.suggestionToggle !== this.state.suggestionToggle) {
        dispatch("core/editor").editPost({ meta: { _sb_is_suggestion_mode: this.state.suggestionToggle } });
      }
    }

    /**
     * Renders the comment button and rich text shortcut for the current block.
     *
     * This component is responsible for rendering the comment button and rich text shortcut
     * based on the current block's properties and user capabilities. It checks various conditions
     * to determine whether the comment button and shortcut should be displayed.
     */
    render() {
      const { isActive, value } = this.props;
      const { text, start, end } = value;
      const isTemplate = select('core/editor').getCurrentPostType();
      const isEditingTemplate = isTemplate === 'wp_template';
      const block = select("core/block-editor").getSelectedBlock();
      let focusedElement;
      let isRichClassExist;
      const iframe = cfGetIframe();
      const iframeDocument = iframe?.contentDocument;
      if(iframeDocument){
        focusedElement = iframeDocument.activeElement.localName;
        isRichClassExist = iframeDocument.activeElement.classList.contains("rich-text");
      } else {
        focusedElement = document.activeElement.localName;
        isRichClassExist = document.activeElement.classList.contains("rich-text");
      }
      // Hide toolbar button for non-text elements
      if ("figcaption" === focusedElement || (isRichClassExist && start === end)) {
        const nonTextButtons = document.getElementsByClassName('toolbar-button-with-nontext');
        for (let i = 0; i < nonTextButtons.length; i++) {
          const parent = nonTextButtons[i].parentElement;
          if (parent) {
            parent.style.padding = '0';
            parent.style.borderRight = 'none';
          }
          nonTextButtons[i].style.display = 'none';
        }
      }
  
      const renderToolbarButton = (onClickHandler) => (
        <BlockControls>
          <ToolbarGroup className="comment-group">
            <ToolbarButton
              icon="admin-comments"
              isActive={isActive}
              label={__("Comment", "commenting-feature")}
              onClick={onClickHandler}
              shortcut={displayShortcut.primaryAlt("m")}
              className={`comment-group-button toolbar-button-with-text toolbar-button__${name}`}
            />
          </ToolbarGroup>
        </BlockControls>
      );
      const renderRichTextShortcut = () => (
        <RichTextShortcut type="primaryAlt" character="m" onUse={this.onApply} />
      );
  
      const renderCommentButton = () => (
        <Fragment>
          {start === end && !allowedBlocks.media.includes(block?.name) && undefined !== start && undefined !== end && "figcaption" !== focusedElement && !isEditingTemplate && (  
            <Fragment>
              {renderToolbarButton(NonTextComment.onToggleNonTextBlock)}
            </Fragment>
          )}
          {((allowedBlocks.text.includes(block?.name) && start !== end) || "figcaption" === focusedElement) &&  !isEditingTemplate && (
            <Fragment>
              {renderRichTextShortcut()}
              {renderToolbarButton(this.onToggle)}
            </Fragment>
          )}
        </Fragment>
      );
  
      return (
        <Fragment>
          {renderCommentButton()}
          {!isEditingTemplate && ( 
            <Fragment>{this.getSelectedText()}</Fragment>
          )}
        </Fragment>
      );
    }
  },
};