How can I continually detect if the focus is set? (Javascript, jQuery) - javascript

I'm very new to Javascript (and jQuery). My JSFiddle really shows the issue in the best way possible. http://jsfiddle.net/mkLsr/3/
I'm trying to make it so a search box text input that is focused upon page load, so a user can type into it without clicking into it. However, I also want default text in it that will disappear when the user clicks into the text input and re-appears if they click out of the text field without writing anything.
The problem is that I have other text inputs on the page, and as it is running now, if a user clicks onto one and begins typing, the focus jumps to the originally focused text input. How can I stop this from happening?
I tried using if ($('input:focus').size() == 0) to make it so it would only set the focus if no other focus has been set. Does it not work because it doesn't re-check after the page loads? How can I get it to re-check, or is there some other problem?
I think that a search box that you can automatically type into, that has a default text that is erased upon typing, is about as user friendly as you can get - but I'm really hoping to do it without expense to other input's user-friendliness.
Any help would be appreciated!
* EDIT *
Kai really helped me out with his Javascript solution and use of the "placeholder" HTML attribute. (http://jsfiddle.net/wgwTC/4/).
I'm just curious if someone knows how to apply it cross-browser so that the first text input is in focus still, but the placeholder text is there upon loading the page. Currently it works in Chrome, but not IE (I'm using 9) or Firefox (5.0). If there's a cross-browser solution, it may help others who want the same or similar functionality on future projects.

Here's a solution that uses the placeholder attribute but will fallback to JS for IE <= 9: (See http://jsfiddle.net/wgwTC/2/ for working example):
// Focus on this box by default
$('#header-search-box').focus();
// Support placeholder text for IE <= 9 (which doesn't support placeholder attribute)
if ( $.browser.msie && (parseInt($.browser.version, 10) <= 9) ) {
$('input[name=search]').attr('value', 'Search New Equipment...');
// Set placeholder text on blur
$('input[name=search]').on('blur', function (e) {
if (!e.currentTarget.value.length) {
e.currentTarget.value = 'Search New Equipment...';
}
});
// Clear placeholder text on focus
$('input[name=search]').on('focus', function (e) {
if (e.currentTarget.value === 'Search New Equipment...') {
e.currentTarget.value = '';
}
});
}

I think this does what you're asking (assuming I understand you correctly).
Here's the fiddle: http://jsfiddle.net/jVvX3/2/

Related

How to detect if selected text is in an editable area?

