public
Last active — forked from 140bytes/LICENSE.txt

insertTags in 140byt.es

  • Download Gist
LICENSE.txt
1 2 3 4 5 6 7 8 9 10 11 12 13
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
 
Copyright (C) 2011 Thiemo M├Ąttig <http://maettig.com>
 
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
 
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 
0. You just DO WHAT THE FUCK YOU WANT TO.
README.md
Markdown

We all know the little toolbar buttons to insert something into a textarea, like BBCode, Wiki markup or HTML tags (fun fact: GitHub doesn't have a toolbar). One of the resources I used once was this German site but there are many more. I was wondering, how much of this nifty, widespread code could be squished into 140 bytes.

Currently, this is 159 bytes and I'm looking for your help. One thing I could do is to remove a.focus(); and +b.length but doing so I will loose a major feature. I'm looking for other ways to make this smaller.

annotated.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13
function(a, b, c, d, e, f, g) //textarea, left and right tag
{
d = 'selection';
e = d + 'End';
d += 'Start';
a.focus(); //not really required but very helpful
f = a[e]; //get cursor position
g = a.value.split(''); //short replacement for substr
g[a[d] - 1] += b; //append both tags
g[f - 1] += c;
a.value = g.join(''); //set new text
a[e] = a[d] = f + b.length //set cursor position
}
package.json
JSON
1 2 3 4 5 6 7 8 9 10 11 12 13
{
"name": "insertTags",
 
"description": "Surrounds selected text in a textarea with tags, e.g. BBCode or Wikitext.",
 
"keywords": [
"bbcode",
"forms",
"tags",
"textarea",
"toolbar"
]
}
test.html
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
<!DOCTYPE html>
<button onclick="insertTags(a, &quot;'''&quot;, &quot;'''&quot;)">'''bold'''</button>
<button onclick="insertTags(a, &quot;''&quot;, &quot;''&quot;)">''italic''</button>
<button onclick="insertTags(a, '[[', ']]')">[[link]]</button><br>
<textarea cols="80" rows="20">Select a word and click a button.</textarea><br>
<script type="text/javascript">
var insertTags = function(a, b, c, d, e, f, g) //textarea, left and right tag
{
d = 'selection';
e = d + 'End';
d += 'Start';
a.focus(); //not really required but very helpful
f = a[e]; //get cursor position
g = a.value.split(''); //short replacement for substr
g[a[d] - 1] += b; //append both tags
g[f - 1] += c;
a.value = g.join(''); //set new text
a[e] = a[d] = f + b.length //set cursor position
}
var a = document.getElementsByTagName('TEXTAREA')[0];
</script>

Known bug: Because I'm using split and join instead of substr slice this fails for the first word in the textarea. But it saves 9 3 bytes.

Save one byte by using the focus(argument): a.focus(d='selection';e=d+'End';d+='Start').

Updated, thanks. Here is another idea to save 5 9 bytes, but this will replace the first occurrence of a selected substring instead of the selected one: g=a.value;a.value=g.replace(g=g.slice(a[d],f),b+g+c);.

I already thought of that, even tried to think up a clever idea with a replace s/(.{x})(.{y})(.{z})/$1b$2c$3/, but it was considerably longer than the original. Even using exec instead of replace doesn't help there.

I also tried to use a regular expression but it's, well, complicated. Here is the shortest solution I found so far: a.value=a.value.replace(RegExp('([\\s\\S]{'+a[d]+'})([\\s\\S]{'+(f-a[d])+'})'),'$1'+b+'$2'+c);. The most reliable solution is this, but it's 3 bytes longer than using split: g=a.value;a.value=g.slice(0,a[d])+b+g.slice(a[d],f)+c+g.slice(f);.

Eval makes this 4 bytes shorter: a.value=a.value.replace(eval('/([\s\S]{'+a[d]+'})([\s\S]{'+(f-a[d])+'})/'),'$1'+b+'$2'+c);

I found a reliable (does not work well when nothing is selected) but very short solution based on a regular expression. It works for all positions in the string including the first character. It's short but still to long (164 163 bytes).

function(a,b,c,d,e,f){a.focus(d='selection');e=d+'End';d+='Start';f=a[e];a.value=a.value.replace(/|/g,function(g,h){return a[d]-h?f-h?g:c:b});a[e]=a[d]=f+b.length}
// The following version also works when nothing is selected (168 bytes)
function(a,b,c,d,e,f){a.focus(d='selection');e=d+'End';d+='Start';f=a[e];a.value=a.value.replace(/|/g,function(g,h){return(a[d]-h?g:b)+(f-h?g:c)});a[e]=a[d]=f+b.length}

I thought about the possibility of function reusal for the replace callback...

I give up. The following version (132 bytes) does not care about setting the cursor position at all. But it works in all cases mentioned above (when the first character or nothing is selected). Anyway, new ideas are welcome.

function(a,b,c,d,e,f){a.focus(d='selection');e=a[d+'End'];d=a[d+'Start'];f=a.value;a.value=f.slice(0,d)+b+f.slice(d,e)+c+f.slice(e)}

Do you really need to use split and join at all? You should be able to access into the string like an array.

@xpansive, I already tried this, but accessing single characters with [] seems to be read-only and can't be abused to insert something.

@maettig Too bad. I was thinking in C...

Doing the same for Internet Explorer is incredible easy, including setting the focus and not losing the cursor position (78 bytes):

function(a,b,c){a=document.selection.createRange(a.focus());a.text=b+a.text+c}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.