How to make cursor pointer while pointer-events is none - javascript

I have input type="text" associated with a datalist, and I want to add a fixed arrow (svg) in the input box so that when someone clicks it the datalist opens (as they clicked the box).
The problem is that the arrow I added has its default cursor-events so by default when I click it the datalist doesn't open.
I changed the cursor-events to none, the problem is solved but the cursor now is text, I want it to be pointer whenever mouse is over the arrow and text whenever mouse is over the box.
I tried the solution here: https://stackoverflow.com/a/25654479/7867670 but it didn't work for me
I tried to add an onclick event listener to the arrow and to trigger input click whenever the arrow is clicked, didn't work too.
input::-webkit-calendar-picker-indicator {
display: none !important;
}
.wrapper{
position: relative;
display: inline;
left: -25px;
cursor: pointer;
}
.wrapper svg{
pointer-events: none;
}
<input type="text" list="mylist" name="inp" />
<div class="wrapper" onclick="getElementsByName('inp')[0].click();">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M16.293 9.293L12 13.586L7.707 9.293l-1.414 1.414L12 16.414l5.707-5.707z" />
</svg>
</div>
<datalist id="mylist">
<option value="1"></option>
<option value="2"></option>
<option value="3"></option>
</datalist>

As far as I know, this is not possible without JavaScript.
The arrow can only change the cursor if it has pointer-events that is not none, but then the input won't get the click.
input can't have children so that is also not an option.
All of the search results indicate that the datalist can't be opened (reliably?) with JavaScript or html only solutions.
The only thing that comes to my mind is to change the cursor programmatically:
function isEventInElement(event, element) {
var rect = element.getBoundingClientRect();
var x = event.clientX;
if (x < rect.left || x >= rect.right) return false;
var y = event.clientY;
if (y < rect.top || y >= rect.bottom) return false;
return true;
}
const inputElement = document.querySelector('[name="inp"]')
const inputElementArrow = document.querySelector('.wrapper')
inputElement.addEventListener('mousemove', (evt) => {
if (isEventInElement(evt, inputElementArrow)) {
inputElement.style.cursor = 'pointer'
} else {
inputElement.style.cursor = null;
}
})
input::-webkit-calendar-picker-indicator {
display: none !important;
}
.wrapper {
position: relative;
display: inline;
left: -25px;
pointer-events: none;
}
.wrapper svg {}
<input type="text" list="mylist" name="inp" />
<div class="wrapper" onclick="getElementsByName('inp')[0].click();">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M16.293 9.293L12 13.586L7.707 9.293l-1.414 1.414L12 16.414l5.707-5.707z" />
</svg>
</div>
<datalist id="mylist">
<option value="1"></option>
<option value="2"></option>
<option value="3"></option>
</datalist>
Code form other answers:
isEventInElement: Detect if a mouse event occurred inside an element's client area

You would want to set the input's cursor via css. Preferably add a css class to the input cursor-pointer and create some css for that selector.
.cursor-pointer {
cursor: pointer !important;
}
If I'm not mistaken, it sounds like you're not expecting the user to type in the input field but rather click it like a dropdown. If that's the case I would recommend using a button to trigger the list, if possible.

Related

Why doesn't setting an input type="number" to type="text" in an mouseout event handler working?

