Responsive Rich Editor Preview - javascript

Consider this Example.
The essential bit is the JavaScript:
function encodeInput(editor) {
theText = editor.val();
theText = theText.replace(/\*\*\*(.*?)\*\*\*/, '<strong><i>$1</i></strong>', 'g');
theText = theText.replace(/\*\*(.*?)\*\*/, '<strong>$1</strong>', 'g');
theText = theText.replace(/\*(.*?)\*/, '<i>$1</i>', 'g');
console.log(theText);
$('#preview').html(theText);
}
$(function() {
$editor = $('#editor');
$editor.keyup(function() {
encodeInput($(this));
});
});
Tested and works great (I do need the \*\*\* part or it doesn't work).
Anyways, on to the main course
The Problem
Because I'm using keyup, the script is not very responsive (eg. it only "runs" once the user had let go of the key). I want it to behave more like the editor here on StackOverflow, where the key is pressed and response occurs immidiately.
I tried using keydown and keypress but it seems as if the val() attribute is not updated when it runs, so I can't really know the updated value.
In Short
How can I make it more responsive, so that when the user pressed a key, the preview is automatically updated??

You can use the HTML5 input event in most browsers and the propertychange event in IE < 9. These events fire immediately after the textarea's value is updated.
Here's an updated demo using these events:
http://jsfiddle.net/muWm2/1/
I've written about this in a few places on SO. Here are two of them:
Catch only keypresses that change input?
jQuery keyboard events
I would recommend against updating the preview on every single change to the textarea's value because it could quickly get unresponsive, which is a big no-no for user experience. I'd suggest "debouncing" the event, in this case waiting for a period of user inactivity (say half a second) before updating the preview. Here's an answer and a link that may help:
How to trigger an onkeyup event that's delayed until a user pauses their typing?
Debouncing Javascript Methods by John Hann

You can bind() both the keyup and keydown events:
$editor.bind('keyup keydown', function() {
encodeInput($(this));
});
I noticed that only the first occurrence was working, adding the g flag to the regex seemed to help, and for the purpose of the jsfiddle demo only, unchecking "normalize css" made the bold text appear.
http://jsfiddle.net/tuUym/3/

Keypress fires when the key is pressed continously, so you have to bind it to keypress in order to see the result. And thats it.
http://jsfiddle.net/tuUym/4/
UPDATE: I see what you mean. Maybe you need an input poller? Check out the de obfuscated wmd code. That will help you achieve the lagless editor you aim for:
WMD Download

Related

Which event is being triggered from a menu paste?

I have a search box that users can type in. When the user keys up, the search is performed. There are checks to see the length of text in the search box.
// THE SEARCH STRING IS BEING POPULATED
$SEARCH.SearchString.keyup($SEARCH.utilities.doSearch);
When someone uses ctrl+v to paste text, this works perfect. When someone uses the menu to paste, like in the image below, the search is not performed.
I am not sure of what to call this menu so it's difficult to search for an answer. What event should I have JavaScript listen for when this menu is present and the user selects "Paste"?
The input event triggers for both paste and typing, thus could be used in lieu of keyup or keydown and cover both scenarios for user entry in modern browsers.
The caveat is that IE shows support starting in IE9 as well as IE9 has some different behavior issues .
IE 9 does not fire an input event when the user removes characters
from input filled by keyboard, cut, or drag operations.
$('input').on('input', function(e){
$('body').append('<br>Input event triggered, value = ' + this.value);
});
Reference: MDN input event docs
DEMO
There is onpaste but it doesn't seem to be part of any standard so your milage may vary
$(selector).on('paste', function() {
doSomething();
});

disable all keyup/keydown/keypressed events present on page

I am having plenty of key events here on my page.Is there any way to disable all the keyup/keydown/keypressed events present on page rather than disabling each event separately.
i am looking for solution using javascript/jquery.
Thanks!!
You could do it this way, though I expect it might be horrendously slow on larger pages:
$('*').off('keyup keydown keypress');
That's going to select every single element on the page, then remove any keyup, keydown, and keypress events that are bound to them.
If you want to prevent the user from using the backspace key to navigate to the previous page, you could try the following code:
var inputTags = ['INPUT', 'TEXTAREA'];
$(document).on('keypress', function(e) {
if(e.which === 8 && $.inArray(e.target.tagName, inputTags) === -1)
e.preventDefault();
});
That should restrict the use of the backspace key, except in instances where the focus is an input element where you can enter text (so an <input type="text"> or a <textarea>).
Take a look at this working demo.
Try
$(document).find('*').off('keyup keydown keypressed');
and you should put this into the $(document).ready() block, after all the loaded JS on page (before </body> tag, for example).
you can use preventDefault() function to solve it
$('*').unbind('keyup keydown keypress')
For me worked this combination:
Turn on keypress event
$(document).keypress(function(){
// Code
});
and for turning off this event I have used:
$(document).off('keypress');
$(elem).off('keypress.jstree')
I recently struggled with this as well since I was adding editing features to tree nodes. By looking at the source, I noticed there's an event keypress.jstree being bound with a timeout of 500ms.
Simply adding the above off binding after initializing the tree solved all my issues at once! This works both for static tree structures as well as tree's loaded with ajax data. The version I'm currently using is 3.3.5
Hope this helps.
This code deletes the last key pressed in TextBox2, by using substr.
`$("#TextBox2").val($("#TextBox2").val().substr(0, ($("#TextBox2").val().length-1)));`
//removes last letter pressed.

jQuery using event.preventDefault() with on('input')

I'm catching paste events with $('selector').on('input', function(event) { ... });
Then I'm trying to test what's been pasted and if it doesn't pass validation, cancel the paste with event.preventDefault(). Unfortunately, by the time the listener function is executed, the text has already been pasted and event.preventDefault() does nothing.
So what's a good way to catch paste events, and if what's been pasted doesn't validate, undo/prevent the paste?
I know I can use .on('paste', function(event) { ... }), but that doesn't give me the text that's been pasted or the contents of the input element after the paste, unless I use setTimeout() with some minute wait time, and I'd like to avoid using setTimeout().
First of all some background on event trigger order for the input element:
keydown -> keypress -> paste -> input -> keyup -> change
Whenever you call preventDefault it stops the chains, like nothing happened.
So my suggestion is to catch the paste event, prevent its default behavior and do your logic there.
I know I can use .on('paste', function(event) { ... }), but that
doesn't give me the text that's been pasted or the contents of the
input element after the paste
Actually you can retrieve the content of the clipboard. See this doc. Support is all major browser (but only IE11+). I do not know if by the time of the writing of the question this functionality was available or not.
Fiddle example
$('#myInput').on('paste', function(e) {
// Cancel the event - this prevents the text from being entered into the input and stops the event chain
e.preventDefault();
// Get the content of the clipboard
let paste = (event.clipboardData || window.clipboardData).getData('text');
// Validate what it is pasted
if (paste == "text to paste") {
// If condition is satisfied manually set the value of the input
$(this)
.val(paste)
// Manually trigger events if you want
.trigger('input')
.trigger('change');
}
});
Notes on the code:
This solution does not include setTimeout. Whenever you make it with setTimeout you see for a very short time the text being pasted, like a blinking effect.
If text meets condition I manually set it in the input. However this does not trigger input and change events. If you need them, just manually trigger them
Similar approach is to first check the text and if it does not meet requirements then call preventDefault, otherwise do nothing. This way you avoid manually setting value in the input and triggering events afterward.
Try using .change event of jquery.
Set value to blank if value doesn't satisfy your condition.
Using
$('selector').on('input', function(event) { ... });
and in case the validation does not pass deleting the pasted text seems to work for me.
Sadly accessing the clipboard has some flaws (browser asking if it is allowed to inspect the clipboard, cross browser compatibility, etc.)
If you are okay with saving the last value of the input, the pasted text can be calculated anyway.
Here is my approach for calculating the pasted text
https://jsfiddle.net/f710o9qd/2/
I hope this helps you :)
(Feel free to refine the calculation of the pasted text if you find any flaws)
My understanding from the question is, we must not allow any data to be pasted inside the text box until and unless it pass a specific validation. Instead of using event.preventDefault(), we can capture the value when user input any content, using on('input') listener and validate it against the specific condition and if the validation gets failed, empty the text box value.
(This is the workaround if we still need to use on('input') event listener)
Sample Code (I am using console.log() for printing the pasted value):
HTML:
<input type='text' id="selector" />
JS:
$(document).ready(function() {
$('#selector').on('input', function (e){
if(e.target.value !== "myValue"){
$('#selector').val('');
}
else{
console.log(e.target.value);
}
});
});

