Use escape key to cancel inline tinyMCE edit - javascript

I'd like a user to be able to use the escape key to abort any changes in a tinyMCE editor in inline mode. Here's the HTML:
<div id="tinymce">
<p>Foo Foo Foo</p>
</div>
And the script:
tinymce.init({
selector: '#tinymce',
inline: true,
setup: function (editor) {
editor.on('keydown', ((e) => {
var tinyMceEditor = tinyMCE.get(e.target.id);
if (e.keyCode === 27) { // escape
// This will hide the editor but it won't come back when trying to re-edit
tinyMceEditor.hide();
}
}));
}
});
It's also a jsfiddle: http://jsfiddle.net/kfnyqufm/
Hitting escape closes the editor like I want but has two issues: (1) the editor doesn't return when clicking the text (2) any edited text doesn't revert to the original value

(1) the editor doesn't return when clicking the text
This happens because you are hiding the editor completely when esc is pressed, and not showing it again. You have (at least) two options to solve this:
Show the editor when the #tinymce div gets focus again; or
Trigger the blur() method on the #tinymce when esc is pressed (that will automatically hide the editor, and it will come back on click again)
If you go with the second option (I think it would be simpler), the code would be like this (only the part related to the escape button):
if (e.keyCode === 27) { // escape
document.getElementById("tinymce").blur();
}
You can also see it on this version of your JSFiddle.
(2) any edited text doesn't revert to the original value
This is a bit trickier (but still simple) as you'll need to keep track of the old value and restore if esc is pressed. The logic for this would be:
When the #tinymce div gets focus: save the inner HTML into a JavaScript variable (or in the localStorage or sessionStorage).
When the escape key is pressed: restore the saved value as the inner HTML of #tinymce.
The code would be something like this for storing the old value:
// define a variable to store the old value
var old_value = "";
// save the old value when #tinymce gets focus
document.getElementById("tinymce").addEventListener("focus", function() {
old_value = document.getElementById("tinymce").innerHTML;
}, false);
And then you'd need to also restore the old value when esc is pressed:
if (e.keyCode === 27) { // escape
// blur the tinymce div and restore the old value
document.getElementById("tinymce").blur();
document.getElementById("tinymce").innerHTML = old_value;
}
You can see it fully working on this version of your JSFiddle.

Related

Block modal with "data-backdrop" and "data-keyboard" on runtime?

I would like to block the user from exiting the modal on clicking outside or pressing ESC when an input has been changed, my attempt being:
$("#cadastroModal input, #cadastroModal textarea, #cadastroModal select").on('change input select select2:select', function() {
$('#cadastroModal').attr('data-backdrop', 'static');
$('#cadastroModal').attr('data-keyboard', false);
});
And while the element does change in runtime (as checked with chrome inspect element), it seems like it doesn't respect the data attributes if its already open. How can I fix this?
Apparently you need to use _config as shown here
This worked:
$('#cadastroModal').data('bs.modal')._config.backdrop = 'static';
$('#cadastroModal').data('bs.modal')._config.keyboard = false;

Safari issue with text inputs, text is selected as user enters it causing text to be lost

I have the following input element on my page:
<input class="input" name="custom_fields[new]" placeholder="Enter placeholder" type="text">
I have a Twitter Flight event listener on this element that looks like this:
this.on('keyup', {
inputsSelector: this.updateViewInputs
});
Which triggers this method:
this.updateViewInputs = function(ev) {
var isDeletionKeycode = (ev.keyCode == 8 || ev.keyCode == 46);
// Remove field is user is trying to delete it
if (isDeletionKeycode && this.shouldDeleteInput(ev.target.value, this.select('inputsSelector').length)) {
$(ev.target.parentNode).remove();
}
// Add another field dynamically
if (this.select('lastInputsSelector')[0] && (ev.target == this.select('lastInputSelector')[0]) && !isDeletionKeycode) {
this.select('inputsContainer').append(InputTemplate());
}
// Render fields
that.trigger('uiUpdateInputs', {
inputs: that.collectInputs()
});
}
And finally triggers uiUpdateInputs:
this.after('initialize', function() {
this.on(document, 'uiUpdateInputs', this.updateInputs)
});
this.updateInputs = function(ev, data) {
// Render all inputs provided by user
this.select('inputListSelector').html(InputsTemplate({ inputs: data.inputs }));
}
All of this functionality works as expected on Chrome and Firefox. Users can type into the input and see the page change in 'real time'. Users also get additional fields that they can enter text into and see the page change.
The issue in question arises when using Safari, as a user enters text into the described input field the text in the input field becomes highlighted (selected) and when they enter the next character all the content is replaced with that single character. This results in the user not being able to enter more than 1 or 2 characters before having them all replaced by the next entered character.
I have tried several approaches to fix this problem but none have worked, they include:
Using a setTimeout to delay the code run on the keyup event
Using Selection to try to disable the selection of the text using collapseToEnd.
Using click,focus,blur events to try to remove the selection from the entered text
Triggering a right arrow key event to try to simply move the cursor forward so they user does not delete the selected text
Using setInterval to routinely remove selections made by the window
I am very confused why this is happening and I am wondering if this is a bug in webkit with Flight. I see no issue with the Firefox or Chrome versions of this page. Thanks for any help!
This seems to be an issue with certain versions of Safari. When listening for the keyup function in javascript it will automatically select all of the text in the box and subsequently delete it all when the next key is typed. To prevent this from happening call preventDefault on the event object that is passed to the keyup function.
this.on('keyup', function(e) {
e.preventDefault()
});

