TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Creating an Editable Textarea That Supports Syntax-Highlighted Code (2021)

14 pointsby cheeaunover 2 years ago

2 comments

_boffin_over 2 years ago
Brilliant and excellent write up.
retrofxover 2 years ago
But what is the real problem ? (getting editing and feedback in a simple way)<p>Textarea or contenteditable provide support for editing, but not for syntax highliting or fancy functions - or to have them, the usual is to write all needed for editing from the ground - because it&#x27;s not possible to control content of editable in other way than by operating ranges of selection (like startOfsset and endOffset, regarding to startContainer and endContainer - and if they are equal, that&#x27;s the cursor).<p>But it&#x27;s very convinient to get both: contenteditable and syntax just by aligning precisely one over another, then get rid of few corner cases - as you can see below.<p>I made it once in Firefox 23+- in very minimal way. I applied it by userContent.css with <i>@-moz-document regexp(&quot;^.*#?\\.(css|js|jsm)$&quot;) { .. }</i>, it was working with <i>view-source:</i> as well, without making any changes to the original document (half transparent anonymous content over it), very little was needed to keep it in sync (or to have a handy feature to highligt same words as under cursor when Ctrl key is pressed) and.. you could just save the document after editing.<p><pre><code> @-moz-document regexp(&quot;^.\*#?\\.(css|js|jsm)$&quot;) { html&gt;body&gt;pre { -moz-binding: url(hilite.xml#hilite) !important; } div { position:absolute; pointer-events:none; } div, pre, span{ white-space:pre !important; background:transparent; .. } ::-moz-selection { background: #d0e0d0 !important;} } </code></pre> - - -<p><pre><code> &lt;binding id=&quot;hilite&quot; bindToUntrustedContent=&quot;true&quot;&gt; &lt;content &gt;&lt;xht:div&gt; &lt;&#x2F;xht:div &gt;&lt;children &#x2F;&gt;&lt;&#x2F;content&gt; &lt;implementation&gt;&lt;constructor&gt;&lt;![CDATA[ .. &#x2F;&#x2F; &quot;http:&#x2F;&#x2F;softwaremaniacs.org&#x2F;soft&#x2F;highlight&#x2F;en&#x2F;&quot;, version: 7.3.0 .. this.sync =function(){ var t=this.replace(&#x2F;&lt;br&gt;&#x2F;g,&#x27;\n&#x27;).replace(&#x2F;&amp;nbsp;&#x2F;g,&#x27; &#x27;).replace(&#x2F;&amp;lt;&#x2F;g,&#x27;&lt;&lt;&gt;&#x27;) .replace(&#x2F;&amp;gt;&#x2F;g,&#x27;&lt;&gt;&gt;&#x27;).replace(&#x2F;&amp;amp;&#x2F;g,&#x27;&lt;&amp;&gt;&#x27;); t=hilite(t, this.word).replace(&#x2F;&lt;&lt;&gt;&#x2F;g,&#x27;&lt;span&gt;&lt;&lt;&#x2F;span&gt;&#x27;) .replace(&#x2F;&lt;&gt;&gt;&#x2F;g,&#x27;&lt;span&gt;&gt;&lt;&#x2F;span&gt;&#x27;).replace(&#x2F;&lt;&amp;&gt;&#x2F;g,&#x27;&lt;span&gt;&amp;&lt;&#x2F;span&gt;&#x27;) this.e0.innerHTML= t; }; this.keydownt = function(e){ &#x2F;&#x2F; filtering keycodes if ((e.keyCode == 9)&amp;&amp;(!e.ctrlKey)){ document.execCommand(&#x27;insertHTML&#x27;,false,&#x27;\t&#x27;); e.preventDefault(); } .. } &#x2F;&#x2F;tab this.keydownf = function(e){ if(e.ctrlKey) getWord(); setTimeout(function() {sync();}, 0); .. } setTimeout(function(){ document.body.setAttribute(&#x27;spellcheck&#x27;,&quot;false&quot;); this.contentEditable = true; this.e0=document.getAnonymousNodes(this)[0]; this.textContent=this.innerHTML.replace(&#x2F;&amp;nbsp;&#x2F;g,&#x27; &#x27;).replace(&#x2F;&amp;amp;&#x2F;g,&#x27;&amp;&#x27;) .replace(&#x2F;&amp;lt;&#x2F;g,&#x27;&lt;&#x27;).replace(&#x2F;&amp;gt;&#x2F;g,&#x27;&gt;&#x27;); sync(); this.focus(); }, 0, false); ]]&gt;&lt;&#x2F;constructor&gt;&lt;&#x2F;implementation&gt;&lt;&#x2F;binding&gt;&lt;&#x2F;bindings&gt; </code></pre> Orthogonally to that, I had userContent&#x2F;Chrome.css opened in the sidebar and on every key up I unregister and loadAndRegisterSheet with it :) (the styles were applied live to documents or browser when the sidebar was open and saved on unload).