Key event doesnt trigger in Firefox on Android when word suggestion is on

I have a search field that triggers an autocomplete search while typing. I have it trigger on keyup. This works perfectly in most browsers, but in Firefox on Android, this does not work. It seems like the keyup event is not triggered while typing. This only happens if word suggestions is turned on in the Android keyboard settings.
I see on Google search that the autocomplete search works there for the same setup, so it is obviously possible to do. I wonder how? Is it a special event I need to listen to for this to work?
Additionally I have tried to listen to the events change, keydown and keypress, but none is triggered.
HTML:
<input type="text" id="searchField"
autocomplete="off" spellcheck="false" autocorrect="off" />
jQuery event binding:
$('#searchField').keyup(function (e) {
var searchValue = $(this).val();
searchApi._executeAutocomplete(searchValue);
});
Note:
Sometimes, the key event is triggered, which is typically hitting a key that is not resulting in the process of forming a word. The most obvious here is Enter, which always triggers. Another is Space, which triggers because no word contain a space since space is the definition of a word completed. Backspace triggers if the the last character deleted was not within a word. This means it triggers if you just deleted the last remaining letter of a word (so it is the start of the field, or cursor following a space), but not if you deleted some characters at the end of a word where the cursor is still immediately following a letter. Basically, the key event is not triggered if the key press results in some kind of word suggestion from the keyboard app.
As a side note, I can say that everything works fine in Chrome on the same device.
You can use the input event instead, that worked for me in Firefox on Android.
You could bind event handlers to both input and keyup events for backwards compatibility, but in most modern browsers this will fire both:
$('#searchField').bind('input keyup', function(e){
var searchValue = $(this).val();
searchApi._executeAutocomplete(searchValue);
});
Example here:
http://jsfiddle.net/JQ928/3/
I found a solution in this answer to another question. The question was a basically "duplicate the text I write dynamically into another part of the page". The answer was including support for catching changes by non-keyboard actions, like pasting text using mouse. It was solved by starting a sniffer on focus in the text field that checks if the value has changed using setInterval(...). It clears the timer on blur.
This solved my problem which was basically that the key events didn't trigger, as well as the "paste by mouse" issue that I didn't realize was a problem until I found this answer...!
This works, but I'm not sure I am totally happy with this solution, because it uses a sniffer. I would be more happy with using some sort of event that is triggered on value change no matter what the cause of the change is. Using the change event would not work, as that is not triggered until focus leaves the field.
Trough the fact that Firefox on Android doesn't trigger key-events, but also triggers the input-event some kind of weird, (like if you press one key two events get triggerd, and it also triggers the input-event if you leave the input) I had to write my own event:
(function($){
var $event = $.event,
$special = $event.special.fennecInput = {
setup: function(){
$(this).on('input',$special.handler);
},
teardown: function(){
$(this).off('input',$spceial.handler);
},
handler: function(event) {
var context = this,
args = arguments,
dispatch = function() {
event.type='fennecInput';
$event.dispatch.apply(context,args);
};
if($(context).val() != $(context).attr('data-fennecInput-oldval')){
dispatch();
$(context).attr('data-fennecInput-oldval',$(context).val());
}
}
};
})(jQuery);
this event gets only triggered if an input-event happens that changes the value, so it doesn't execute events unnecessary.