Goal:
I have an input element in which the user should enter a number between 1 and 999, optionally may use the (input type="number") up/down spinner, but when the mouse isn't over this element or the element doesn't have the focus, I want the input element to be of 'text' type to ensure that the input is sized to only show the element's value without the spinner showing or the blank area of the hidden spinner. This way the value in the input element and the text to the right of the element doesn't move whether the element is of type 'text' or 'number', the element has the focus or not, or the mouse is over the element or not.
Background:
Currently, I'm initially setting the input element's type to 'text', margin-left to '2ch', and width to '4ch', then when the mouse is over the element, I set the element's type to 'number', margin-left to '0', and width to '6ch'. When the mouse moves off of the element or the element looses focus, I set these properties back to their initial values.
Code:
<style>
/* Number text (1/3 etc) */
.numbertext { color: #f2f2f2; font-size: 12px; padding: 8px 12px; position: absolute; top: -90px; }
</style>
<div class="numbertext">
<input type="text" style="text-align: right; margin-left: 2ch; width: 4ch;" min="1" max="999" value="1"
onmouseover="setInputType( 'number' );"
mouseout="setInputType( 'text' );"
onblur="setInputType( 'text' );" />/
<span>999</span>
</div>
<script>
function setInputType( type ) {
var input = window.event.currentTarget;
if( type === 'text' ) {
input.style.marginLeft = '2ch';
input.style.width = '4ch';
}
else {
input.style.marginLeft = '0';
input.style.width = '6ch';
}
input.type = type;
}
</script>
Problem:
When the page initially shows, the code displays the way that I want, hovering the cursor over the field or focusing on it works, too. However, moving the mouse away from the field after the mouse hovered over the it, or the field looses the focus, inconsistently restores the initial setting of the input element because the mouseout and blur event handlers aren't always triggering. I know this because putting a breakpoint on the setInputType function's if( type === 'text' ) statement branch and running the code in the Chrome inspect > source panel doesn't stop the code execution when the mouse moves away from the element after it mouse was moved over it.
Any ideas about why the mouseout and blur event handlers aren't properly working consistently?
Solution:
This CodePage shows a fully working solution that includes Bryan Elliott's correction and Jon P's suggestion.
Thanks
On your element events, you have mouseout="...", It needs to be: onmouseout="..."
Like this:
<input
type="text"
style="text-align: right; margin-left: 2ch; width: 4ch;"
min="1" max="999"
value="1"
onmouseover="setInputType( 'number' );"
onmouseout="setInputType( 'text' );" //notice the onmouseout="" instead of mouseout=""
onblur="setInputType( 'text' );"
/>
Use event listeners to bind the events unobtrusively. Then use event.type to determine what action to take.
//Get the relevent elements
let numText = document.querySelectorAll(".numbertext input[type='text']");
//Loop them
for (var i = 0; i < numText.length; i++) {
//Now loop the event types we're interested in
"blur focus mouseenter mouseleave".split(" ").forEach(function(e) {
//and add the event listener for that event type
numText[i].addEventListener(e, setInputType);
})
}
//Event listener
function setInputType(event) {
var type = "text";
//Dont change on mouse leave if the element has focus
if(event.type == "blur" || (event.type == "mouseleave" && this != document.activeElement )) {
this.style.marginLeft = '2ch';
this.style.width = '4ch';
type = "text";
} else {
this.style.marginLeft = '0';
this.style.width = '6ch';
type = "number";
}
this.type = type ;
}
.numbertext {
color: #f2f2f2;
font-size: 12px;
padding: 8px 12px;
/*position: absolute;
top: -90px;*/
}
<div class="numbertext">
<input type="text" style="text-align: right; margin-left: 2ch; width: 4ch;" min="1" max="999" value="1" />/
<span>999</span>
</div>
<div class="numbertext">
<input type="text" style="text-align: right; margin-left: 2ch; width: 4ch;" min="1" max="999" value="1" />/
<span>999</span>
</div>

Change the line height of the selected text with Javascript

I am trying to program my own WYSIWYG editor as a summer project. I am trying to implement the line height function that controls(single spacing, double spacing, etc). I have created the dropdown that will allow users to select between the types of spacing. However, I cannot seem to get the right Javascript, because the selected text does not change in line spacing at all no matter which option I choose. Can someone please take a look at my Javascript and tell me where I went wrong? If possible, can you give me the correct code for the Javascript so I can refer off of it? Thank you!
HTML(working):
<select id="lineHeight" onchange="spacing(this)">
<option value="20px">20px</option>
<option value="80px">80px</option>
<option value="100px">100px</option>
<option value="200px">200px</option>
</select>
Javascript(not working)
function spacing(sel) {
var text = editor.document.getSelection();
text.style.lineHeight = sel.value;
}
If I understand what you're trying to do, perhaps this will work for you:
function changeStyle( property, value ) {
if ( window.getSelection().rangeCount ) {
var range = window.getSelection().getRangeAt( 0 ),
contents = range.extractContents(),
span = document.createElement( 'span' );
span.style[ property ] = value;
span.appendChild( contents );
range.insertNode( span );
window.getSelection().removeAllRanges()
}
}
#editor {
width: 350px;
max-height: 100px;
padding: 20px;
overflow-y: auto;
background-color: #efefef;
border: 1px solid #ddd
}
<p>
<label for="lineHeight">Line Height: </label>
<select id="lineHeight" onchange="changeStyle('line-height', this.value)">
<option value="20px">20px</option>
<option value="80px">80px</option>
<option value="100px">100px</option>
<option value="200px">200px</option>
</select>
<button onclick="changeStyle('font-weight', 'bold')">Bold</button>
<button onclick="changeStyle('font-style', 'italic')">Italic</button>
<button onclick="changeStyle('color', 'red')">Color</button>
<button onclick="changeStyle('background-color', 'yellow')">Background</button>
</p>
<div id="editor" contenteditable>Change the line height of the selected text with Javascript:<br>Please note that this example should be completed.</div>