Disable and re-enable user input without leaving textarea

I have been working on a small personal project that requires me to be able to enable and disable text input in a textarea through key commands. It will function similar to the way Vi/Vim handle insertion and command mode.
I cannot seem to figure out an elegant way to perform this task. Setting the textarea to disabled means that the user can no longer move their cursor caret through the text. Setting the keydown event to return false works for disabling the field, but obviously cannot re-enable it because it will instantly return false before reaching any other logic.
If there is any logic prior to the return false then the textarea takes the character input. I had attempted a version which accepts this input and instantly reverts it if it's not set to insertion mode, but this feels clunky and caused more problems than it was worth (plus it's not really instant...)
I am not familiar with Vi/Vim but I think you are trying to achieve something like this:
http://jsfiddle.net/FSjTa/
$('#text').keydown(function() {
if ($(this).hasClass('command-mode')) {
return false;
}
});
$('#btn-toggle').click(function() {
$text = $('#text');
if ($text.hasClass('input-mode')) {
$text.removeClass('input-mode');
$text.addClass('command-mode');
$(this).html('command mode');
} else {
$text.removeClass('command-mode');
$text.addClass('input-mode');
$(this).html('input mode');
}
});
I think the code should explain itself. If not, feel free to ask!
Using JQuery:
var txt = $("#txt");
txt.on("keyup",function(e){
//Hit shift to disable
if (e.keyCode === 16){
$(this).attr("disabled","disabled");
}
});
$("body").on("keyup",function(e){
//Hit enter to enable
if (e.keyCode === 13){
txt.removeAttr("disabled","");
}
});
Here is a demo:
http://jsfiddle.net/JMyTY/1/
I made a fiddle of this, just a simple demo, hitting d disables the field and hitting e enables it. Other characters can be entered while enabled. http://jsfiddle.net/gKDDh/1/
Try this, set a hidden field that contains the same text as the textarea. Now never actually disable the textarea, just maybe change the background color or text color so the user can differentiate between disabled and not. Then setup your logic like this.
onkeydown {
if (state == disabled and hidden field value <> textarea value) {
copy value from hidden field to textarea
}
else if (state == enabled) {
copy value from textarea to hidden field
}
basically what we are doing is keeping constant track of what the value should be, and only allowing a change when the state is enabled.

How to disable tab key globally except for all forms in a page with JavaScript?

I'm making a single page app that is launching next week, for a pretty huge client, and going live for a pretty big event and well, there's still a ton to finish before then.
There's 100+ 'pages' which are all loaded within a single 700px x 600px window, and I had learned not long ago you could tab through the page/sections, which in-turn would break the app because it would bring focus to hidden off-screen elements, so for this reason, I disabled the tab key for the entire app.
But now there are a couple places where we have a form with a handful of input fields which you are not able to tab through as you fill in the form. It's a pain in the ass.
I need to make it so you can tab through the form fields, but only the form fields. I have the tabindex attribute set for the form, and have tried to make inputs tab enabled but was not able to make it work without causing the app to jump to hidden sections.
Here's the function I need to change so it will disable tab key except from input to input fields in a form.
window.onkeydown = function(e) {
if (e.keyCode === tab) {
return false;
}
}
I tried to do this, which obv didnt work lol
$('input').keydown(function(e) {
if (e.keyCode === tab) {
return true;
}
});
Thanks :)
I made some fixes to what #Joseph posted for an answer to this that handle being able to shift + tab through inputs of a form so you can reverse direction. It was a very annoying thing for me before when I first had to find a way to do this, and didn't have time to waste anymore trying to find a complete solution for this until now. Here it is.
$(function() {
// gather all inputs of selected types
var inputs = $('input, textarea, select, button'), inputTo;
// bind on keydown
inputs.on('keydown', function(e) {
// if we pressed the tab
if (e.keyCode == 9 || e.which == 9) {
// prevent default tab action
e.preventDefault();
if (e.shiftKey) {
// get previous input based on the current input
inputTo = inputs.get(inputs.index(this) - 1);
} else {
// get next input based on the current input
inputTo = inputs.get(inputs.index(this) + 1);
}
// move focus to inputTo, otherwise focus first input
if (inputTo) {
inputTo.focus();
} else {
inputs[0].focus();
}
}
});
});
Demo of it working http://jsfiddle.net/jaredwilli/JdJPs/
Have you tried setting tabIndex="-1" on all elements that you don't want to be able to tab to? I think that's a much better solution.
Otherwise, within your key handler function test event.target (or event.srcElement in IE) to see if the event originated with a form element. You seem to be using jQuery, so you could assign an "allowTab" class just to the fields in your form and then do this:
$(document).keydown(function(e) {
if (!$(e.target).hasClass("allowTab"))
return false;
});
Or
if (e.target.tagName !== "input")
// etc
what we do is to determine what input is next in line and skip to it!:
http://jsfiddle.net/qXDvd/
$(document).ready(function() {
//gather all inputs of selected types
var inputs = $('input, textarea, select, button');
//bind on keydown
inputs.on('keydown', function(e) {
//if we pressed the tab
if (e.keyCode == 9 || e.which == 9) {
//prevent default tab action
e.preventDefault();
//get next input based on the current input we left off
var nextInput = inputs.get(inputs.index(this) + 1);
//if we have a next input, go to it. or go back
if (nextInput) {
nextInput.focus();
}
else{
inputs[0].focus();
}
}
});
});​
may need some optimization but it works. this was originally meant to skip non-form elements. you can add selectors not to skip if you like. additionally, you can add logic for the Shift+Tab behavior (maybe before the tab logic)
obviously, it will still go through some elements according to how they appear in the source. however, why not just remove those hidden elements from the DOM but still keep track of them using the methods found in this question. that way, you won't have the pain of having to cycle back and forth through off-screen elements.

