Forum Moderators: open

Message Too Old, No Replies

Replacing :-) with image

         

csdude55

9:42 pm on Nov 26, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



My textarea is really contenteditable, and I have it set up with a series of emoji images (well, sprites really) that the user can click to insert. I've always also converted 9 or 10 ascii emojis (like :-D and :D ) to a corresponding emoji image after they submit it for processing.

Now, though, I'd like to change it up so that the text is automatically converted while they're typing. So instead of them seeing :-D in their text and then it being converted afterward, they would see exactly what's going to show up. So I want to automatically convert when the text matches and is followed by a whitespace or return.

The issue I'm having is speed. I hate to run a regex after every key stroke to constantly read the last 3 characters, I think that would be noticeably slow for people like myself that type fast.

Any other suggestions?

I'm thinking maybe to create an empty array, and onkeyup if the keystroke is a : then add it to the array; if not, empty the array. Then on the next onkeyup, if array[0] exists and the keystroke is a - or one of the predefined characters (D, ), (, etc) then add it to the array; if not, empty the array. Then on the next onkeyup, if array[0] exists and the keystroke is one of the predefined characters, add it to the array; if not, empty the array.

Then if the NEXT onkeyup is a whitespace or a return, run a regex to replace the ending with a matching image. Something like this (typed, not tested):

var emoji = {
':)' : 'emoji_grin.gif',
':D' : emoji_smile.gif'
};

var array = [];

// using jQuery
$('#str)
.on('keyup', function(e) {
// colon = 186
if (array.length == 0 && e.which == 186) {
array.push(':');
return;
}

// hyphen = 189, 173 in FF
if (array.length == 1 && (e.which == 189 || e.which == 173)) {
return;
}

// so far it looks like an emoji, go ahead and add whatever the next character is
if (array.length == 1 && e.which !== 189 && e.which !== 173) {
array.push(e.which);
return;
}

// enter = 13, whitespace = 32
// replace matching text then empty array
if (array.length == 2 && (e.which == 13 || e.which == 32)) {
str.replace(new RegExp(array.join('') + '\s+$'), emoji{array.join('')});
array = [];
}

// they pressed space or enter with no final character, empty array
elseif (e.which == 13 || e.which == 32)
array = [];
});


I guess that I can't really just replace it with the emoji object, I'd have to run a function to convert the image to insertHTML. But this should give you an idea of what I'm thinking.

This also has two other issues:

1. if someone has typed out a sentence, then click in the middle of the sentence to add an ascii emoji, it's not going to be replaced since I'm using $ to only look at the end of the string. If you think that I'm on the right path, though, then maybe there's a way to apply to the text immediately before the current cursor position rather than the end of the string?

2. If they type :- and type space, enter, or something else that doesn't match "emoji", then click on Backspace to add a ), the array is already wiped out so it's not going to change it. It would still be changed when it processes through Perl, of course, they just wouldn't see it before submitting.

Thoughts?

lucy24

1:39 am on Nov 27, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Honestly I think this would be more trouble than it's worth. Does the editable area have a Preview option? Seems like that would be the place to put in the emoji. Same as on the present forum, where you do a quick Preview to make sure that some bit of parenthesized blahblah doesn't turn into an unwanted :) or ;)

If not, can submissions be edited after posting? (One forum that I love dearly has neither option, and boy is it irritating.)

csdude55

2:23 am on Nov 27, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



No to both questions... the whole reason for the contenteditable area was to eliminate the need for a preview! With the exception of profanity / vulgarity, what they see in the contenteditable is how it should look when it goes live.

I eliminated both Preview and Edit because people were just using it in an attempt to get around those profanity / vulgarity filters.

phranque

2:35 am on Nov 27, 2021 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



keep in mind that emojis are a terrible idea if your users are entering technical text such as code.
ask me how i know this...

phranque
Moderator - Webmaster General; Apache Web Server; Perl Server Side CGI Scripting; Website Technology Issues; ...

csdude55

6:26 am on Nov 27, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Hahahahaha! But no, they're not entering code... if they did it would scare the crap out of me!

robzilla

8:44 am on Nov 27, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I think that would be noticeably slow for people like myself that type fast.

You think, but have you tried? It may not be as slow as you expect.

Alternatively, you could look at the characters preceding the caret position, like so: [stackoverflow.com...]

But that still wouldn't account for all the possible ways a user might type out an emoticon, e.g. when one types -D and only later adds the preceding colon. To take all of that into account, you'll need quite a bit of code and I suspect a regex would be far more efficient. But obviously that is something you could benchmark.

You could also put in a brief delay so the regex only runs when the user stops typing.

tangor

9:50 am on Nov 27, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Raise your hand if you remember a time when there were no emojis...

@csdude55 ... not sure there's an actual need to convert on the fly. An accidental typo might scare a non-emoji user when some funny thing appeared on screen!

tangor

9:56 am on Nov 27, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Other option is to paint an insert table of allowed emoticons at point insert (cursor) outside the text area. Keeps code simple, predictable, and easier to sanitize before db insert.

csdude55

8:00 pm on Nov 27, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



@robzilla:

You think, but have you tried? It may not be as slow as you expect.

