I've got a small contenteditable span on a page. Under some circumstances (pressing the escape key, for example), I'd like to programmatically cancel editing mode.
Is there a way to do that?
So far, I've found only the hack of removing the contenteditable attr and restoring it shortly thereafter (e.g. 100ms later or so) which is cannot possibly be the right way :-( I would imagine I could change the focus for the same effect.
What I really want is elem.endEdit() or some such...
Thanks!
You can call blur() on the element that is being edited.
Here is an example: https://codepen.io/MarcMouries/pen/PowEYRv
<h3>Editable content</h3>
<div contenteditable="true" id="editor">Click me, type something, then press the ESC key</div>
<h3>Events</h3>
<textarea id="log" rows="10" cols="100" readonly></textarea>
var element = document.getElementById("editor");
var eventsLog = document.getElementById("log");
var oldValue = "";
document.addEventListener('keyup', (e) => {
if (event.keyCode == 27) {
eventsLog.value += "ESC key pressed => UNDO reset to (" + oldValue + ")\n";
var element = event.target;
element.textContent = oldValue;
element.blur();
}
}, false);
element.addEventListener("focus", function(event) {
var element = event.target;
oldValue = element.textContent;
eventsLog.value += "FOCUS: value = " + oldValue + "\n";
});
element.addEventListener("blur", function(event) {
var element = event.target;
var newValue = element.textContent;
if(newValue != oldValue) {
eventsLog.value += "Input changed value to: " + newValue + " \n";
}
}, false);
Related
In my Web App I have have an TextEditor, which can be manipulated by some buttons.
For example:
<textarea id="textareaId"></textarea>
<button onclick="add()">Click me</button>
<script>
add() {
document.getElementById('textareaId').value += 'some content';
}
</script>
The issue is, that the user cant undo this (for example by shortcut ctrl + z).
It looks like that the the undo-buffor for the textarea gets cleared by that. Is there any way to do the changes without losing the option of undoing?
You can cache the textarea's value using an array as stack:
var valuesStack = [];
var textarea = document.getElementById('textareaId');
textarea.addEventListener('keydown', function(event) {
if (event.ctrlKey && event.key === 'z') restore();
});
function cache() {
valuesStack.push(textarea.value);
}
function add() {
cache();
textarea.value += 'some content';
}
function restore() {
var value = valuesStack.pop();
if (value === undefined) textarea.value = "";
else textarea.value = value;
}
<textarea id="textareaId" onchange="cache()"></textarea>
<button onclick="add()">Click me</button>
There are quite a few posts on this but after spending several hours trying to adapt the solutions that already exist, it's become clear to me that this is a little bit more complicated.
I'm attempting to create 'copy to clipboard' functionality so that our users can copy their serial number with a single click (I managed to achieve this functionality with 2 different solutions) but there's a major catch.
As the serial number is generated dynamically using a shortcode I cannot place it inside a HTML 'text'/'value' field, like so:
<input id="serial" value="[shortcode here]">
as this breaks the shortcode, so it has to be placed inside it's own div, which I have done like this:
<div id="serial">[shortcode here]</div>
This outputs the shortcode on the page with the direct parent ID of 'serial', so the JS I'm using should then select the text from the element ID - #serial.
Unfortunately it doesn't...
I've tried to adapt this method also with no luck:
From the Roll Your Own section: https://www.sitepoint.com/javascript-copy-to-clipboard/
This one was working with with plain text but not with the shortcode or custom div.
Can anyone provide me with a working clipboard solution as shown in the example above that won't break the shortcode?
document.getElementById("copyButton").addEventListener("click", function() {
copyToClipboardMsg(document.getElementById("copyTarget"), "msg");
});
document.getElementById("copyButton2").addEventListener("click", function() {
copyToClipboardMsg(document.getElementById("copyTarget2"), "msg");
});
document.getElementById("pasteTarget").addEventListener("mousedown", function() {
this.value = "";
});
function copyToClipboardMsg(elem, msgElem) {
var succeed = copyToClipboard(elem);
var msg;
if (!succeed) {
msg = "Copy not supported or blocked. Press Ctrl+c to copy."
} else {
msg = "Text copied to the clipboard."
}
if (typeof msgElem === "string") {
msgElem = document.getElementById(msgElem);
}
msgElem.innerHTML = msg;
setTimeout(function() {
msgElem.innerHTML = "";
}, 2000);
}
function copyToClipboard(elem) {
// create hidden text element, if it doesn't already exist
var targetId = "_hiddenCopyText_";
var isInput = elem.tagName === "INPUT" || elem.tagName === "TEXTAREA";
var origSelectionStart, origSelectionEnd;
if (isInput) {
// can just use the original source element for the selection and copy
target = elem;
origSelectionStart = elem.selectionStart;
origSelectionEnd = elem.selectionEnd;
} else {
// must use a temporary form element for the selection and copy
target = document.getElementById(targetId);
if (!target) {
var target = document.createElement("textarea");
target.style.position = "absolute";
target.style.left = "-9999px";
target.style.top = "0";
target.id = targetId;
document.body.appendChild(target);
}
target.textContent = elem.textContent;
}
// select the content
var currentFocus = document.activeElement;
target.focus();
target.setSelectionRange(0, target.value.length);
// copy the selection
var succeed;
try {
succeed = document.execCommand("copy");
} catch(e) {
succeed = false;
}
// restore original focus
if (currentFocus && typeof currentFocus.focus === "function") {
currentFocus.focus();
}
if (isInput) {
// restore prior selection
elem.setSelectionRange(origSelectionStart, origSelectionEnd);
} else {
// clear temporary content
target.textContent = "";
}
return succeed;
}
<input id="copyTarget" value="Some initial text"> <button id="copyButton">Copy</button><br><br>
<span id="copyTarget2">Some Other Text</span> <button id="copyButton2">Copy</button><br><br>
<input id="pasteTarget"> Click in this Field and hit Ctrl+V to see what is on clipboard<br><br>
<span id="msg"></span><br>
Would you please try above snippet?
Second #pruvik7373 answer
I think [shortcode] may contain some code which can translate into anything else so instead of using textContent use innerHTML it will make sure to copy everything as it is.
document.getElementById("copyButton").addEventListener("click", function() {
copyToClipboardMsg(document.getElementById("copyTarget"), "msg");
});
document.getElementById("copyButton2").addEventListener("click", function() {
copyToClipboardMsg(document.getElementById("serial"), "msg");
});
document.getElementById("pasteTarget").addEventListener("mousedown", function() {
this.value = "";
});
function copyToClipboardMsg(elem, msgElem) {
var succeed = copyToClipboard(elem);
var msg;
if (!succeed) {
msg = "Copy not supported or blocked. Press Ctrl+c to copy."
} else {
msg = "Text copied to the clipboard."
}
if (typeof msgElem === "string") {
msgElem = document.getElementById(msgElem);
}
msgElem.innerHTML = msg;
setTimeout(function() {
msgElem.innerHTML = "";
}, 2000);
}
function copyToClipboard(elem) {
// create hidden text element, if it doesn't already exist
var targetId = "_hiddenCopyText_";
var isInput = elem.tagName === "INPUT" || elem.tagName === "TEXTAREA";
var origSelectionStart, origSelectionEnd;
if (isInput) {
// can just use the original source element for the selection and copy
target = elem;
origSelectionStart = elem.selectionStart;
origSelectionEnd = elem.selectionEnd;
} else {
// must use a temporary form element for the selection and copy
target = document.getElementById(targetId);
if (!target) {
var target = document.createElement("textarea");
target.style.position = "absolute";
target.style.left = "-9999px";
target.style.top = "0";
target.id = targetId;
document.body.appendChild(target);
}
target.textContent = elem.innerHTML;
}
// select the content
var currentFocus = document.activeElement;
target.focus();
target.setSelectionRange(0, target.value.length);
// copy the selection
var succeed;
try {
succeed = document.execCommand("copy");
} catch(e) {
succeed = false;
}
// restore original focus
if (currentFocus && typeof currentFocus.focus === "function") {
currentFocus.focus();
}
if (isInput) {
// restore prior selection
elem.setSelectionRange(origSelectionStart, origSelectionEnd);
} else {
// clear temporary content
target.textContent = "";
}
return succeed;
}
<input id="copyTarget" value="Some initial text"> <button id="copyButton">Copy</button><br><br>
<div id="serial"><div>[pw_map address="New York City"</div> enablescrollwheel="false" key="YOUR API KEY"]</div> <button id="copyButton2">Copy</button><br><br>
<input id="pasteTarget"> Click in this Field and hit Ctrl+V to see what is on clipboard<br><br>
<span id="msg"></span><br>
Below code did the trick for me.
Note: Below snippet might not work as window object is not accessible.
$(function() {
$('#serial').click(function() {
window.clipboardData.setData('text', $(this).text());
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="serial">[shortcode here]</div>
You can do it like:
<div id="serial">[shortcode here]</div>
<input id="some_other_id" type="text" />
And the javascript code:
//first get text from your div and put it inside input field
//then apply code to copy that text from input field
$(document).ready(function(){
var text = $("#serial").text();
$("#some_other_id").val(text);
//your code for copying text from input field goes here
});
I have a simple input:
<input type="date" class="self-select" value="1980-05-04">
<input type="text" class="self-select" value="my birthday">
And I have a listener for all such inputs:
$(document).on('focus', '.self-select', function(){
$(this).select();
});
The idea is that when user clicks to the input field, its' contents are selected, so he needs just ctrl+c to copy.
But this doesnt work with type="date" in Chrome. There is no selection and basically no way to copy date value from an input field.
Here is the fiddle:
https://fiddle.jshell.net/Dmatafonov/s8r9dt6j/
I managed to write some kind of a "hacky" walk around...
The trick is to copy to clipboard (using this other great SO answer) while the date input type is temporarely setted to "text" on CTRL+C keydown...
It's not perfect since only a segment of the date is selected on focus...
And some users will scratch their head a little until they notice that the whole date is copied anyway.
I have no solution for this.
What's important is that copying to clipboard is works.
Try the snippet!
// Your on focus -> select event handler
$(document).on('focus', '.self-select', function(){
$(this).select();
});
// An on keydown event handler to copy to clipboard when [ctrl]+[C] is pressed
// Exclusively for the "date" inputs.
$(document).on('keydown', 'input[type="date"]', function(e){
if( e.which == 67 && e.ctrlKey ){
var copiedDate = $(this).val();
//console.log( copiedDate );
// First, get the value and fix the date format from YYYY-MM-DD to MM/DD/YYYY
var tempDate = copiedDate.split("-");
var year = tempDate.shift();
//console.log( year );
tempDate.push(year);
var fixedDate = tempDate.join("/");
console.log( fixedDate );
// Then temporarly change the input type from "date" to "text"
$(this).attr("type","text").val(fixedDate);
// Use the copy to clipboard function
$(this).select();
copyToClipboard($(this));
// Set the input type back to "date" a small delay later
var that=$(this);
setTimeout(function(){
that.attr("type","date").val(copiedDate); // And restore original value
},20)
}
});
// ---------------------------------
// A nice JavaScript "copy to clipboard" function found here : https://stackoverflow.com/a/22581382/2159528
// ---------------------------------
function copyToClipboard(elem) {
// create hidden text element, if it doesn't already exist
var targetId = "_hiddenCopyText_";
var isInput = elem.tagName === "INPUT" || elem.tagName === "TEXTAREA";
var origSelectionStart, origSelectionEnd;
if (isInput) {
// can just use the original source element for the selection and copy
target = elem;
origSelectionStart = elem.selectionStart;
origSelectionEnd = elem.selectionEnd;
} else {
// must use a temporary form element for the selection and copy
target = document.getElementById(targetId);
if (!target) {
var target = document.createElement("textarea");
target.style.position = "absolute";
target.style.left = "-9999px";
target.style.top = "0";
target.id = targetId;
document.body.appendChild(target);
}
target.textContent = elem.textContent;
}
// select the content
var currentFocus = document.activeElement;
//target.focus();
target.setSelectionRange(0, target.value.length);
// copy the selection
var succeed;
try {
succeed = document.execCommand("copy");
} catch(e) {
succeed = false;
}
// restore original focus
if (currentFocus && typeof currentFocus.focus === "function") {
currentFocus.focus();
}
if (isInput) {
// restore prior selection
elem.setSelectionRange(origSelectionStart, origSelectionEnd);
} else {
// clear temporary content
target.textContent = "";
}
return succeed;
}
/* Textarea sizing for this snippet */
#pasteIt{
width:316px;
height:150px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="date" class="self-select" value="1980-05-04">
<input type="text" class="self-select" value="my birthday">
<br>
<br>
<textarea id="pasteIt" placeholder="Paste here to test your clipboard."></textarea>
I ran into this same issue but also needed to be able to paste to another date field. I did something similar to the above but made it obvious to the user that the full date is being copied.
My use case also included the need to copy from and paste to datetime-local type fields.
https://jsfiddle.net/h444uL45/23/
var control_pressed = false;
function changeInputType(oldObject, oType) {
var newObject = document.createElement("input");
newObject.type = oType;
if(oldObject.size) {newObject.size = oldObject.size;}
if(oldObject.value) {newObject.value = oldObject.value;}
if(oldObject.name) {newObject.name = oldObject.name;}
if(oldObject.id) {newObject.id = oldObject.id;}
if(oldObject.className) {newObject.className = oldObject.className;}
oldObject.parentNode.replaceChild(newObject,oldObject);
newObject.select();
return newObject;
}
function swapToText(date_type) {
$('input[type="'+date_type+'"]').on("keydown", function(event) {
if ((event.keyCode == 17) && (control_pressed != true)) {
$(this).addClass("revert_date_to_text");
changeInputType(this, "text");
swapToDate(date_type);
control_pressed = true;
}
})
}
function swapToDate(date_type) {
$(".revert_date_to_text").on("keyup", function(event) {
if ((event.keyCode == 17) && (control_pressed != false)) {
$(this).removeClass("revert_date_to_text");
if (date_type == 'datetime-local') {
$(this).val($.format.date($(this).val().replace(/\//g,"-").replace("T"," ")+':00.000', "yyyy-MM-ddTHH:mm"));
} else {
$(this).val($.format.date($(this).val().replace(/\//g,"-"), "yyyy-MM-dd"));
}
changeInputType(this, date_type);
swapToText(date_type);
control_pressed = false;
}
})
}
$(function() {
$.getScript('https://cdnjs.cloudflare.com/ajax/libs/jquery-dateFormat/1.0/jquery.dateFormat.min.js');
swapToText('date');
swapToText('datetime-local');
});
Ok, I've been trying to build a basic combo box widget (a hidden select, an inputfield and a div for the options) that reacts to certain events like keypressed and focusin. Now I stumbled upon a problem, I can not delete characters in the input using backspace. I can delete with the delete key, I can go left and right with the left and right keys, but backspace does not work.
The following code shows my _create method of my jquery ui widget
Code:
_create: function() {
var self = this;
this.currentComboContainer = $("<div class='currentComboBoxContainer' ></div>");
this.select = this.element.hide();
this.select.wrap(this.currentComboContainer);
var selected = this.select.children(":selected"),
value = selected.val() ? selected.text() : "";
this.input = $("<input />");
this.optionsDiv = $("<div></div>");
this.input.insertAfter(this.select)
.addClass("currentComboBox");
this.optionsDiv.insertAfter(this.input)
.addClass("currentComboBox");
this.select.children().clone().appendTo(this.optionsDiv);
this._on(".currentComboBoxOptionElement", {
click: this._optionClick
});
//this.optionsDiv.delegate(".currentComboBox", "click", this._optionClick);
this.input.val(value)
.focusin(function() {
self.optionsDiv.show();
})
.focusout(function() {
self.optionsDiv.delay(200).hide(0);
})
.dblclick(function () {
CCNet.UI.wait(true);
var toId = self.input.val();
self.input.blur();
if(toId)
$.post(self.options.navigationAction + "?id=" + toId);
})
.keyup(function (keyevent) {
/*if (keyevent.which === 13) {
CCNet.UI.wait(true);
var toId = self.input.val();
self.input.blur();
if(toId)
$.post(self.options.navigationAction + "?id=" + toId);
}*/
});
var inputOffset = this.input.position();
inputOffset.top += this.input.height() + 3;
this.optionsDiv
.css(inputOffset)
.hide();
}
I'd appreciate any kind of input on the topic, thanks
I have an input form that has a jQuery event applied to it that creates square brackets around the users input. The issue is that the event prevents the ability to use backspace to delete the text. I'm looking for a way to check if backspace is being pressed and prevent the code from runnning.
jQuery Script
function test(obj) {
var oldVal = obj.val().replace(/\[/g,\'\');
oldVal = oldVal.replace(/\]/g,\'\');
var val = \'[\' + oldVal + \']\';
obj.val(val);
Input Form
oninput="test($(this));"
function test(obj,e) {
if(!(e.which == 8)){
var oldVal = obj.val().replace(/\[/g,'');
oldVal = oldVal.replace(/\]/g,'');
var val = '[' + oldVal + ']';
obj.val(val);
}
}
and pass event as parameter ..
<input class="text-box" onkeyup="test($(this),event)">