将光标(插入符号)放在<pre> contenteditable element

时间:2017-08-30 20:02:40

标签: javascript html

I'm making a web application to test regular expressions. I have an input where I enter the regexp and a contenteditable pre element where I enter the text where the matches are found and highlighted.

Example: asuming the regexp is ab, if the user types abcab in the pre element, both regexp and text are sent to an api I implemented which returns

    <span style='background-color: lightgreen'>ab</span>c<span style='background-color: lightgreen'>ab</span>

and this string is set as the innerHTML of the pre element

This operation is made each time the user edites the content of the pre element (keyup event to be exact). The problem I have (and I hope you can solve) is that each time the innterHTML is set, the caret is placed at the beginning, and I want it to be placed right after the last character input by de user. Any suggestions on how to know where the caret is placed and how to place it in a desired position? Thanks.

UPDATE For better understanding...A clear case: Regexp is ab and in the contenteditable element we have:

    <span style='background-color: lightgreen'>ab</span>c<span style='background-color: lightgreen'>ab</span>

Then I type a c between the first a and the first b, so now we have:

    <span style='background-color: lightgreen'>ab</span>c<span style='background-color: lightgreen'>ab</span>

At this moment the caret has returned to the beginning of the contenteditable element, and it should be placed right after the c I typed. That's what I want to achieve, hope now it's more clear.

UPDATE2

    <span style='background-color: lightgreen'>ab</span>c<span style='background-color: lightgreen'>ab</span>
    acbc<span style='background-color: lightgreen'>ab</span>

3 个答案:

答案 0 :(得分:0)

CD: C:\Users\TBMEPYG\AppData\Local\Continuum\Anaconda3
Current directory: C:\Users\TBMEPYG\AppData\Local\Continuum\Anaconda3
python "C:\Users\TBMEPYG\Desktop\vamo.py"
Process started >>>
Traceback (most recent call last):
  File "C:\Users\TBMEPYG\Desktop\vamo.py", line 8, in <module>
    data = driver.find_element_by_name('Dt_Ref')
  File "C:\Users\TBMEPYG\AppData\Local\Continuum\Anaconda3\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 426, in find_element_by_name
    return self.find_element(by=By.NAME, value=name)
  File "C:\Users\TBMEPYG\AppData\Local\Continuum\Anaconda3\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 832, in find_element
    'value': value})['value']
  File "C:\Users\TBMEPYG\AppData\Local\Continuum\Anaconda3\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 297, in execute
    self.error_handler.check_response(response)
  File "C:\Users\TBMEPYG\AppData\Local\Continuum\Anaconda3\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 194, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: {"errorMessage":"Unable to find element with name 'Dt_Ref'","request":{"headers":{"Accept":"application/json","Accept-Encoding":"identity","Connection":"close","Content-Length":"89","Content-Type":"application/json;charset=UTF-8","Host":"127.0.0.1:62040","User-Agent":"Python http auth"},"httpVersion":"1.1","method":"POST","post":"{\"using\": \"name\", \"value\": \"Dt_Ref\", \"sessionId\": \"bdd3fc70-8dd0-11e7-aeb1-85b8cfbe0d1c\"}","url":"/element","urlParsed":{"anchor":"","query":"","file":"element","directory":"/","path":"/element","relative":"/element","port":"","host":"","password":"","user":"","userInfo":"","authority":"","protocol":"","source":"/element","queryKey":{},"chunks":["element"]},"urlOriginal":"/session/bdd3fc70-8dd0-11e7-aeb1-85b8cfbe0d1c/element"}}
Screenshot: available via screen

I quickly made this and it places the cursor at the end of the string in the input box. The onclick is for when the user manually clicks on the input and the onfocus is for when the user tabs on the input.

from selenium import webdriver

path_phantom = 'C:\\Users\\TBMEPYG\\AppData\\Local\\Continuum\\Anaconda3\\Lib\\site-packages\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe'
driver = webdriver.PhantomJS(executable_path= path_phantom)
driver.get('http://www.anbima.com.br/reune/reune.asp')