onMouseMove + onMouseDown to call function

I have a real problem over here. I want a function to get called only when an object is clicked and when when the mouse is moved over the object. Here is a (syntax-retarded) example to get your understanding:
<div onMouseMove+onMouseDown="function()" ... ></div>
I was thinking of a way to solve this. What if I make a onMouseDown that trigger a function that will change the name of my onMouseMove - function, and use a "filler" or a "substitute" function? Let me explain:
<div id="object" onMouseMove="substituteFiller()" onMouseDown="nameChanger()" ... ></div>
<script>
function nameChanger(){
document.getElementById("object").onMouseMove = "theRealFunction()";
}
</script>
<script>
function theRealFunction() ...
When I move the mouse over the object nothing will happen, because the function substituteFiller() won't work. But, when the mouse has clicked on the object the onMouseMove- function will be the correct one, theRealFunction(), and theRealFunction() will now get called when the mouse moves.
This way I could activate/call theRealFunction() only when the object is clicked and when the mouse moved. However, it does not work.
To be clear: how can I change the name of the function that is being called? How can I make a function to be called only when an object is clicked and mouse moved?
Best regards, hope you understood! If not, comment I guess!
Okay, all you need to do is separately register 3 event handlers:
mouse down
mouse up
mouse move
You will have a boolean flag toggled to true and false on mouse down and up respectively. Then, on the mouse move handler, you need to check if the flag is true, which would mean the mouse button is down. Finally, we check to see if the cursor has actually moved from its initial position.
Here's the JSFiddle.
var example = document.getElementById("example");
var position = {
X: 0,
Y: 0
};
example.onmousedown = function (down) {
downFlag = true;
// Record click position
position.X = down.clientX;
position.Y = down.clientY;
};
example.onmouseup = function (up) {
downFlag = false;
};
example.onmousemove = function (move) {
if (downFlag) {
if (position.X !== move.clientX || position.Y !== move.clientY) {
// Do stuff here
}
}
};
Its a part from one of my web page..Check It out.May this will help you..
<div id="Log_frm">
<fieldset id="fld_1">
<!--<legend>Log In</legend>-->
<div id="log_l" onmouseover="dv_in();" onmouseout="dv_out();" style="background-color:#0C93D4;font-size: 15px;height: 30px;padding: 7px 32px 0px 32px;font-weight:bold; float: left;-webkit-border-top-left-radius: 5px;">
Log In
</div>
<div id="log_r" onmouseover="dv_out();" onmouseout="dv_in();"style="background-color: #0C93D4;font-size: 15px;font-weight:bold; float: right;height: 30px;padding: 7px 14px 0px 12px;-webkit-border-top-right-radius: 5px;">
Need Any Help
</div >
</fieldset>
</div>
<style>
#Log_frm {
width: 250px;
height: 60px;
margin-top: 10px;
position: absolute;
font-size: 12px;
float: right;
right: 0px;
}
#Log_frm a {
color: #fff;
text-decoration: underline !important;
left: auto;
margin-right: auto;
}
<script type="text/javascript">
function dv_in() {
log_l.style.backgroundColor="#06C";
log_r.style.backgroundColor="#0C93D4";
}
function dv_out() {
log_l.style.backgroundColor="#0C93D4";
log_r.style.backgroundColor="#06C";
}
</script>
Regds..