Programmatically selecting text in an input field on iOS devices (mobile Safari)

How do you programmatically select the text of an input field on iOS devices, e.g. iPhone, iPad running mobile Safari?
Normally it is sufficient to call the .select() function on the <input ... /> element, but this does not work on those devices. The cursor is simply left at the end of the existing entry with no selection made.
input.setSelectionRange(0, 9999);
https://developer.mozilla.org/en/DOM/Input.select
Nothing in this thread worked for me, here's what works on my iPad:
// t is the input field
setTimeout(function() {
t.setSelectionRange(0, 9999);
}, 1);
See this fiddle: (enter some text in the input box and click 'select text')
It is selecting text in an inputbox on my iPod (5th gen iOS6.0.1), opening the keyboard and also showing the Cut/Copy/Suggest... menu
Using plain javascript. Did not try this with jQuery
document.getElementById("p1").selectionStart = 0
document.getElementById("p1").selectionEnd = 999
Note that the number 999 is just a sample. You should set these numbers to the number of characters you want to select.
UPDATE:
iPod5 - iOS6.0.1 - Working ok.
iPad1 - iOS5.1.1 - Only text selected. Tap selection once to open Cut/Copy menu
iPad2 - iOS4.3.3 - Only text selected. Tap selection once to open Cut/Copy menu
For the last two, you might experiment by triggering a click event on the input element
UPDATE: (07-10-2013)
iPod5 - iOS7.0.2 - Using the fiddle in the link: Can't see typed text in input box.
Pressing select redirects me to facebook.com (??? wtf ???)
no idea what's going on there.
UPDATE: (14-11-2013)
iOS 7.0.3 : Thanks to the comment from binki update that the
.selectionStart and .selectionEnd does work.
UPDATE: (15-01-2015)
iOS 8.x.x : Thanks to the comment from Michael Siebert. Taken from the comment:
I had to listen for both focus AND click events and then setTimeout/_.debounce
to make it work in both cases: click the input or focus through tabbing
It's hard to prove a negative, but my research suggests this is a bug in Mobile Safari.
Note that focus() works, more or less—though it can require more than one tap to succeed, and it's not necessary if you're trying to respond to a user tap on the field in question as the tap itself will give the field focus. Unfortunately, select() is simply non-functional in Mobile Safari.
Your best bet may be a bug report with Apple.
Sorry, in my earlier post, I didn't notice the Javascript implying that you wanted an answer in Javascript.
To get what you want in UIWebView with javascript, I have managed to scrape together two important pieces of info to get it to work. Not sure about the mobile browser.
element.setSelectionRange(0,9999); does what we want
mouseUp event is undoing the selection
Thus (using Prototype):
input.observe('focus', function() {
this.setSelectionRange(0, 9999);
});
input.observe('mouseup', function(event) {
event.stop();
});
does the trick.
Matt
It looks like focus will work but only when directly called from a native event. calling focus using something like SetTimeout does not appear call up the keyboard. Control of the ios keyboard is very poor. Its not a good situation.
I went nuts looking for this solution, while all your responses did help it opened another can of worms for me.
The client wanted the user to be able to click and select all, and also let the user 'tab' and select all on the iPad (with an external keyboard. I know, crazy...)
My solution to this problem was, rearrange the events. First Focus, then Click, then touchstart.
$('#myFUBARid').on('focus click touchstart', function(e){
$(this).get(0).setSelectionRange(0,9999);
//$(this).css("color", "blue");
e.preventDefault();
});
I hope this helps someone, as you lot have helped me countless times.
Something like the following is working for me for me on Webkit that comes with Android 2.2:
function trySelect(el) {
setTimeout(function() {
try {
el.select();
} catch (e) {
}
}, 0);
}
See Chromium Issue 32865.
With iOS 7 on iPad the only way that I was able to make this work was to use actually <textarea></textarea> instead of <input> field.
e.g.
<textarea onclick="this.setSelectionRange(0, 9999);">My text will be selected when textarea is clicked.</textarea>
How to prevent user from changing text inside area was more difficult, since is you make textarea readonly the selection trick won't work anymore.
If you are using HTML5-compliant browsers, you can use placeholder="xxx" in your input tag.
That should do the job.

Categories

Resources