data = driver.find_element_by_name('Dt_Ref')
data.clear()
data.send_keys('21/08/2017')

答案 1 :(得分:0)

Here to make selection easy, I've added another pip install GoogleMaps tag with nothing in it, and given it a C:\Users\NA401134>pip install GoogleMaps Collecting GoogleMaps Using cached googlemaps-2.5.1.tar.gz Complete output from command python setup.py egg_info: warning: no files found matching 'NOTICE' Installed c:\users\na401134\appdata\local\temp\pip-build-y5t07ucg\googlemaps\.eggs\requests-2.18.4-py3.5.egg Searching for certifi>=2017.4.17 Reading https://pypi.python.org/simple/certifi/ Best match: certifi 2017.7.27.1 Downloading https://pypi.python.org/packages/20/d0/3f7a84b0c5b89e94abbd073a5f00c7176089f526edb056686751d5064cbd/certifi-2017.7.27.1.tar.gz#md5=48e8370da8b370a16e223ee9c7b6b063 Processing certifi-2017.7.27.1.tar.gz Writing C:\Users\NA401134\AppData\Local\Temp\easy_install-ttda9z_e\certifi-2017.7.27.1\setup.cfg Running certifi-2017.7.27.1\setup.py -q bdist_egg --dist-dir C:\Users\NA401134\AppData\Local\Temp\easy_install-ttda9z_e\certifi-2017.7.27.1\egg-dist-tmp-k3p_29q4 creating c:\users\na401134\appdata\local\temp\pip-build-y5t07ucg\googlemaps\.eggs\certifi-2017.7.27.1-py3.5.egg Extracting certifi-2017.7.27.1-py3.5.egg to c:\users\na401134\appdata\local\temp\pip-build-y5t07ucg\googlemaps\.eggs Installed c:\users\na401134\appdata\local\temp\pip-build-y5t07ucg\googlemaps\.eggs\certifi-2017.7.27.1-py3.5.egg Searching for urllib3<1.23,>=1.21.1 Reading https://pypi.python.org/simple/urllib3/ Best match: urllib3 1.22 Downloading https://pypi.python.org/packages/ee/11/7c59620aceedcc1ef65e156cc5ce5a24ef87be4107c2b74458464e437a5d/urllib3-1.22.tar.gz#md5=0da7bed3fe94bf7dc59ae37885cc72f7 Processing urllib3-1.22.tar.gz Writing C:\Users\NA401134\AppData\Local\Temp\easy_install-n_pau25n\urllib3-1.22\setup.cfg Running urllib3-1.22\setup.py -q bdist_egg --dist-dir C:\Users\NA401134\AppData\Local\Temp\easy_install-n_pau25n\urllib3-1.22\egg-dist-tmp-on1foee6 c:\anaconda\lib\site-packages\setuptools-23.0.0-py3.5.egg\setuptools\dist.py:285: UserWarning: Normalizing '2017.07.27.1' to '2017.7.27.1' warning: no previously-included files matching '*' found under directory 'docs\_build' zip_safe flag not set; analyzing archive contents... urllib3.packages.__pycache__.six.cpython-35: module references __path__ creating c:\users\na401134\appdata\local\temp\pip-build-y5t07ucg\googlemaps\.eggs\urllib3-1.22-py3.5.egg Extracting urllib3-1.22-py3.5.egg to c:\users\na401134\appdata\local\temp\pip-build-y5t07ucg\googlemaps\.eggs Installed c:\users\na401134\appdata\local\temp\pip-build-y5t07ucg\googlemaps\.eggs\urllib3-1.22-py3.5.egg Traceback (most recent call last): File "<string>", line 1, in <module> File "C:\Users\NA401134\AppData\Local\Temp\pip-build-y5t07ucg\GoogleMaps\setup.py", line 39, in <module> 'Topic :: Internet', File "c:\anaconda\lib\distutils\core.py", line 108, in setup _setup_distribution = dist = klass(attrs) File "c:\anaconda\lib\site-packages\setuptools-23.0.0-py3.5.egg\setuptools\dist.py", line 269, in __init__ File "c:\anaconda\lib\site-packages\setuptools-23.0.0-py3.5.egg\setuptools\dist.py", line 313, in fetch_build_eggs File "c:\anaconda\lib\site-packages\setuptools-23.0.0-py3.5.egg\pkg_resources\__init__.py", line 826, in resolve File "c:\anaconda\lib\site-packages\setuptools-23.0.0-py3.5.egg\pkg_resources\__init__.py", line 1085, in best_match File "c:\anaconda\lib\site-packages\setuptools-23.0.0-py3.5.egg\pkg_resources\__init__.py", line 695, in find pkg_resources.VersionConflict: (idna 2.1 (c:\anaconda\lib\site-packages), Requirement.parse('idna<2.7,>=2.5')) ---------------------------------------- Command "python setup.py egg_info" failed with error code 1 in C:\Users\NA401134\AppData\Local\Temp\pip-build-y5t07ucg\GoogleMaps\ attribute to make it easy to select.

