In my custom-editor wrapping up the code in <pre> tags works fine. I would like to visually organize the pasted code for better readability. For that I need blank lines in between chunks of code. But instead of a empty line, when I press Enter, the whole code block breaks into two, with new one wrapped in its own pre-tag. The code below is supposed to be in a single-block with an empty line between example_function and another_example_function()
FYI, the contenteditable class is set to have style="display:inline-block" to prevent div.wrapper on every line. Possibly relevant CSS info - pre { white-space: pre-wrap;}. I am on chrome 83.xx. Let me know if you need any more info. Below is what I tried and failed:
//there could be several code-blocks so running a loop to get all
let preTags = document.querySelector('.custom_editor').querySelectorAll('pre')
if (preTags) {
preTags.forEach(function(item) { // attaching an event-listener to each code block
item.addEventListener('click', function(e) {
if (e.keyCode === 13) { //on enter just need a empty new line
document.execCommand('insertHTML', false, '<br>');
return false;
}
})
}
}
HTML
<div class="content" style="display:inline-block;" contenteditable="true"></div>
The nested pretags eg. contenteditable>pre do not seem like an ideal setup for events like 'keypress', 'keydown' and 'keyup' as they did respond to these events in my case. The 'click' event within pretags worked but did not process the if (e.key === 'Enter') check, so I did not follow that route.
Instead of listening to events for each pretag, I attached a listener to the container only and all of sudden my custom setting for enter-event was working inside and outside all pretags within container. Eventually I can get the empty lines within my pretags on pressing the Enter key.
document.querySelector('.custom_editor').addEventListener('keypress', someFunc)
function someFunc(e){
if (e.key === 'Enter') {
document.execCommand('insertHTML', false, "<br>");
e.preventDefault()
}
}
Related
I have created a JQuery dynamic table here and I'm trying to implement input checking to make sure only the numbers are saved. The cell is updated either by clicking outside of it or by pressing the enter button and what I am trying to achieve is having an alert whenever an invalid input is entered.
The 'focusout' function alert is is working perfectly. The 'keypress' function alert on the other hand is behaving strangely, the alert message is popping out as normal however it doesn't go away no matter how many times I click ok.
According to console.log() the alert is triggering the 'focusout' function somehow. But even if that was the case, I don't understand how that is causing the error since the 'focusout' function works fine. I've tried to use $(this).focus() after the alert but this didn't work. Any Idea what I may be missing?
Thanks in advance
$(document).on('keypress', '.row_data', function (event) {
if (event.which === 13) {
event.preventDefault()
if (isNaN($(this).html())) {
alert("Enter valid number")
} else {
var elem = $(this)
saveValue(elem)
}
}
});
/* Saves the edited cell data when user clicks outside the cell */
$(document).on('focusout', '.row_data', function (event) {
event.preventDefault();
if (isNaN($(this).html())) {
alert("Enter valid number")
} else {
var elem = $(this)
saveValue(elem)
}
});
EDIT
So here is my HMTL for context. I am using Handlebars to create a table but basically all my cells are like this..
<span class="row_data" edit_type="click" col_name="col_1">{{col_1}}</span>
</td>
<td>£
<span class="row_data" edit_type="click" col_name="col_2">{{col_2}}</span>
</td>
<td>£
<span class="row_data" edit_type="click" col_name="col_3">{{col_3}}</span>
</td>
and I'm using JQuery to make the cells editable like this...
/* Makes each cell on the table editable */
$(document).on('click', '.row_data', function (event) {
event.preventDefault();
if ($(this).attr('edit_type') === 'button') {
return false;
}
$(this).closest('span').attr('contenteditable', 'true');
$(this).css("background-color", "beige").css('padding', '5px');
$(this).focus();
})
I've made some changes below to your code and have commented on it fully. It's best to not repeat code whenever possible, and just maintain a single function and trigger that using various methods rather than having to ensure two different functions are maintained separately.
You are currently triggering your alert multiple times, we can rationalize the code a bit to avoid the two different functions triggering the warning.
I think you can simplify things by using:
$(":focus").blur();
This removes the focus from whichever element is in focus.
I've assumed your .row_data is an input, so have also used .val() rather than .html(), you might need to change this back depending on your use case.
Let me know if you were hoping for something else.
// I would recommend using keyup rather than keypress
$(document).on('keyup', '.row_data', function(event) {
// Check if it is a return
if (event.which === 13) {
// Remove focus
// This will triger the function below, it'll be easier to manage a single function
$(':focus').blur();
// Prevent default
event.preventDefault()
}
});
/* Saves the edited cell data when user clicks outside the cell */
$(document).on('focusout', '.row_data', function(event) {
// Prevent default
event.preventDefault();
// Check if NaN
// Used .val() - not sure if you need to use .html in your use case
if (isNaN($(this).val())) {
// Notify user
alert("Enter valid number")
} else {
// Pass element to save
saveValue($(this))
}
});
// Test saving function
function saveValue(elem) {
// Send to console to prove it works
console.log("Saving " + elem.val());
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input class="row_data">
Hi having your HTML here will help suggest a better soultion, but the simple guess is that you are creating a loop, with your events.
You said the keypress event is the problem, just for testing purposes have you tried changing keypress to keydown/keyUp.
Also i sugges changing the alert to console.log, for easier debuging.
I have assigned an event listener to a HTML container and when the user clicks on the play again button, the code within the 'if' statement should execute. Nothing is happening when clicking on the play again button and nothing is being logged to the console. I have tried various different ways of doing it such as testing to see whether the element has a certain class name etc.
Here is the relevant HTML code:
<div class="play-again-btn">
<input type="button" class="play-btn" value="PLAY AGAIN">
</div>
Here is where the event listener is assigned to the container:
document.querySelector(DOMstrings.endContainer).addEventListener("click", playerCtrl.playAgain);
Here is the playAgain method:
playAgain: (event) => {
let finishedPlayer, parentEl;
console.log(event.target);
//1. only action below code if correct button is clicked (correct target element is clicked)
if (event.target.nodeName == "input") {
//2. delete existing character from finish line
finishedPlayer = document.querySelector(DOMstrings.finishBox);
finishedPlayer.removeChild(finishedPlayer.childNodes[0]);
//3. bring character select pop up
document.querySelector(DOMstrings.usersInput).style.visibility = "unset";
//4. remove leaderboard pop up
parentEl = document.querySelector(DOMstrings.endContainer);
parentEl.removeChild(parentEl.childNodes[1]);
}
},
The Node#nodeName property stores the type of the node (Text, Element, Comment, etc.) not the tag name of the HTML element represented by the node.
So, Node#nodeName will never be equal to "input", and your code won't run.
To check the tag name, use Element#tagName instead:
if (event.target.tagName == "input") {
Also, instead of that, it seems better to check if the clicked element is your button, so, if you can select the button, it's better to do an equality check with it:
if (event.target === document.querySelector(selectorOfButton)) {
How to simulate keypress inside of a contenteditable div Programatically?
I want to remove characters programatically with a jQuery script without any human typing.
I would like to delete some characters from the end of the span tag with simulating a Backspace keypress inside of the contenteditable div.
<div class="editor" contenteditable="true">
<span>This is a span!!</span>
</div>
So the result would be something like this:
This is a span
I wouldn't like to rewrite the text. I need to simulate backspace keypress. Tested with this code, but nothing happened.
$(document).ready(function(){ // after the website loaded
// I want to trigger a keypress (backspace key)
// inside of the contenteditable div Programatically
$('.editor').trigger(jQuery.Event('keypress', { keycode: 8 }));
});
Can you help me?
I used some part of code that was mentioned in the comments: SO answer - Yuri
Here is the part that triggers the keydown event
$(document).ready(function(){ // after the website loaded
// I want to trigger a keypress (backspace key)
// inside of the contenteditable div Programatically
var e = jQuery.Event("keydown");
e.which = 8; // backspace key
$(".editor").trigger(e);
});
After that, I created a handler to .editor element
$(".editor").keydown(function(e) {
if (e.originalEvent === undefined) {
console.log('triggered programmatically');
} else {
console.log('triggered by the user');
}
console.log("Key pressed:" + e.which);
if(e.which == 8) {
// do your stuff
}
});
I also, put a validator to check if the event was trigged by user or programmatically.
I want to use the arrow keys to navigate between the input text fields in my form (next, previous). I found this simple method to implement it: link to it but for me it doesn't work... I tried it in the HEAD and in the BODY after the FORM as well, but no luck...
I think the problem could be, that my form is send back to the page via AJAX...
I'm not that familiar with jQuery, can someone please help me out here?
This is the jQuery code:
<script>
$(document).ready(function(){
$('input').keyup(function(e){
if(e.which==39)
$(this).closest('td').next().find('input').focus();
else if(e.which==37)
$(this).closest('td').prev().find('input').focus();
else if(e.which==40)
$(this).closest('tr').next().find('td:eq('+$(this).closest('td').index()+')').find('input').focus();
else if(e.which==38)
$(this).closest('tr').prev().find('td:eq('+$(this).closest('td').index()+')').find('input').focus();
});
});
</script>
if your inputs are dynamically created after domready event you should change
$('input').keyup(function(e){
...
into
$('body').on('keyup', 'input', function(e) {
...
doing so the keyup event will be captured on body element using event delegation
For further info see the documentation here: http://api.jquery.com/on/
Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on(). To ensure the elements are present and can be selected, perform event binding inside a document ready handler for elements that are in the HTML markup on the page. If new HTML is being injected into the page, select the elements and attach event handlers after the new HTML is placed into the page. Or, use delegated events to attach an event handler...
If your script is loaded before the form is on the page then the keyup binding would not be able to bind on load. Try using:
$('input').live('keyup', function(e) { code here });
Just in case you want to bind more than one event, this is how you do it:
$('body').on({
'keyup' : function(e) {
...
},
'keydown' : function(e) {
...
}
}, 'input');
Also 'body' can be swapped with any parent element of 'input' that will not be dynamically added to the page (i.e. it exists on page load). So if you have some div containing each input, you might want to bind that instead.
I've got a slight improvement to the code above. The problem with the code is that you cannot navigate inside an input field. E.g. you have a value of '100.00|' with the cursor currently at the end (indicated with |). If you press the left key it will jump to the prev input field instead of moving the caret by one position to '100.0|0'.
In order to do that you need to check the current caret position with e.target.selectionStart. But you also need the prev caret position as otherwise you can't identify whether the caret went from 1 to 0 (no jump) or the caret was already on 0 and the user pressed left again (jump).
Another change I've added is that only input fields with the class tableInput are considered. In case you want to exclude some fields.
function(e){
var charPos = e.target.selectionStart;
var strLength = e.target.value.length;
var prevPos = $(this).data('prevPos');
if(e.which==39){
//only go right if we really reached the end, that means the prev pos is the same then the current pos
if(charPos==strLength && (prevPos ==null || prevPos == charPos)){
$(this).closest('td').next().find('input.tableInput').focus();
$(this).data('prevPos',null);
}else{
$(this).data('prevPos',charPos);
}
}else if(e.which==37){
//only go left if we really reached the beginning, that means the prev pos is the same then the current pos
if(charPos == 0 && (prevPos ==null || prevPos == charPos)){
$(this).closest('td').prev().find('input.tableInput').focus();
$(this).data('prevPos',null);
}else{
$(this).data('prevPos',charPos);
}
}else if(e.which==40){
$(this).closest('tr').next().find('td:eq('+$(this).closest('td').index()+')').find('input.tableInput').focus();
$(this).data('prevPos',null);
}else if(e.which==38){
$(this).closest('tr').prev().find('td:eq('+$(this).closest('td').index()+')').find('input.tableInput').focus();
$(this).data('prevPos',null);
}
});
I have a web app which plots points with SVG, I want to add the ability to delete a selected point by pressing the delete key. I can capture delete keydown (or up) for the entire document and prevent the default event (Chrome's default behavior is to go back a page), however this obviously blocks all delete events so the delete button no longer works in forms.
Is there a way to set it up so that the delete key works as intended in forms/inputs but when anywhere else in the app it can be used as a custom delete function?
The first thing that came into my mind, is to stopPropagation on the input and textarea fields, then the preventDefault should not be triggered on the document.
JQuery pseudo code:
$('input, textarea').keypress(e, function(e){e.stopPropagation();});
$(document).keypress(e, function(e){if(delete) e.preventDefault();});
Another possiblity is the check the orignal target on the key event of the document.
Event callback:
var originalElement = e.srcElement || e.originalTarget;
if(orignalElement.tagName === 'INPUT' or orignalElement.tagName === 'TEXTAREA'){ return; }
// else do your delete key stuff
The first line should be obsolete, if you are using jQuery, because it normalized the event for you, and you can use e.target to get the originalTarget
My prefered approach would be something like this:
$(window).keyup(function(e) {
if(e.keyCode == 46 && $("input:focus, textarea:focus").length == 0) {
e.preventDefault();
alert("delete key pressed!");
}
});
However, I'm not sure if you'll be able to override the back button behaviour - it seems unlikely that Chrome would allow it, given the potential for abuse.