Disable and re-enable user input without leaving textarea - javascript

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.

Related

Qualtrics Javascript focus / select / place cursor on text box when page loads

I am trying to make Qualtrics focus automatically on a text box (single question per page) so participants can start typing right away.
I have tried different things from other answers (e.g.,Qualtrics: Automatic blinking cursor (focus) does not work on JFE, only on SE surveybuilder) but the focusing doesn't work on browsers like IE (Firefox, without including code, automatically focuses on the question).
The code also seems to invalidate code for advancing to next page by pressing "Enter" (below), so the survey gets stuck on the page
Qualtrics.SurveyEngine.addOnload(function()
{
this.hideNextButton();
this.hidePreviousButton();
var that = this;
Event.observe(document, 'keydown', function keydownCallback(e) {
var choiceID = null;
switch (e.keyCode) {
case 13: // 'enter' was pressed
choiceID = 1;
break;
}
if (choiceID) {
Event.stopObserving(document, 'keydown', keydownCallback);
that.clickNextButton();
}
});
});
Any ideas how to fix this? thank you!
The problem with your code may be hideNextButton with addOnload due to timing issues. Use addOnReady instead. Also, it is best to check for the existence of the PreviousButton first. If is is not there it will cause an error and stop your script. On some browsers you have to select a field before you can focus on it, activate() does that. Finally, it is better to add your event handler to the text field, instead of the document.
Try this:
Qualtrics.SurveyEngine.addOnReady(function()
{
$('NextButton').hide();
if($('PreviousButton')) $('PreviousButton').hide();
var inputText = $(this.questionId).down('.InputText');
var evt = inputText.on('keydown', function(e) {
if(e.which == 13) {
evt.stop();
$('NextButton').click();
}
});
inputText.activate();
});
Is there any way to have the cursor placed in the first text box, say for a form field in Qualtrics? I need people to input their contact information (street address, city, state etc.) and I'd like the cursor to be automatically placed in the top box. I can do it with single questions but haven't figured out how to do it with the form field.
Thanks!

Use escape key to cancel inline tinyMCE edit

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.

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()
});

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.

How do write a JavaScript function that allows for non-editable textbox?

I need to have an input textbox in which I can click and the cursor starts blinking but the user cannot change any text inside it.
I tried using "readonly" or "disabled" attributes, but they do not allow the cursor to be inside the textbox. So, I was thinking of a solution to implement in JavaScript on a normal textbox. Is there a plugin that already do this? How do I implement this?
EDIT: Thanks for all the answers, but I wanted to make the textarea/input type text as uneditable but selectable at the same time. Pressing Ctrl + A inside the textbox doesn't work. Is it possible to get the changed value and the old value and compare them and then return false if the values are different, but in all other cases return true so that the Ctrl + A, Shift + end, etc. combinations work?
Something like this:
<textarea onkeydown="javascript:return false;"></textarea>
would do the trick. (jsfiddle)
You can also do that at runtime if you want to:
<textarea class="readonly"></textarea>
with
$(".readonly").keydown(function() false);
The onkeydown callback captures keystroke events and cancels them using return false;.
Depending on what you are trying to do, you may want to prevent other kind of events, since it is still possible to change the contents with the mouse, for instance.
Your callback function can accept or cancel events depending of the kind of keystroke. For example, to enable only ctrl-a and ctrl-c (with jQuery):
function keydown(e) {
if(!e.ctrlKey) return false; // Cancel non ctrl-modified keystrokes
if(e.keyCode == 65) return true;// 65 = 'a'
if(e.keyCode == 67) return true;// 67 = 'c'
return false;
}
$(function(){
$("inputSelector").keydown(function(){ return false; });
});
You cannot rely on disabling a <textarea> as a user input, as it's trivial to remove any sort of HTML or javascript disabling with firebug, or other tools. Remember that forms aren't limited to the fields you give them, anyone can submit any data to a page.
Disabled inputs are not submitted with a form anyway, bearing that in mind my advice would be to not use a textarea and just print it out.

Categories