I have not, I felt like it would be a lot to build just to find out. I was hoping someone else has done it before me :-)

I DID, however, build a system awhile back that tried to offer corrected spellings (before mobile). This system was running an ajax function after every keyup and was suuuuuuuuper slow. Since then, I've shied away from using keyup in general.

Alternatively, you could look at the characters preceding the caret position, like so: [stackoverflow.com...]

Thanks for the find! That looks super complicated, but if I move forward then I'll try to test it out and see if it's faster.

But that still wouldn't account for all the possible ways a user might type out an emoticon, e.g. when one types -D and only later adds the preceding colon. To take all of that into account, you'll need quite a bit of code and I suspect a regex would be far more efficient. But obviously that is something you could benchmark.

You could also put in a brief delay so the regex only runs when the user stops typing.

Now that's a great idea, waiting for a period of no-typing (maybe 2 seconds?) and then just run a regex on the whole thing. That shouldn't be too hard; borrowing from this thread:

[stackoverflow.com...]

here's my modification:

var emoji = {
':)' : 'emoji_grin.gif',
':D' : 'emoji_smile.gif'
};

// look for period of no-typing; 2000 = 2s
var typingDelay = 2000,
array = [],
typingTimer;

// using jQuery
$('#str')
.on('keyup', function(e) {
var x = e.which;

// Change to emoji when they hit space or enter
//
// colon = 186
if (array.length == 0 && x == 186) {
array.push(':');
return;
}

// hyphen = 189, 173 in FF
if (array.length == 1 && (x == 189 || x == 173))
return;

// so far it looks like an emoji, go ahead and add whatever the next character is
if (array.length == 1 && x !== 189 && x !== 173) {
array.push(x);
return;
}

// enter = 13, whitespace = 32
// replace matching text then empty array
if (array.length == 2 && (x == 13 || x == 32)) {
str.replace(
new RegExp(array.join('') + '\s+$'),
emoji[array.join('')]
);

array = [];
}

// they pressed space or enter with no final character, empty array
elseif (x == 13 || x == 32)
array = [];

// Run full regex when they stop typing as a backup
clearTimeout(typingTimer);
typingTimer = setTimeout(doneTyping, typingDelay);
})

// clear the countdown
.on('keydown', function () {
clearTimeout(typingTimer);
});

function doneTyping() {
$('#str').html(function(i, val) {
$.each(Object.keys(emoji), function(i, v) {
// allow for emojis with - since they're not in the main list; eg, :-D
// then escape anything not a letter, number, or ?
var escapedV = v.slice(0, 1) + '-?' + v.slice(1);
escapedV = escapedV.replace(/([^\w?])/g, "\\$1");

// why doesn't it match with an opening \b?
// new RegExp('\\b' + v + '\\b', 'g'),
val = val.replace(
new RegExp(v + '\\b', 'g'),
emoji[v]
);
});

return(val);
});
}

csdude55

8:06 pm on Nov 27, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Raise your hand if you remember a time when there were no emojis...

Oh, the good old days!

I used to be a heavy usenet user, though, and even then we used a lot of ascii emojis. Which is why I guess I'm doing this little project; I still find myself typing out :-D and never go hunting for an emoji to click on. It's just too much work to go back and forth from keyboard to mouse to keyboard.

Remember when we only had to worry about 640x480 and 800x600 resolutions? Talk about a simpler time! Gah, I miss that :'-(

Other option is to paint an insert table of allowed emoticons at point insert (cursor) outside the text area. Keeps code simple, predictable, and easier to sanitize before db insert.

I do have that set up, too; this is really just an autofix for maybe 10 people that still type out ascii emojis like me. Which, of course, is why speed is critical: I hate to impose any speed issues on the 99.9% of people for whom it's irrelevant.

So I dunno, maybe I'll eliminate the array part of it completely and just do a full regex when they stop typing.

lucy24

6:06 am on Nov 28, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



maybe 10 people that still type out ascii emojis like me
Plot twist: 9 of those 10 people actually expect to see the ;-P or :-o that they typed, and will be annoyed and disconcerted when it turns into a fancy emoji.

:: vague recollection of distressing results in portions of William Savage’s Dictionary of the Art of Printing that were intended to show simple symbols and instead come through as full-color 3D emojis ::

csdude55

8:26 pm on Nov 28, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



@lucy24, how dare you try to bring logic and common sense to my chaos! LOL

I'm close to having the script finished, I'll post it when I'm done. It might turn in to more trouble than it's worth, but it was a fun aside from Perl scripting this weekend anyway :-)

csdude55

11:25 pm on Nov 28, 2021 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I think I have everything functioning now, if you want to see it in practice:

[jsfiddle.net...]

Just click in the contenteditable and type something like ":-)" or "Blah blah :-)" and you'll see how it goes. Of course, you can add as many emojis to the "emoji" list at the top as you want.

The only issue I've seen is that, after it substitutes, it pushes the caret back to the beginning. As-is, that would be a problem for anyone typing! But in my application I'm using document.execCommand('insertHTML',...) instead of just substituting to text, and I already take care of putting the caret back where it belongs. That was a pain to write, and I didn't want to complicate this script with that whole thing.