What's the best way to limit focusable controls to current dialog?

I've a web application with dialogs. A dialog is a simple div-container appended to the body. There is also an overlay for the whole page to prevent clicks to other controls. But: Currently the user can focus controls that are under the overlay (for example an input). Is there any way to limit the tabbable controls to those which are in the dialog?
I am using jQuery (but not using jQueryUI). In jQueryUi dialogs it's working (but I don't want to use jQueryUI). I failed to figure out, how this is accomplished there.
Here is the jQueryUI example: http://jqueryui.com/resources/demos/dialog/modal-confirmation.html - The link on the webpage is not focusable. The focus is kept inside the dialog (the user cannot focus the urlbar of the browser using tab).
HTML:
I should not receive any focus
<input type="text" value="No focus please" />
<div class="overlay">
<div class="dialog">
Here is my dialog<br />
TAB out with Shift+Tab after focusing "focus #1"<br />
<input type="text" value="focus #1" /><br />
<input type="text" value="focus #1" /><br />
</div>
</div>
CSS:
.overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
text-align: center;
}
.dialog {
display: inline-block;
margin-top: 30%;
padding: 10px;
outline: 1px solid black;
background-color: #cccccc;
text-align: left;
}
Here is my fiddle: http://jsfiddle.net/SuperNova3000/weY4L/
Does anybody have an idea? I repeat: I don't want to use jQueryUI for this. I'd like to understand the underlying technique.
I've found an easy solution for this issue after hours of trying. I think the best way is adding 2 pseudo elements. One before and one after the dialog (inside the overlay). I'm using <a>-Tags which are 0x0 pixels. When reaching the first <a>, I'm focusing the last control in the dialog. When focusing the last <a>, I'm focusing the first control in the dialog.
I've adapted the answer of this post: Is there a jQuery selector to get all elements that can get focus? - to find the first and last focusable control.
HTML:
<div class="overlay">
<a href="#" class="focusKeeper">
<div class="dialog">
Here is my dialog<br />
TAB out with Shift+Tab after focusing "focus #1"<br />
<input type="text" value="focus #1" /><br />
<input type="text" value="focus #1" /><br />
</div>
<a href="#" class="focusKeeper">
</div>
Extra CSS:
.focusKeeper {
width: 0;
height: 0;
overflow: hidden;
}
My Javascript:
$.fn.getFocusableChilds = function() {
return $(this)
.find('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object:not([disabled]), embed, *[tabindex], *[contenteditable]')
.filter(':visible');
};
[...]
$('.focusKeeper:first').on('focus', function(event) {
event.preventDefault();
$('.dialog').getFocusableChilds().filter(':last').focus();
});
$('.focusKeeper:last').on('focus', function(event) {
event.preventDefault();
$('.dialog').getFocusableChilds().filter(':first').focus();
});
May be I'll add a fiddle later, no more time for now. :(
EDIT: As KingKing noted below the focus is lost, when clicking outside the control. This may be covered by adding an mousedown handler for the .overlay:
$('.overlay').on('mousedown', function(event) {
event.preventDefault();
event.stopImmediatePropagation();
});
EDIT #2: There's another thing missing: Going outside the document with the focus (for example the titlebar) and than tabbing back. So we need another handler for document which puts back the focus on the first focusable element:
$(document).on('focus', function(event) {
event.preventDefault();
$('.dialog').getFocusableChilds().filter(':first').focus();
});
You can try handling the focusout event for the .dialog element, check the e.target. Note about the e.relatedTarget here, it refers to the element which receives focus while e.target refers to the element lossing focus:
var tabbingForward = true;
//The body should have at least 2 input fields outside of the dialog to trap focusing,
//otherwise focusing may be outside of the document
//and we will loss control in such a case.
//So we create 2 dummy text fields with width = 0 (or opacity = 0)
var dummy = "<input style='width:0; opacity:0'/>";
var clickedOutside = false;
$('body').append(dummy).prepend(dummy);
$('.dialog').focusout(function(e){
if(clickedOutside) {
e.target.focus();
clickedOutside = false;
}
else if(!e.relatedTarget||!$('.dialog').has(e.relatedTarget).length) {
var inputs = $('.dialog :input');
var input = tabbingForward ? inputs.first() : inputs.last();
input.focus();
}
});
$('.dialog').keydown(function(e){
if(e.which == 9) {
tabbingForward = !e.shiftKey;
}
});
$('body').mousedown(function(e){
if(!$('.dialog').has(e.target).length) {
clickedOutside = true;
}
});
Demo.