I then simply create a range from this and use window.getSelection addRange to apply it.

Update: modified to place caret after the first C:\Users\NA401134>pip freeze alabaster==0.7.8 anaconda-client==1.4.0 anaconda-navigator==1.2.1 argcomplete==1.0.0 astropy==1.2.1 Babel==2.3.3 backports.shutil-get-terminal-size==1.0.0 beautifulsoup4==4.4.1 bitarray==0.8.1 blaze==0.10.1 bokeh==0.12.0 boto==2.40.0 Bottleneck==1.1.0 cffi==1.6.0 chest==0.2.3 click==6.6 cloudpickle==0.2.1 clyent==1.2.2 colorama==0.3.7 comtypes==1.1.2 conda==4.1.6 conda-build==1.21.3 conda-env==2.5.0a0 configobj==5.0.6 contextlib2==0.5.3 cryptography==1.4 cycler==0.10.0 Cython==0.24 cytoolz==0.8.0 dask==0.10.0 datashape==0.5.2 decorator==4.0.10 dill==0.2.5 docutils==0.12 dynd===c328ab7 et-xmlfile==1.0.1 fastcache==1.0.2 Flask==0.11.1 Flask-Cors==2.1.2 gevent==1.1.1 greenlet==0.4.10 h5py==2.6.0 HeapDict==1.0.0 idna==2.1 imagesize==0.7.1 ipykernel==4.3.1 ipython==4.2.0 ipython-genutils==0.1.0 ipywidgets==4.1.1 itsdangerous==0.24 jdcal==1.2 jedi==0.9.0 Jinja2==2.8 jsonschema==2.5.1 jupyter==1.0.0 jupyter-client==4.3.0 jupyter-console==4.1.1 jupyter-core==4.1.0 llvmlite==0.11.0 locket==0.2.0 lxml==3.6.0 MarkupSafe==0.23 matplotlib==1.5.1 menuinst==1.4.1 mistune==0.7.2 mpmath==0.19 multipledispatch==0.4.8 nb-anacondacloud==1.1.0 nb-conda==1.1.0 nb-conda-kernels==1.0.3 nbconvert==4.2.0 nbformat==4.0.1 nbpresent==3.0.2 networkx==1.11 nltk==3.2.1 nose==1.3.7 notebook==4.2.1 numba==0.26.0 numexpr==2.6.0 numpy==1.11.1 odo==0.5.0 openpyxl==2.3.2 pandas==0.18.1 partd==0.3.4 path.py==0.0.0 pathlib2==2.1.0 patsy==0.4.1 pep8==1.7.0 pickleshare==0.7.2 Pillow==3.2.0 ply==3.8 psutil==4.3.0 py==1.4.31 pyasn1==0.1.9 pycosat==0.6.1 pycparser==2.14 pycrypto==2.6.1 pycurl==7.43.0 pyflakes==1.2.3 Pygments==2.1.3 pyOpenSSL==16.0.0 pyparsing==2.1.4 pyreadline==2.1 pytest==2.9.2 python-dateutil==2.5.3 pytz==2016.4 pywin32==220 PyYAML==3.11 pyzmq==15.2.0 qtconsole==4.2.1 QtPy==1.0.2 requests==2.10.0 rope-py3k==0.9.4.post1 ruamel-yaml===-VERSION scikit-image==0.12.3 scikit-learn==0.17.1 scipy==0.17.1 simplegeneric==0.8.1 singledispatch==3.4.0.3 six==1.10.0 snowballstemmer==1.2.1 sockjs-tornado==1.0.3 Sphinx==1.3.1 sphinx-rtd-theme==0.1.9 spyder==2.3.9 SQLAlchemy==1.0.13 statsmodels==0.6.1 sympy==1.0 tables==3.2.2 toolz==0.8.0 tornado==4.3 traitlets==4.2.1 unicodecsv==0.14.1 Werkzeug==0.11.10 xlrd==1.0.0 XlsxWriter==0.9.2 xlwings==0.7.2 xlwt==1.1.2

