Focusing input box programatically from another component - html

I had a question where the (great) answer exemplified how to allow an input box to obtain focus (by requesting change detection to be run in case the component isn't visible at the moment of focus assignment).
Now, I'm faced with a similar problem. I'm setting the value in a field of the component that contains the input box from another component. It works as far I can see the input box being displayed and the read-only label getting hidden. However, the input box isn't focused on.
I'm suspecting that the reason for it is the same, or least similar. However, since I'm setting the value from outside of the component, I can't rely on accessing it as a view child anymore, as I did in the case of the click handler.
What would be an appropriate strategy to approach it?
The usual googling rendered no useful links. I'm not providing a sample because, frankly, I'm not sure how to illustrate the issue other than describe it in words.
onUpdate(config: DataRowConfig) {
const target = config.cellConfigs.find(a => a.justSubmitted);
const index = config.cellConfigs.findIndex(a => a.justSubmitted);
if (target.key === "Enter")
config.cellConfigs[(column + 1) % 5].editing = true;
}

Related

Find elements with opacity==0 elements and make them visible with Forge

We're trying to visualize an IFC model with forge that contains a lot of invisible elements.
One problem we're facing is that the elements that is invisible does not fall under the normal category of hidden elements. E.g. model.setAllVisibility(true) does not make them appear. Also, model.visibilityManager.hiddenNodes is empty and model.visibilityManager.setVisibilityOnNode(dbId, true) does nothing to make them appear.
What seems to be the case with these elements is that their material.opacity is 0.
We tried setting the opacity to 1, and also tried using a different material, with no luck.
The only thing we have managed to do so far is to highlight the element's corresponding fragment:
model.setHighlighted(fragId, true)
however, this does not really cut it (unless it's possible to highlight many elements, and make them transparent?).
It's also worth mentioning that:
The elements comes from a IfcBuildingElementProxy IFC type
Calling viewer.setDisplayEdges(true) makes it possible to see the wireframe of the invisible elements
It's possible to click on the elements even though they are invisible.
So, my questions:
Is there any good way to find all the invisible elements in a model?
Is it possible to change them to be visible without highlighting them?
The viewer doesn't provide any solution for this out-of-the-box but it should be quite straightforward by putting together some of the viewer's features:
To check the opacity of all objects, you can just get the list of all fragments, and check the opacity of each material:
const frags = viewer.model.getFragmentList();
for (let i = 0; i < frags.getCount(); i++) {
const mat = frags.getMaterial(i);
console.log(mat.opacity);
}
And then, when you find materials you would like to change, you can do that, too. Here's some resources that might help:
how to add custom material to a fragment in forge viewer
https://forge.autodesk.com/blog/material-swatches-forge-viewer
https://forge.autodesk.com/blog/custom-shader-materials-forge-viewer

self disable button, accessibility

is there a way to don't read 'unavailable' or 'dimmed' in a self-disable-button?
See the example Example
var saveBtn = document.getElementById("saveBtn");
var helper = document.getElementById("helper");
var content = document.getElementById("content");
saveBtn.onclick = function(e) {
saveBtn.setAttribute("disabled", "disabled");
saveBtn.setAttribute("aria-disabled", true);
content.innerHTML = 'Lorem input a lot of stuffs';
helper.innerHTML = "Content added, please read it";
setTimeout(function(){
helper.innerHTML = "";
saveBtn.removeAttribute("disabled");
saveBtn.setAttribute("aria-disabled", false);
}, 5000);
};
Voice only says: 'Content added, please read it'
NVDA says: 'Content added, please read it. Unavailable'
I know that it is happening because the button still having focus. But, I need to find a solution for that because I can't modify the current behavior of my page.
I'm using the html helper to inform transitions as you can see https://stackoverflow.com/a/38137593/3438124.
Sorry for ugly code, this is only to simulate my real behavior.
Thank you guys!
You will need to move focus to the new element. Give it tabindex=0 and then use focus().
aria-live is for when you want to have the screen reader speak changes for the content area with the aria-live attribute. Since you use it on a sibling div, you are missing the opportunity for it to just do what it does. Alternative, you can skip the tabindex/focus() approach and just put aria-live on a container for your new content.
Also, you can ditch the aria-disabled and just lean on disabled for the button. aria-disabled is for elements that otherwise do not support disabled.
You answered your own question when you said "I know that it is happening because the button still having focus" and then aardrian pointed it out explicitly when he said "You will need to move focus to the new element".
Keep in mind, though, that whether the focus remains on a disabled object is totally up to the user agent (browser). Some browsers leave the focus on the disabled object and others move it to the parent.
aardrian's comment about using tabindex was if you wanted to move the focus to an object that is not normally focusable (ie, if it's an element you can't normally TAB to). So if you want to move the focus to some simple text (just to get it off the button), then I'd tweak aardrian's suggestion and use tabindex='-1' instead of tabindex='0'. That will allow you to call focus() on that element but won't allow the user to TAB to it.
If you want to move the focus to another button on the page, or some other element that can naturally receive focus (checkbox, input field, etc), then you don't need tabindex.
If you end up moving the focus to the text that was just added, then you don't really need aria-live because the screen reader will read the text that you just focused to. But that's only relative to the example you posted, which I understand is just a sample to show the problem. Your real app might not be adding text.
And I want to second aardrian's recommendation of not setting aria-disabled when you're already using the disabled property. It's superfluous. The aria-disabled property is for when you're simulating a disabled object.
How the text is read varies reader to reader. None is right or wrong. If you want the text being read out to be same and consistent across the readers..Do a little workaround. Add an aria-label="desired text" to your button. This will override anything that is present inside the button tag.
eg
<button aria-label="desired text button">This text will be ignored</button>
Nvda will read the button as "desired text button". Text inside button is ignored. Now you can handle(add/remove) the disabled and aria-label attribute with JS.
In the context of your question you can try:
Instead of:
helper.innerHTML = "Content added, please read it";
Try using:
saveBtn.setAttribute("aria-label", "Content added, please read it.");
setTimeout(function(){
saveBtn.removeAttribute("aria-label");}, 5000);
Then the text will be same across the readers.

How to make a custom web component focusable?

I'm writing a custom web component that is meant to be interactive. How can I tell the browser that this custom component should receive focus?
I wish that my custom element…
could be focused (by tab-navigation);
could receive keypresses when focused;
could be matched by :focus pseudo-selector.
I'm not using any external library, just plain HTML5 APIs.
Based on this demo that I found in this question, I have this answer:
Just add the tabindex attribute to the elements you want to be focusable.
// Add this to createdCallback function:
if (!this.hasAttribute('tabindex')) {
// Choose one of the following lines (but not both):
this.setAttribute('tabindex', 0);
this.tabIndex = 0;
}
// The browser automatically syncs tabindex attribute with .tabIndex property.
Clicking on the element will give it focus. Pressing tab will work. Using :focus in CSS will also work. keydown and keyup events work, although keypress doesn't (but it's deprecated anyway). Tested on Chrome 44 and Firefox 40.
Also note that this.tabIndex returns -1 even if the HTML attribute is missing, but this has a different behavior than setting tabindex="1":
<foo></foo>: No tabindex attribute, the element is not focusable.
<foo tabindex="-1"></foo>: The element is not reachable through tab-navigation, but it is still focusable by clicking.
References:
http://www.w3.org/TR/html5/editing.html#sequential-focus-navigation-and-the-tabindex-attribute
https://html.spec.whatwg.org/multipage/interaction.html#the-tabindex-attribute
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
https://github.com/whatwg/html/issues/113
#Denilson, I would like to provide you with some more information.
As you said, this.tabIndex = 0 works when your webcomponent contains no focusable elements. If it does, it gets more complicated.
For example, if your component contains one or more inputs, then first the "whole" component gets focus, and only later, when tabbing, each inner inputs get focus, one by one. This is usually not what you want. Usually, when the component gets focus this should mean its first input gets focus immediately.
Also, there is a reverse tabbing problem. If your first input has focus and you press SHIFT-TAB, then the "whole" component gets focus, and you are forced to press SHIFT-TAB twice to move to the previous element.
I found this to solve all focus and tabbing problems:
// At first, the component may get focus and accept tabbing.
createdCallback = function () { this.tabIndex = 0; }
// When the component gets focus, pass focus to the first inner element.
// Then make tabindex -1 so that the component may still get focus, but does NOT accept tabbing.
focus = function (e) { firstFocusableInnerElement.focus(); this.tabIndex = -1; }
// When we completely left the component, then component may accept tabbing again.
blur = function (e) { this.tabIndex = 0; }
Note: As of now (Sep 2015) if an inner element gets focus, then the "whole" element is not matched by the :focus pseudo-selector (tested only in Chrome). If find this behavior to be just plain wrong. The focus event was fired, and the blur event was not. So the element should have focus, right? I hope they change this in the future.
Short answer: delegatesFocus is what you need here, not tabindex.
Details:
Assuming that you have interactive elements inside the shadow DOM, there is no satisfying way to make the component programmatically focusable with tabindex:
if you set it to 0 you add the host element to the tab sequence ("sequential keyboard navigation") and you have an extra tab stop
if you set it to -1 you remove not only the host element but any interactive element inside its shadow DOM from the tab sequence, so the whole thing becomes inaccessible for keyboard users
There's a web component API just for this: ShadowRoot.delegatesFocus, see here. Set this to true and you'll get:
calling .focus() on the host or clicking on any non focusable part of the component focuses the first focusable element in the shadow DOM
:focus styles are applied to the host in addition to the focused element within
tab sequence is unchanged (it should already work the way you want)
It's supported since shadow DOM v1.
One very pragmatic approach I use, if possible and suitable, is just to put a <button type='button'> around my custom element.
This maybe does not fit as solution for you, I mention it anyway for others stepping into this question / problem.
It handles all focus matters, including a focus rectangle an so on.
To tame a <button> is less work than it seems (think especially about the line-height the button changes)

Make resizable methods makes input fields not clickable

I've really strange behavior and I spent a couple of days to try to figure out what is a problem.
MooTools methods makes my input fields not clickable, and I don't know why.
$$('.class1.class2').makeResizable({
});
Above piece of code needs to make all children of div which has class 'class1' & 'class2' to be re-sizable, and that works perfectly but beside that it also makes input fields not clickable.
Does anybody had the similar problem?
Any kind of help will be appreciate.
Thanks
so the problem is that you have no handle passed in. when you fail to do that, the whole element becomes a listener for mousedown and attempts to click into any child element will not bubble correctly, resulting in weird behaviour.
I also found a bug in the logic for adding handlers, which seems to not evaluate handles correctly
https://github.com/mootools/mootools-more/blob/master/Source/Drag/Drag.js#L66 is wrong on many levels - it expects a collection / array of elements but looks in the global document and not child elements - yet it ends up picking element anyway and ignores passed collections like $$('.class1 .resizer')
i did a small change to accept a string for a child selector and added a resize handler.
http://jsfiddle.net/pbu5uzho/
you should submit this bug to https://github.com/mootools/mootools-more/issues though i doubt it will get picked up.
$$('.class1').makeResizable({
handle: '.resizer'
});
the change I did to make this work was:
this.handles = this.element.getElements(this.options.handle);
alternatively, you can use something like InteractJS to handle this.
I'm not 100% sure but can you try this one
I think you are missing (,)
$$('.class1,.class2').makeResizable({
});

What's the best way to hide a tab in a TabNavigator?

I'd like to conditionally hide a tab in a TabNavigator. It seems that setting visible doesn't work properly (presumably because this is how the TabNavigator hides the tabs that aren't currently selected).
What's the right way to do this?
You can do this by making use of TabNavigator's getTabAt() method which returns the Button that makes up the visual tab. You can then set that Button's visible property. It's a little tricky to get this setup with a bindings, but it's doable.
You could also consider just disabling the tab instead, which you can do by setting enabled on the corresponding TabNavigator child (for which visible didn't work).
What do you mean by hide? If you actually mean remove, then just take your array that's bound to the data in the TabNavigator, and remove the applicable element from it.
If you want to just have them removed temporarily, create a component of your own that encapsulates the TabNavigator and has an array of removed tabs and an array of actual tabs. Then handle this as you see fit.
You might want to check out the flexlib project. They have a component called SuperTabNavigator that adds a lot of functionality to the base Flex TabNavigator, including hiding tabs (I think).
If you do have to create your own component, though, it's a bit more tricky. The thing to know is that "tabs" are actually specially styled buttons, contained within a TabBar component (the TabBar is then contained within the TabNavigator). What you'll have to do then, is subclass TabNavigator and have some property on your views (i.e. the canvases, etc. that are added to the TabNavigator) that is bound to the visible and includeInLayout properties of the TabBar buttons.
In essence, what you'll have is something like:
BindingUtils.bindProperty( tabButton, "visible", view, "someProperty" );
BindingUtils.bindProperty( tabButton, "includeInLayout", view, "someProperty" );
I don't know about TabNavigator, but in other containers, you can set the includeInLayout property to false and it will be ignored. You probably still need to combine it with visible.
var secondTab = tabNavigator.removeChildAt(0);