I have containers with multiple lines but only the first one visible (overflow:hidden). The container is expandable upon a click. (See https://stackoverflow.com/a/6972830 and the jsFiddle http://jsfiddle.net/JUtcX/2/)
If someone performs a Ctrl+F with text from the non-visible lines, the browser reports a match but cannot show it (because it's hidden).
How can I react to Ctrl+F and open the container whether a non-visible text in it was searched for?
[Update]
Approaches that do not meet all requirements:
Listening for Ctrl+F.
I have multiple containers and only want to expand those containing the search phrase. Upon listening for Ctrl+F I could only open all containers at once.
Does not work on all systems. This is a negligible defect only, though.
Chrome-specific workaround (link)
At least also Firefox should be supported
You can do something like this:
function find(e) {
if (e.ctrlKey && e.keyCode == 70) {
document.getElementById("hide").style.display = "block";
}
}
document.addEventListener('keyup', find, false);
#hide{
display: none;
}
<div>
ASDF:
<div id="hide">
Hidden
</div>
</div>
Listening to browser Ctrl+F/find layout modifications
I don't think it is possible to listen to those layout modifications.
When the browser find an element, it is equivalent to call
scrollIntoView for the matched element. Thus a scroll event will be
fired only if the container div is scrollable.
In the example, the parent style is overflow: hidden;. Thus it does
not trigger any scroll event.
It becomes then impossible to listen to these layout change, because
the only workaround that exist to listen to scroll event on
overflow:hiden element, is to listen to mouse wheel event ...
The bad story is that it is then impossible to prevent user from
modifying layout through the browser find, because even if one can
prevent Ctrl+F or F3, we can't prevent user from using the Edit-> Find
menu in Firefox or IE
JBE
Listen for Events from Browser "Find" Window in JavaScript
I don't know of any way you can listen for a find-like event and if
that's supported in any browser it sure isn't a portable solution.
I also don't know what you're trying to achieve but I think that your
best option is to listen for the keyboard events that trigger the find
window and attempt to cancel them while attempting to emulate the
find-toolbar/window with JavaScript of your own. This is however a
herculean (and nearly impossible) task due to some browsers
customization of keyboard shortcuts depending on the localization (for
instance, in IE, en-US uses Ctrl+F (for Find) while pt-PT uses Ctrl+L
(for Localizar, meaning find)).
Conclusion: I think you're out of luck there...
Miguel Ventura
Searching for text (Ctrl+F) across hidden spans
Chrome search feature (ctrl+f) finds hidden text ( but it's invisible! )
Related
I'm working on a modal component to be used across my organisation's website and digital services (around 17,000 pages created over the last 15+ years with millions of monthly users). As you can imagine these pages vary considerably and it's impossible to test them all.
To maximise the accessibility of this component I need to restrict focus (via the tab key and/or virtual cursor) to the modal while the modal is open.
My approach has been to attach a handler to the blur event on the last focusable element that returns focus to the first focusable element in the modal. This works absolutely fine unless the last focusable element in the modal is also the last focusable element on the page, in which case focus returns to the browser search bar.
I've been pretty puzzled by this for a couple of days and unable to find any information to indicate why this would be. Here's some simplified code which illustrates the issue:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Focus trap</title>
<style>button:focus {background-color: orange;}</style>
</head>
<body>
<div id="modal">
<button id="link-1">Link-1</button>
<button id="link-2">Link-2</button>
<button id="link-3">Link-3</button>
</div>
<script>
let last_link = document.getElementById('link-3'),
first_link = document.getElementById('link-1');
last_link.addEventListener('blur', () => {
first_link.focus();
})
</script>
</body>
</html>
I'm aware of a few things we could do, but none of these are ideal:
Try intercepting keyboard events rather than blur - but I'm reluctant to do that because it's likely to exclude users of some assistive technologies
Create and hide an additional focusable element in the modal - which I'm reluctant to do because it feels a bit of a hack
You can't go against the address bar or native toolbars being focused. They take the priority over whatever you could say and there are fortunately very good reasons for that to be so.
The solution is one of the two options you have already mentionned:
Intercept tab on the last element, as well as shift+tab on the first one
Put two hidden focusable elements, one at the beginning and one at the end, and move the focus to the first or last element as soon as your hidden focusable elements get focus.
I don't see which assistive technology would be defeated by doing tab/shift+tab interception. If you think about touch interface, anyway iOS/Android work completely differently with focus.
If you think about special devices, many of them simulate pressing keys on the keyboard, independently of the effective way their actions are triggered.
In case of doubt, the second one looks more like an hack, but is more robust if there effectively exist a special way to move the focus other than by the keyboard.
I am making an editor without relying on contenteditable, in order to get a clean, controlled output. So I'm catching all keyboard and mouse events, building a model and creating a DOM view from that model.
Since I need spellcheck, I activated contenteditable in divs in my view. The user doesn't interact with it, because I'm catching all events.
The problem I have is that spellchecking only seems to be activated on user input on the contenteditable div, which in my case happens only when I right-click somewhere on the text (because I'm not catching that). I've found a question that just says we shouldn't expect spellchecking to be active at the beginning - but in my case even when the user types, spellchecking doesn't happens (because he doesn't type in the contenteditable, I'm building it).
HTML spellcheck in contenteditable div not working after span
So is there a way I can trigger an event that would make the browser think the user is interacting with the contenteditable?
Update: that's only for Chrome, in Firefox the spellchecker works even without events directly caused by the user.
Most of user interaction elements associated to a custom JavaScript behavior in Web applications can be HTML links (a elements) having a meaningful href attribute value, enabling them to be used in non JavaScript-enabled environments:
<a id="profile" href="profile">Profile</a>
<script>
document.getElementById("profile").onclick = function() {
return !open(this.href, "_blank", "scrollbars=no,status=no"); // whatever
};
</script>
But some interaction elements are deeply linked to JavaScript, either because the Web application they are contained in requires JavaScript to run or because they were generated by JavaScript and don't make any sense when it is not available.
For those, as I want users to be able to interact with them whatever device they are on (i.e. I don't want to define mouse, keyboard, touch, … interaction by myself on a span element), I see two relevant HTML elements: a and button.
My problem with the a element here is that it defines at least one behavior I don't want: the ability for the user to open its target anywhere he wants to (e.g. in a new tab), whereas the interaction I want to take place is specific to the current tab.
My problem with the button element here is that, as far as I can tell from the online resources, it is difficult to style reliably on all modern browsers (but I am not sure if it is still the case now).
Some of the facets of this question have already been answered elsewhere, but I can't find a comprehensive and up-to-date summary: what HTML element would you recommend to use?
If you want an element to semantically be a button without the style issues of a <button> element, or behavior of an <a href> element, then you should use an element with [role="button"]. <span> is commonly used, but pretty much any element could be used.
<span role="button"></span>
Now, [role="button"] is really just a flag for assistive technology, so some interactions need to be set up to react as a button, but they're actually quite easy.
Buttons (such as links and form elements) are typically tabbable. This isn't always necessary, such as if a keyboard shortcut has been set for it already. If you want the <span> in the tabbing order, just add the [tabindex] attribute:
<span role="button" tabindex="0"></span>
Now you can tab to the button, but you'd probably still want to trigger the click event when Enter and/or Space is pressed.
Simply adding an event listener to the button is enough.
For brevity this example uses jQuery:
$(document).on('keydown', 'span[role="button"]', function (e) {
if (e.which === 13 || e.which === 32) {
$(this).click();
e.preventDefault();
}
});
This uses an event delegation format to provide click support for all spans with [role="button"], you may want to choose a different selector depending on your situation.
Now all that's left is to listen for when the button is clicked:
Again, jQuery:
$('.myButtonClass').click(function () {
...do stuff...
});
Now, for other devices, you're going to want to trigger a click on, say, a touch event. If you're using jQuery, there are assorted libraries to support turning touch into click and/or tap. If you're not using jQuery, it's not a lot of work to listen for touch events.
I'm not going to provide a code example to handle touch, but that's because it depends on what the button is supposed to do. In some cases you want to trigger a handler simply by starting a touch on the button (equivalent to mousedown), in other cases you want to trigger the handler if you've started and stopped the touch event on the same element (similar to how click works normally).
I'm not hopeful, but I'll ask just in case.
I would like to be able to use JavaScript to open a select element in mobile Safari for iPhone/iPad.
An extensive Google / Stack Overflow search shows that a lot of people would like to be able to do this in browsers in general, but it is not supported (why not, I wonder?). Various hacks have been suggested, from calling focus() on the select element and changing its size property to make more option elements visible, or constructing an entirely mock select element with <div> and <ul> elements. I would, however, like to use the native browser select controls in iPad and iPhone.
I wondered, just maybe, someone might know of a proprietary Apple WebKit method to do this. It would be something like:
var myselect = document.getElementsByTagName("select")[0];
myselect.open(); // this method doesn't exist
As a bonus, it'd also be handy to know of a boolean property that says whether the select element is currently open/active, or not (i.e. not just whether the element has focus). I know I can work this out by tracking click and change events, but a simple property would be useful.
Wishful thinking?
UPDATE:
I don't yet have the answer, but I've found that simulating a mousedown successfully opens a select element in Google Chrome, but not iPad or Firefox and so on:
function simulateMouseEvent(eventName, element) {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent(eventName, true, true, window,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
element.dispatchEvent(evt);
}
simulateMouseEvent("mousedown", select);
UPDATE:
I've asked a related, but different (and similarly unanswered!) question on select boxes here: Is there a DOM event that fires when an HTML select element is closed?
I have a working solution for this that works on recent versions of iOS and Android. I haven't yet tested on older versions. There are no two ways about it: this solution is a hack. But it works if implemented carefully.
In my situation I had iOS 7 like toggle switch element. I wanted the picker view for the select to be presented when the switch was turned on. In my case we did not need or want the user to see the select field itself. We merely wanted to use iOS' nice scrolly-picker interface.
I used CSS to position and stretch the select completely over the switch. I then set the opacity in CSS to something like opacity: .001; which makes it invisible for all intents and purposes. It may still work with opacity 0 but I felt leaving a little opacity there may be safer and you really can't see it all anyway. Now when the user taps the area of the screen that is displaying the switch the tap events are actually going to the select which causes the picker view to display.
On the onchange event of the select I set display: none; to completely hide the select. This means that when the user touches the switch to turn it off they are interacting with the switch itself. When the switch is toggled off I then set display: block to return the select to its active state.
My use case is narrow but the position/opacity technique should be adaptable to many use cases though you may have to have 2 select elements in cases where you want the field to be visible.
Here is a screenshot demoing the technique. The opacity is set to 0.25 in this screenshot for demo purposes. When you set it to 0.001 you can't see the select
Triggering HTML controls with JS is a very gray area, partly because of security reasons, and partly due to lack of support. Even using frameworks like jQuery, you cannot simply click() a link to follow it in the same way as click() on a button - you need to trigger a native click event at the browser level (I believe the latest version of Selenium does this, but that's a testing framework so unsuitable for this problem). Congrats on being able to achieve a partial result in Chrome! However, you will not find a universal solution that uses real select inputs.
I would suggest using a different type of control - either a vertical stack of buttons if you want to press one to activate a feature, or a stack of radio buttons backed by labels (with a little CSS) if you want a multi-choice format.
The select element needs to be visible.
If you use jQuery you can do it as follows:
$('mySelectElementSelector').focus();
On mobile it will show the default select control. On desktop just focus on the select control.
Have you tried the change() method?
I have the need to trigger the opening of the browser (IE, Firefox, Safari, etc) context-menu via javascript. The problem I am trying to solve, is when an overlaid element is right-clicked, the element below it shows its context menu. So if the top element is a label, when you right click, I need to show the context menu for the input element below.
I know how to keep the label's context menu from showing, but I don't know how to open a context menu arbitrarily.
Any help is appreciated!
Sorry to be the bearer of unfortunate news, but this is impossible to do with Javascript.
I don't want to frustrate you, quite the contrary, especially because you answered my own question :)
I don't think that a browser's contect menu is accessible via an ordinary script on a web page.
If what you are asking for was actually doable, then the browser makers would possibly consider this a bug and remove this behavior. Cross-browser, this behavior is very unlikely to be available today.
Why don't you capture mouse events, and whenever the mouse is directly in the area of the element below that you want to show the context menu for, push the covering element below, otherwise back on top?
That is one possiblity I could think of, basically revealing/exposing the hidden element depending on mouse position. Like cutting a hole into the overlay.
Or why don't you make the text field transparent and put the overlay below the text field entirely?
If this does not work out technically, then at least you have a point in filing bugs or enhancements against the targeted browsers.
BTW it looks like the context menu actually works if the user right-clicks directly at the position of the caret, so this might be another loophole for you to consider.
I have a possible solution that may suit your needs. It is not perfect yet, I have only done a few quick tests in a few browsers (Fox 3.6, IE7, IE8, Chrome 4, Safari 3 on xp) It will need to be tweaked and improved but its a start. Basically the idea is to remove the label on right-click mousedown so that the desired field is hit by the mouseup event and therefore fires up the context menu on the relevant field.
// Remove the contextmenu from "In-Field" Labels
base.$label.bind("contextmenu",function(e){
return false;
});
// Detect right click on "In-Field" label:
// hide label on mousedown so mouseup will target the field underneath.
base.$label.mousedown(function(e){
if ( e.which == 3 ){
var elLbl = $(this);
elLbl.hide();
var elFid = $(this).attr("for");
// bind blur event to replace the label when we are done.
$("#" + elFid ).bind("blur.infieldlabel",function(){
elLbl.show();
$("#" + elFid ).unbind("blur.infieldlabel");
});
return false;
}
});
The IE and Safari browsers experience a strange issue where you need to click in and out twice before the label will display again (something to do with event timing I think). You may be able to easily see why this is happening by looking at the code. Also noticed slight glitch sometimes in the fox after pasting into the field, on blur the label appeared for a split second when it should not. This should be a fairly simply thing to rectify if you decide to incorporate this method into your code.
You can make Your label/span element contenteditable="true" and handle any further actions with listeners. Making it contenteditable will enable normal, input-like contextmenu to show up on right click.
And if someone doesn't care for IE support:
pointer-events: none
Type the following in the console:
document.oncontextmenu = reEnable
That will print to the console the following:
reEnable()
{
return true;
}
Done, you can now use the context menu.