css/javascript element returning false when it should return true

I have a one field form (text input and submit button). Here is the form code:
<form id="new_skill" class="new_skill" method="post" action="/skills" >
<li>
<input id="resume-field" class="field field288" type="text"
value="Type a speciality you want to add to your profile"
title="Type a speciality you want to add to your profile"
name="skill[label]"></input>
</li>
<li class="td80">
<input class="button button-add button-add-disabled"
type="submit" value="ADD +" name="commit"></input>
</li>
</form>
Using javascript, if text is entered in the text field, the submit button should be unclickable. If there is no text in the field, it should be clickable. I am doing that by using javascript to remove and/or put back the button-add-disabled class. Here is the javascript:
(function($){
$(document).on('focusin', '#resume-field', function() {
$(this).parents().find('.button-add-disabled').removeClass('button-add-disabled');
}).on('focusout', '#resume-field', function(){
if(this.value==' '||this.title==this.value) {
$(this).parents().find('.button-add').addClass('button-add-disabled');
} else {
$(this).parents().find('.button-add').removeClass('button-add-disabled');
}
});
$('.button-add-disabled').click(function(){
return false;
});
}(jQuery));
And here is the css:
.button-add { width: 49px; height: 28px; border: solid 1px #8c8c8c; display: block;
font-size: 11px; line-height: 28px ; color: #fff; text-align: center;
font-family: 'Ubuntu', sans-serif; transition: none; margin: 0 0 0 auto;
border-radius: 3px; }
.button-add:hover { text-decoration: none;
-webkit-transition:none;
-moz-transition:none;
-ms-transition:none;
-o-transition:none;
transition:none;
}
.td80 .button-add { margin-left:35px !important; }
.button-add-disabled { background: url(/assets/add-specialities-disabled.png)
repeat-x 0 0; box-shadow: 0 0 0 0; margin-left:35px; }
.button-add-disabled:hover { background: url(/assets/add-specialities-disabled.png)
repeat-x 0 0; box-shadow: 0 0 0 0; }
The classes are changing as expected and the javascript is working. For some reason though, even if .button-add-disabled is not applied to the form element, the form element is still returning false and therefore won't submit. When "button-add-disabled" is removed by the javascript, the form should submit. I can see the server logs. If I remove the line from the javascript "return: false", the form works, So i know the form itself works. I'm pretty sure something is wrong with the javascript. Any ideas?
That's not how that works. Events are bound to elements, which are reached via selectors; they are not bound to selectors.
When you bind the event directly to the element, the event is now bound to that element until you explicitly unbind it. The original selector is no longer relevant.
You need to do this, or something like it:
$('.button-add-disabled').click(function(){
return !$(this).hasClass('button-add-disabled');
});
That is, test whether the button is currently disabled by your class at the point the event is raised.
As an aside, this...
if(this.value==' '||this.title==this.value) {
$(this).parents().find('.button-add').addClass('button-add-disabled');
} else {
$(this).parents().find('.button-add').removeClass('button-add-disabled');
}
should be this:
var disabled = this.value == ' ' || this.title == this.value;
$(this).parents().find('.button-add').toggleClass('button-add-disabled', disabled);
You want to set/remove the disabled attribute of the input element, not set a CSS style which is for display purposes only
$('#resume-field').on('change', function() {
if ($(this).val().length == 0) {
$(this.form).find('input[type=submit]').attr('disabled', false).removeClass('button-add-disabled');
} else {
$(this.form).find('input[type=submit]').attr('disabled', true).addClass('button-add-disabled');
}
})
jsFiddle Demo
Also be sure that you handle the submission of the form when the user presses enter in the input field, you can do that using the jQuery .submit event handler and preventing the default behaviour. It is also essential you handle this server side.
EDIT: I just noticed what the CSS was doing, updated answer.

Categories

Resources