在textarea中选择多个单独的区域?

时间:2019-02-14 16:02:29

标签: javascript jquery html

我对编码还很陌生,并且一直在使用textarea创建一个文本编辑器组件:https://jsfiddle.net/chrismg12/jLk70ar3/5/

我打算创建一个函数,用于选择找到的单词的所有实例。但是,我不知道如何在textarea中执行此操作。注意:这不是关于多个插入符号,而是多个选择,但是在实现多个插入符号的建议中将不胜感激。
HTML

var lNo = "";

function injectStyles(rule) {
  var div = $("<div />", {
    html: '&shy;<style>' + rule + '</style>'
  }).appendTo("body");
}

$.fn.selectRange = function(start, end) {
  return this.each(function() {
    if (typeof end == "undefined") {
      end = start;
    }
    if (start == -1) {
      start = this.value.length;
    }
    if (end == -1) {
      end = this.value.length;
    }
    if (this.setSelectionRange) {
      this.focus();
      this.setSelectionRange(start, end + 1);
    } else if (this.createTextRange) {
      var range = this.createTextRange();
      range.collapse(true);
      range.moveEnd('character', end);
      range.moveStart('character', start);
      range.select();
    }
  });
};

$.fn.selectRangeExcludingLast = function(start, end) {
  return this.each(function() {
    if (typeof end == "undefined") {
      end = start;
    }
    if (start == -1) {
      start = this.value.length;
    }
    if (end == -1) {
      end = this.value.length;
    }
    if (this.setSelectionRange) {
      this.focus();
      this.setSelectionRange(start, end + 1);
    } else if (this.createTextRange) {
      var range = this.createTextRange();
      range.collapse(true);
      range.moveEnd('character', end);
      range.moveStart('character', start);
      range.select();
    }
  });
};

function getPos(str, substr, index) {
  var io = str.split(substr, index).join(substr).length;
  if (io >= str.length) {
    return -1;
  } else {
    return io;
  }
}

function gutterChildControl(gutter, textarea, settings) {
  if (gutter.childNodes.length != $(textarea).val().split("\n").length) {
    while (gutter.childNodes.length < $(textarea).val().split("\n").length) {
      var gutterChild = document.createElement("div");
      gutterChild.className = "gutterChild"
      gutterChild.style.height = $(textarea).css('line-height');
      var gutterChildLineHeight = $(textarea).css('line-height');
      $(gutterChild).css('line-height', gutterChildLineHeight)
      gutterChild.style.fontSize = $(textarea).css('font-size');
      gutterChild.style.width = "100%";
      gutterChild.style.color = settings.gFontCol;
      gutterChild.style.paddingRight = `${settings.gPadding}px`;
      gutterChild.style.paddingLeft = `${settings.gPadding}px`;
      gutterChild.style.textAlign = settings.gFontAlign;
      gutterChild.onmouseover = function() {
        gutterChild.style.opacity = "0.75"
      }
      gutterChild.onmouseleave = function() {
        gutterChild.style.opacity = "1"
      }
      gutterChild.onclick = function() {
        if (parseInt(gutterChild.innerHTML) != 1) {
          startPos = getPos($(textarea).val(), "\n", parseInt(gutterChild.innerHTML) - 1)
          console.log(`startPos:${startPos}`);
          endPos = getPos($(textarea).val(), "\n", parseInt(gutterChild.innerHTML))
          if (endPos == -1) {
            endPos = $(textarea).val().length - 1
          }
          console.log(`endPos:${endPos}`)
          $(textarea).selectRange(startPos, endPos);
        } else {
          startPos = 0;
          console.log(`startPos:${startPos}`)
          endPos = getPos($(textarea).val(), "\n", 1)
          if (endPos == -1) {
            endPos = $(textarea).val().length - 1
            if (endPos == -1) {
              endPos = 0;
            }
          }
          console.log(`endPos:${endPos}`)
          $(textarea).selectRange(startPos, endPos);
        }
      }

      gutter.appendChild(gutterChild);
      gutterChild.innerHTML = `${gutter.childNodes.length}`
    }
    while (gutter.childNodes.length > $(textarea).val().split("\n").length) {
      gutter.removeChild(gutter.lastChild)
    }
    // while(gutter.childNodes.length > $(textarea).val().split("\n").length){
    //  gutter.childNodes.pop;
    // }
  }
}