The coder's fantasy
I created a simple user script to act very quickly on the text I selected. It goes like this:
I select a word, a website (doesn't have to be a link), or a phrase from, let's say, a p element
When I press the trigger key, the algorithm will try to figure out if it's a website or text. It will open a tab: if it's a website, that's what it'll load; if it's text, it will google it.
The problem shows its ugly head
It works great except when I'm editing text. If I'm editing something I've written in a textarea/input it will fire, potentially losing what I wrote. Fortunately, there's usually cache, or even the site will warn me for having unsaved changes, which saves me from losing whatever I wrote. But it's something to fix.
The challenge
The userscript should only run on text that can't be edited. You'd think it is as easy as not calling the function if the selected text is within a textarea. But there are many ways to display editable content without using classical elements. The "best" filter I've found is to check for document.activeElement.isContentEditable. However, in this very box, that returns false. This is a textarea element, so I can add it to the filter, and I can do so with a few more I can think of. But apart from being an ugly solution, it is not foolproof.
Besides adding a "did you run me by accident?" prompt, is there a better way to do this?
Edit: my current code
If I understand correctly .... here is an example of how to go about it.
if (['TEXTAREA', 'INPUT'].includes(document.activeElement.nodeName)) {
// it is in textarea, input
}
else if (document.activeElement.isContentEditable) {
// it is in contentEditable element
}
else {
// not above
}
Above is not the only method, e.g. the following using window.getSelection():
const sel = window.getSelection();
const text = sel.toString();
if (!text.trim()) {
// there is no selection
// or selection is white-space
// or selection is in textarea, input
}
else if (document.activeElement.isContentEditable) {
// it is in contentEditable element
}
else {
// not above
}

How to detect where in an input element user has clicked

Is there a way to detect where in an input element's content a user has clicked? Specifically in Firefox?
I need to know not where the caret is but where the caret would be when the user clicks into an input element.
I am trying to fix a bug in firefox where the user cannot click to place the caret into an input element which has had '.select()' called on it -- the caret fails to appear in firefox, so I want to place it manually if possible.
Thanks!
You can get the pixel position of the user's click (relative to the input field) by reading the click event's offsetX and offsetY:
// get the click position:
document.getElementById('test').onclick = function(e) {
console.log(e.offsetX, e.offsetY)
};
// for testing the 'select' issue:
document.getElementById('btn').onclick = function() {
document.getElementById('test').select();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="test">xxxxxx</textarea>
<button id="btn">Select</button>
Converting that to the desired caret location is not easy, though, because it will depend on font sizes and the text content of the input field. The best I can think of would be to do something like the technique used in textarea-caret-position, except iterating through every possible caret position in the textarea to find the one closest to where the user clicked. Which is almost certainly overkill for the task you have in mind.
(For what it's worth, the current version of firefox (v57) does not seem to have any trouble placing the caret correctly whether the input field is selected or not. I'm not certain whether this was the case in previous versions.)
Found the root of the problem, some bad css had set text-select to auto on input elements. Changing it to text-select:text allowed the fix I used for Safari to work in Firefox as well.

Moving caret in the contents of a read-only div allowing for dynamic highlighting

I've been struggling with getting a field working properly. This field displays a lot of data, and the user wants to select and copy a large portion of it. The data is basically a big list and the user wants to select all entries below a certain point. The way that they achieve the selection is by highlighting a word or two in the first entry they want then pressing ctrl+shft+end to select everything to the bottom. This was working until a new feature on the page was added below the contents of the list. Now the hot key select also selects the contents of the rest of the page.
The current implementation is simply :
<div id='diff-contents'>[content here]</div>
<div id='trailing-content'>blah blah blah...</div>
I have tried a read-only input field:
<input id='diff-contents' value='[content here]' readonly/>
This works in Firefox to some extent however the contents contains HTML, and the input field show html literally, not rendered. In addition to that Chrome doesn't show a blinking caret and the hot keys do nothing, so the input field is sadly not viable for me in this situation.
How can I make a selectable field that maintains focus for the cursor and shows a blinking caret but is not editable using javascript, CSS, HTML, or JQuery?
Edit: jsfiddle example that should clarify a bit.
Look at these questions how to determine the current selection: Getting selected text in a browser, cross-platform
The next step is to create a new range which starts at the end tag of #diff-contents. With this information, you should be able to extend/modify the existing selection.
I suggest to either add a button to the UI or use JavaScript with a key-press handler to trigger this code.
With that, the correct amount of HTML should be selected. Users can then copy that into the clipboard with Ctrl+C.
#Aaron Digulla mentioned key listeners, and that got me thinking about simply stopping the events.
The diff-content element is still a div but it is set to editable. This gives both HTML rendering and a blinking caret.
$(this).keydown(function (event) {
if (document.activeElement.id == 'diff-content') {
if (!allowedKeys(event.keyCode)) {
//The only other key presses that should be processed are ctrl+c (keycode 67) and ctrl+a (65)
if (!event.ctrlKey || !(event.keyCode == 67 || event.keyCode == 65)) {
event.preventDefault();
}
}
}
});
The javascript adds a keydown event listener to the entire page. This is necessary since if you just add it to the element, the event has already propagated through the rest of the page and will still be processed, and this was causing funny issues for me. Next we check if it's the diff-content that is active since we want other input elements to still operate normally. Then we check if the key event is an allowed key (tab, home, end, arrows). And finally, check for ctrl+c and ctrl+a and allow those too. I tried event.stopPropogation() and event.stopImmediatePropogation(), and neither of those worked, but preventDefault did.
Lastly, I added style="outline-style:none" to the element so that the blue border would not appear when the element has focus.
The only issue that I have yet to resolve is that since it is editable, the browser still allows you to select and then right click to either cut or paste, which will allow you to alter the text.
Here is the final jsfiddle for what I am using: http://jsfiddle.net/wh3nzmj8/12/

Problem getting selected text when using a sprited button and selection.createRange() in Internet Explorer

I'm working on implementing sprited buttons in Stackoverflow's beloved WMD markdown editor and I've run into an odd bug. On all versions of IE, the selected text is lost upon button clicks, so, say, highlighting a block of text and clicking the code button acts like you placed the cursor at the end of the selection and clicked the button.
e.g. highlighting this:
This
Is
Code
and clicking the code button give you:
This
Is
Code`enter code here`
What's really weird is that I left the original non-sprited button bar in and that works just fine. In fact ALL buttons and keyboard shortcuts code use the same doClick(button) function!
Old-style non-sprited buttons: OK
Keyboard shortcuts: OK
Sprited buttons in non-IE browsers: OK
Sprited buttons in IE: WTF
I've isolated the problem down to a call to selection.createRange() which finds nothing only when the sprited button is clicked. I've tried screwing around with focus()ing and making sure as little as possible happens before the doClick() but no joy. The keyboard shortcuts seem to work because the focus is never lost from the input textarea. Can anyone think of a hack that will let me somehow collect the selected text in IE?
The onclick handler looks like this:
button.onmouseout = function(){
this.style.backgroundPosition = this.XShift + " " + normalYShift;
};
button.onclick = function() {
if (this.onmouseout) {
this.onmouseout();
}
doClick(this);
}
I've tried moving the onmouseout call to after the doClick in case that was causing a loss of focus but that's not the problem.
EDIT:
The only thing that seems to be different is that, in the original button code, you are clicking on an image. In the sprited code, you are clicking on a list item <li> with a background image set. Perhaps it's trying to select the non-existent text in my list item?
/EDIT
Actual code is located in my wmd repository on git in the button-cleanup branch.
If you revert to the 0d6d1b32bb42a6bd1d4ac4e409a19fdfe8f1ffcc commit you can see both button bars. The top one is sprited and exhibits the weird behavior. The bottom one contains the remnants of the original button bar and works fine. The suspect code is in the setInputAreaSelectionStartEnd() function in the TextareaState object.
One last thing I should mention is that, for the time being, I'm trying to keep the control in pure Javascript so I'd like to avoid fixing this with an external library like jQuery if that's possible.
Thanks for your help!
I know what the answer to my own question is.
The sprited buttons are implemented using an HTML list and CSS, where all the list items have a background image. The background image is moved around using CSS to show different buttons and states (like mouseover highlights). Standard CSS button spriting stuff.
This works fine in IE with one exception: IE tries to select the empty list text when you click on the background image "button". The selection in the input textarea goes away and the current selection (which will be returned by document.selection.createRange()) is moved to the empty text in the list item.
The fix for this is simple - I created a variable to cache the selection and a flag. In IE I cache the selection and set the flag in a mousedown event handler. In the text processing, I check for the presence of the flag - if it's set I use the cached range instead of querying document.selection.createRange().
Here are some code snippets:
wmd.ieCachedRange = null;
wmd.ieRetardedClick = false;
if(global.isIE) {
button.onmousedown = function() {
wmd.ieRetardedClick = true;
wmd.ieCachedRange = document.selection.createRange();
};
}
var range;
if(wmd.ieRetardedClick && wmd.ieCachedRange) {
range = wmd.ieCachedRange;
wmd.ieRetardedClick = false;
}
else {
range = doc.selection.createRange();
}
The solution is only a few lines of code and avoids messing around with the DOM and potentially creating layout engine issues.
Thanks for your help, Cristoph. I came up with the answer while thinking and googling about your answer.
You have to blur() a button before IE can select anything else on a page.
Can you provide a minimal example (only containing relevant code) which reproduces the bug?

Firefox 3.03 and contentEditable

I'm using the contentEditable attribute on a DIV element in Firefox 3.03. Setting it to true allows me to edit the text content of the DIV, as expected.
Then, when I set contentEditable to "false", the div is no longer editable, also as expected.
However the flashing caret (text input cursor) remains visible even though the text is no longer editable. The caret is now also visible when I click on most other text in the same page, even in normal text paragraphs.
Has anyone seen this before? Is there any way to force the caret hidden?
(When I either resize the browser or click within another application, and come back, the caret magically disappears.)
I've dealt with this and my workaround is clearing the selection when I disable contentEditable:
if ($.browser.mozilla) { // replace with browser detection of your choice
window.getSelection().removeAllRanges();
}
I am actually removing the "contenteditable" attribute for browsers other than IE, rather than setting it to false:
if ($.browser.msie) {
element.contentEditable = false;
}
else {
$(element).removeAttr( 'contenteditable' );
}
The browsers manage the contentEditable attribute inconsistently and my testing revealed that this worked better overall. I don't remember if this contributed to fixing the caret problem, but I'm throwing it in here just in case.
The style attribute -moz-user-input can be used in Firefox to get the functionality contenteditable=false working.
The value assigned defines if user input is accepted. The possible values are
none : The element does not respond to user input.
enabled : The element can accepts user input. This is default.
disabled : The element does not accept user input.
E.g.:
// to disallow users to enter input
<asp:TextBox ID="uxFromDate" runat="server" style="-moz-user-input: disabled;"></asp:TextBox>
// to allow users to enter input
<asp:TextBox ID="uxFromDate" runat="server" style="-moz-user-input: enabled ;"></asp:TextBox>
Refer to https://developer.mozilla.org/en/CSS/-moz-user-input for further reference.
This solve the ploblem, looks like firefox is just checking is own way to make things :P
getDoc().designMode = "off";

Categories