span
data-end

答案 2 :(得分:0)

从这里获得这些功能的帮助 - &gt;

Add element before/after text selection

我创造了一些我认为你追求的东西。 我基本上将一些临时标签放在当前光标所在的html中。然后我渲染新的HTML,然后用带有data-cpos属性的span替换标记。使用此我然后重新选择光标。

var insertHtmlBeforeSelection, insertHtmlAfterSelection;

(function() {
    function createInserter(isBefore) {
        return function(html) {
            var sel, range, node;
            if (window.getSelection) {
                // IE9 and non-IE
                sel = window.getSelection();
                if (sel.getRangeAt && sel.rangeCount) {
                    range = window.getSelection().getRangeAt(0);
                    
                    range.collapse(isBefore);
        
                    // Range.createContextualFragment() would be useful here but is
                    // non-standard and not supported in all browsers (IE9, for one)
                    var el = document.createElement("div");
                    el.innerHTML = html;
                    var frag = document.createDocumentFragment(), node, lastNode;
                    while ( (node = el.firstChild) ) {
                        lastNode = frag.appendChild(node);
                    }
                    range.insertNode(frag);
                }
            } else if (document.selection && document.selection.createRange) {
                // IE < 9
                range = document.selection.createRange();
                range.collapse(isBefore);
                range.pasteHTML(html);
            }
        }
    }
    
    insertHtmlBeforeSelection = createInserter(true);
    insertHtmlAfterSelection = createInserter(false);
})();




function refreshInnerHtml() {
  var
    tag_start = '⇷',  //lets use some unicode chars unlikely to ever use..
    tag_end = '⇸',
    sel = document.getSelection(),
    input = document.getElementById('textInput');
   
  //remove old data-cpos
  [].forEach.call(
    input.querySelectorAll('[data-cpos]'),
    function(e) { e.remove() });
  
  //insert the tags at current cursor position
  insertHtmlBeforeSelection(tag_start);
  insertHtmlAfterSelection(tag_end);
  
  //now do our replace
  let html = input.innerText.replace(/(ab)/g, '<span style="background-color: lightgreen">$1</span>');
  input.innerHTML = html.replace(tag_start,'<span data-cpos>').replace(tag_end,'</span>');
  
  //now put cursor back 
  var e = input.querySelector('[data-cpos]');
  if (e) {
    var range = document.createRange();
    range.setStart(e, 0);
    range.setEnd(e, 0);
    sel.removeAllRanges();
    sel.addRange(range);  
  }
}

refreshInnerHtml();
Type some text below, with the letters 'ab' somewhere within it. <br>

<pre contenteditable onkeyup="refreshInnerHtml()" id="textInput" style="border: 1px solid black;" >It's about time.. above and beyond</pre>

相关问题