function Ventify(element, options) {
  const settings = {
    taCol: "#1d252c",
    gCol: "#1d252c",
    fSize: "22px",
    gFontCol: "rgba(58,74,88,1)",
    pad: 1,
    gFontAlign: "center",
    gPadding: 20,
    ...options
  }
  element.style.display = "flex";
  element.style.flexDirection = "row";
  var gutter = document.createElement("div");
  var textarea = document.createElement("textarea");
  gutter.className = "gutter";
  gutter.classList.add("scrll")
  textarea.className = "ventiEditor";
  textarea.classList.add("scrll")

  gutter.style.width = "100px";
  gutter.style.height = "100%";
  gutter.style.backgroundColor = settings.gCol;
  gutter.style.overflowY = "scroll"
  gutter.style.scrollbarWidth = "none";
  injectStyles(".gutter::-webkit-scrollbar{width:0px;}")
  injectStyles(".ventiEditor{outline:0px !important;-webkit-appearance:none;}")

  textarea.style.width = "calc(100% - 100px)";
  textarea.style.fontSize = settings.fSize;
  textarea.style.color = settings.gFontCol;
  textarea.style.overflowY = "scroll";
  textarea.style.whiteSpace = "pre";
  textarea.style.resize = "none";
  textarea.style.height = "100%";
  textarea.style.margin = "0px 0px 0px 0px"
  textarea.style.border = "0px solid rgb(255,255,255)"
  textarea.style.padding = "0"
  $(textarea).css('line-height', `calc(${2*settings.pad}px + ${settings.fSize})`)
  textarea.style.backgroundColor = settings.taCol;
  textarea.spellcheck = false;
  $(textarea).css("-moz-tab-size", "4");
  $(textarea).css("tab-size", "4")
  $('.ventiEditor:focus').css('outline', '0px !important')
  $('.ventiEditor:focus').css('-webkit-appearance', 'none')
  textarea.oninput = function() {
    var gutter = textarea.parentElement.childNodes[0];
    gutterChildControl(gutter, textarea, settings)
  };
  textarea.onscroll = function() {
    gutter.scrollTop = textarea.scrollTop
  }
  $(textarea).keydown(function(e1) {
    if (e1.ctrlKey) {
      if (e1.keyCode >= 48 && e1.keyCode <= 57) {
        lNo += e1.key;
        console.log(lNo);
      }
    }
  })
  // gutter.onscroll = function(){
  //  if(gutter.scrollTop != textarea.scrollTop){
  //      textarea.scrollTop = gutter.scrollTop;
  //  }
  // }
  element.appendChild(gutter);
  element.appendChild(textarea);
  gutterChildControl(gutter, textarea, settings);
}

function gutterFix(textarea) {}

$(document).delegate('.ventiEditor', 'keydown', function(e) {
  var keyCode = e.keyCode || e.which;

  if (keyCode == 9) {
    e.preventDefault();
    var start = this.selectionStart;
    var end = this.selectionEnd;

    // set textarea value to: text before caret + tab + text after caret
    $(this).val($(this).val().substring(0, start) +
      "\t" +
      $(this).val().substring(end));

    // put caret at right position again
    this.selectionStart =
      this.selectionEnd = start + 1;
  }
});

injectStyles(".gutterChild{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}")
Ventify(document.getElementsByClassName("container")[0], {
  taCol: "#1d252c",
  gCol: "#1d252c",
  pad: 5,
  gFontCol: '#bbb'
})
html,
body {
  height: 100%;
  margin: 0px 0px 0px 0px;
}

.container {
  height: 100%;
}
<link rel="stylesheet" href="bootstrap-4.3.1-dist/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container"></div>

1 个答案:

答案 0 :(得分:0)

您可以设置一个空数组并将所有匹配字符串的位置推入其中。 (例如,如果要在字符串“ this”中查找“ this and this match; so does this”,则数组将得到[0,9,29]。)您可能希望/需要使用{{3} }

利用此信息(并知道子字符串的长度),您可以执行以下操作:
 -在文本区域上覆盖div(也许使用regexz-index: 1
 -将每个匹配的字符串括在span元素中(有关该contenteditable="true"的更多信息),并可能给所有这些spans一个类,  -使用querySelectorAll获取包含所有这些范围的NodeList,并且
 -遍历列表以更改其样式(因此    用户可以看到“选择的内容”)及其内容(假设该点是    以便用户可以进行更改。)

您可以稍后删除环绕间距,用更新后的文本更新文本区域,并删除覆盖的div。
请注意,索引数组可能不会长期有效,并且根据您对初始列表的处理方式,您可能需要向后循环遍历以保护这些值,直到不再需要它们为止。

那还是我的脑力激荡。