Hook paste event to hidden textarea

I want to hook paste event for <input type="text"> and force this text to be pasted into hidden textarea (then I want to parse textarea's text and perform 'paste data from excel to gridview' action). Something like:
$('#input1').bind('paste', function(e) {
// code do paste text to textarea instead of originally targeted input
});
What cross-browser code should I write instead of comments?
Thanks.
There is this hacky solution that fires a focus event on a textarea when Ctrl and V keys or Shift and Insert keys are down. [Yes, it doesn't work for contextmenu -> past]
$(document).ready(function(){
var activeOnPaste = null;
$('#input1').keydown(function(e){
var code = e.which || e.keyCode;
if((e.ctrlKey && code == 86) || (e.shiftKey && code == 45)){
activeOnPaste = $(this);
$('#textarea').val('').focus();
}
});
$('#textarea').keyup(function(){
if(activeOnPaste != null){
$(activeOnPaste).focus();
activeOnPaste = null;
}
});
});
The code lets the pointer focus on a textarea when Ctrl and V keys are down. At that moment no text is pasted, it's pasted after this keydown function is fired so the pasted text is shown in the textarea. After that, on keyup on that textarea, #input1 will be focused.
While typing this, I see that there may be a solution for both keyboard pasting and mouse pasting, using ranges. I'll try something with that too...
You should bind a function to your input-fields onChange() event and copy its content everytime this function is called and process the data afterwards. If you are specifically interested in "pasted" content (I do not know what you are trying to do there, but generally it is a sign of bad concept to be in a situation where pasted content has to be treated additionally) you can try implementing a counter that checks the input speed (eg more than xx characters per second -> PASTE-Eventcall)

Categories