how do I find out if my custom widget has focus in Dojo?
i have dojo editor i wnat to know if the editor has already focus or not?
you can use the module dijit/focus to find out the focus
FROM DOJO DOCS
Tracking active widgets
At any point in time there is a set of (for lack of a better word)
“active” or “focused” widgets, meaning the currently focused widget
and that widget’s ancestors. “Ancestor” can mean either DOM ancestor
(ex: TextBox –> Form), or a logical parent-child relationship (ex:
TooltipDialog –> DropDownButton).
For example, if focus is on a TextBox inside a TabContainer inside a
TooltipDialog triggered by a DropDownButton, the stack would be
TextBox –> ContentPane –> TabContainer –> TooltipDialog –>
DropDownButton.
The activeStack[] parameter indicates this set of widgets, and an app
can monitor changes to activeStack[] by:
require([ "dijit/focus" ], function(focusUtil){
focusUtil.watch("activeStack", function(name, oldValue, newValue){
console.log("Focused widget + ancestors: ", newValue.join(", "));
});
});
the question in title has a different answer than the one in the descriptions.
there are two ways achieving the question in the title, by using dojo's focusUtil ("dijit/focus"). both ways give you something that you could find the widget using it and the dijit's registry ("dijit/registry").
focusUtil.curNode: gives you the DOM Node that currently has the focus. the function below, you could get the widget reference.
function getWidgetByNode(node){
var result;
while (!result && node){
result = registry.byNode(node);
if (node.parentElement)
node = node.parentElement;
else
node = null;
}
return result;
}
var focusedWidget = getWidgetByNode(focusUtil.curNode)
focusUtil.activeStack: gives you an array of the widgets (parent to child) that has the focus. so the last item in the array is the direct widget which has the focus. index values are widget ids, so you should get the widget by the following code
var focusedWidgetId = focusUtil.activeStack[focusUtil.activeStack.length-1];
var focusedWidget = registry.byId(focusedWidgetId);
now if you want to know if the currently focused widget is some specific one, it depends on what you have in hands from that specific widget:
widget itself: like the return values of above samples. now you have to compare if these are the same thing. you can not compare two widget objects using the == operator. you could compare their ids like this:
myWidget.id == focusedWidget.id
widget's id: this way you just easily get the id of the current node from focusUtil and compare it with the id you have liek this:
myWidgetId == focusedWidgetId
references:
http://dojotoolkit.org/reference-guide/1.9/dijit/focus.html
http://dojotoolkit.org/reference-guide/1.9/dijit/registry.html
require([ "dijit/focus" ], function(focusUtil){
var activeElement = focusUtil.curNode; // returns null if there is no focused element
});
check blow url here you can see some examples
http://dojotoolkit.org/reference-guide/1.8/dijit/focus.html#dijit-focus
a) For dojo 1.6: call dijit.getFocus(). This will return an object containing the currently focused dom node, among other things (selected text, etc.). To get the corresponding widget, simply do:
var activeElement = dijit.getEnclosingWidget(dijit.getFocus().node);
This is the full reference for dijit.getFocus(), from the source code:
// summary:
// Called as getFocus(), this returns an Object showing the current focus
// and selected text.
//
// Called as getFocus(widget), where widget is a (widget representing) a button
// that was just pressed, it returns where focus was before that button
// was pressed. (Pressing the button may have either shifted focus to the button,
// or removed focus altogether.) In this case the selected text is not returned,
// since it can't be accurately determined.
//
// menu: dijit._Widget or {domNode: DomNode} structure
// The button that was just pressed. If focus has disappeared or moved
// to this button, returns the previous focus. In this case the bookmark
// information is already lost, and null is returned.
//
// openedForWindow:
// iframe in which menu was opened
//
// returns:
// A handle to restore focus/selection, to be passed to `dijit.focus`.
b) For dojo 1.7 and up, use dijit/focus:
require([ "dijit/focus" ], function(focusUtil) {
var activeElement = focusUtil.curNode; // returns null if there is no focused element
});
Related
I have two editors on the screen, one read-only. What I want to do is allow the user to select content from the read-only editor and paste it into the current position of the other by clicking a button. (the logic may manipulate the text which is one reason I don't want to use the system's clipboard.)
So far I have the function that is able to paste the text like as follows. (I am using the Angular wrapper which explains the presence of the CKEditorComponent reference.
doPaste(pasteEvent: PasteEvent, editorComponent: CKEditorComponent) {
const editor = editorComponent.editorInstance;
editor.model.change(writer => {
writer.insertText(pasteEvent.text, editor.model.document.selection.getFirstPosition() );
});
}
What I can't find from the documentation is how to extract the selected text. What I have so far is:
clickPasteSelectedPlain(editorComponent: CKEditorComponent) {
const editor = editorComponent.editorInstance;
const selection = editor.model.document.selection;
console.log('clickPasteAll selection', selection);
console.log('clickPasteAll selectedcontent', editor.model.document.getSelectedContent);
}
The selection appears to change depending on what is selected in the editor's view. The getSelectedContent function is undefined. How do I get the content?
With a bit of poking around I figured out how to do this. I'll document it here on the chance that it will help someone down the road avoid the process of discovery that I went through.
On the source document I have a ckeditor element like this:
<div *ngIf="document">
<ckeditor #ckEditor
[editor]="Editor" [config]="ckconfig" [disabled]="true"
[(ngModel)]="document.text"></ckeditor>
<button mat-flat-button (click)="clickPasteSelectedPlain(ckEditor)">Paste Selected Text Plain</button>
</div>
In the component the function called on the click event is like this:
#Output() paste = new EventEmitter<PasteEvent>();
...
clickPasteSelectedPlain(editorComponent: CKEditorComponent) {
const editor = editorComponent.editorInstance;
this.paste.emit({
content: editor.model.getSelectedContent(editor.model.document.selection),
obj: this.document,
quote: false
});
}
The PasteEvent is defined as an exported interface which I will omit here to save space. The content key will refer to a DocumentFragment.
Note that I am passing the CKEditorComponent as a parameter. You could also access it via an Angular #ViewChild declaration but note that my ckeditor is inside an *ngIf structure. I think that works well in Angular 6 but in the past I have had difficulty with #ViewChild references when the target was conditionally in the DOM. This method always works but use whatever method you want.
The event fired by the emit is processed with a method that looks like this:
doPaste(pasteEvent: PasteEvent, editorComponent: CKEditorComponent) {
const editor = editorComponent.editorInstance;
editor.model.insertContent(pasteEvent.content);
}
Because the content is a DocumentFragment the paste operation will include all formatting and text attributes contained in the selected source. But that's all there is to it.
We have a dijit.Tree that indicates a node type by using an icon. The icon is a unique indicator that tells the person this node is a "book" or a "DVD" or a "magazine" for example.
dijit renders the icon as a background image in CSS which we know screen readers do not see.
I tried overriding the getTooltip method to provide a tooltip saying "book" or "DVD". It successfully adds the "title" attribute to the "dijitTreeRow". If I mouse over the node, I see the text. This is not ever focused on when the user moves down to get from one node to the next.
When navigating the tree, the up and down arrows traverse the nodes. The span with the visible text is focused on and that string is read. You can see the dotted line focus as well as hear this with JAWS in the most basic of examples: https://dojotoolkit.org/reference-guide/1.10/dijit/Tree.html
What I have not been able to figure out is how to create an indicator that the screen reader will pick up on that will read "Book" alongside "The Great Gatsby".
Does anyone have any tips on how they made this dijit widget accessible for the screen reader when the images are an indicator that should be heard by the blind user?
The tree supports HTML labels, via setting the labelType property on the model you give it.
Assuming you don't want to change the store data (or override the getLabel method), you can reimplement dijit/Tree.getLabel and produce the HTML label, and wrap it with a span with an aria-label.
(code lifted from the dijit.Tree reference).
var myModel = new ObjectStoreModel({
store: myStore,
labelType: "html", // Hack to tell the tree node to render as HTML
query: {id: 'world'}
});
var tree = new Tree({
model: myModel,
getLabel: function(item) {
var label = this.model.getLabel(item);
// dojo.string
return dstring.substitute("<span aria-label='dvd ${0}'>${0}</span>", [label]);
}
});
If your data might contain HTML-ish characters that you don't want to render, escape the characters in getLabel too.
When a page has a search box with multiple tabs, one of the tabs is always selected; either the default tab is selected or the user has changed the tab. In either case the search input box of the selected tab should always have the keyboard focus so the user can just start typing their keywords.
Example: search box on http://www.lib.umd.edu/
Do you know how I could get the focus to be in the input box when a different tab is clicked? I got it to work on the first tab, but when I click another tab, the focus is lost.
The script I am using:
<script type="text/javascript" language="JavaScript">
document.forms[''].elements[''].focus();
</script>
$(document).ready(function () {
setTimeout(function () {
// focus on the txtenclude text area first visible and enabled input field or textarea
$(":input:visible:enabled").each(function () {
if ($(this).is('textarea')) {
$(this).focus();
return false;
}
});
}, 1000);
Your code snippet
To set the focus on a certain element you have to specify which element should receive the focus. In your snippet this specification is missing:
document.forms[''].elements[''].focus();
If you want to you can use this line: document.getElementById("DuringSearch").focus();
DuringSearch is the id of the input element that should receive the focus <input id="DuringSearch" type="text">
The problem that needs to be solved is to change the id based on the tab that was clicked.
There are several ways to achieve this. In a previous post is used an attribte named data-tab.
Example to wire up tabs and focus to input
To attach an event handler to a click on a tab you can do the follwing (using jQuery) on document.ready:
// add event handler for click on tab
$("#tabs li").click(function () {
loadTabs(this);
setFocusOnInput(this);
return false;
});
If you click on a tab the attached event fires and executes the 2 functions: loadTabs and setFocusOnInput.
To set the focus you need to know the id of that input-box. In my exmaple i am using an attribute data-tab
<li data-tab="Before">
Before
</li>
In my example i use the following function:
function setFocusOnInput(_this){
var tab = $(_this).attr("data-tab");
var searchId = tab + "Search"
console.log("_this:", _this);
document.getElementById(searchId).focus();
}
See more explanations on my previous post.
Could you elaborate what you want to know. Do you want to know how to wire it up in general or how to do it in a specific case?
Let's say in a view I have a DojoX Mobile ListItem that is pulling an HTML view fragment into the DOM via AJAX and then transitioning to that view. Assume this is all working fine.
Now, I go back to the initial view that had that ListItem on it and click some other button that destroys that view node from the DOM. If I now click on that ListItem that previously loaded that view node into the DOM (which has now been removed), it will try to transition to a view that doesn't exist. It doesn't know that it has been removed.
Is there some type of way to tell a ListItem that it needs to fetch the HTML again because what was previously fetched no longer exists? I am not seeing anything about doing this in any documentation anywhere. I don't think a code sample is really necessary here, but I can provide a minimal one if necessary.
I went a different route and left the view exist in the DOM, and simply made a function that clears all sensitive data out of the view.
Okay, in this case, i guess you could hook the onShow function of your ListItem container(or any other onchange event). Create a listener for said handle to evaluate if your item needs reloading. Following is under the assumtion that it is the item.onclick contents showing - and not the label of your item which contains these informations
Or better yet, do all this during initialization so that your ListItem container will be an extended with custom onClick code.
Seems simple but may introduce some quirks, where/when/if you programatically change to this item, however here goes:
function checkItem() {
// figure out if DOM is present and if it should be
if( isLoggedIn() ) {
this.getChildren().forEach(function(listitem) {
if( dojo.query("#ID_TO_LOOK_FOR", listitem.domNode).length == 0 ) {
// this references the listItem, refresh contents.
// Note: this expects the listitem to be stateful, have no testing environment at time being but it should be
listitem.set("url", listitem.url);
}
});
}
}
Preferably, set this in your construct of the container for your ListItems
var listItemParent = new dojox.mobile.RoundRectList({
onShow : checkItem,
...
});
Or create listener
var listItemParent = dijit.byId('itemRegistryId');
// override onClick - calling inheritance chain once done
dojo.connect(listItemParent, "onClick", listItemParent, checkItem);
What i have is a single dijit.Menu that contains the dijit.MenuItem objects with labels 1 - 9. It is connected to a sudoku like grid of 81 'nodes' (because there are so many, i dont bother with individual id's, i simply collect them with dojo.query('their-css-class-name')). This is the code i'm using inside of a widget to instantiate the context menu and its menu items.
var contextMenu = new dijit.Menu({targetNodeIds:dojo.query(".sudokuNode"), leftClickToOpen:true});
for(var i = 1; i <= 9; i++) {
contextMenu.addChild(new dijit.MenuItem({
label:i,
onClick: function(evt) {
//??
}
}));
};
contextMenu.startup();
What i'm trying to do is have the node that is clicked, and subsequently opens a popup/context menu, be filled with the value (1-9) selected from the context menu's MenuItems.
My problem is that i dont know how to "know" which of the 81 nodes was the one to fire the oncontextmenu event, and i dont know how to reference that node inside the 'onClick' method declared in the menu item.
Any help demonstrating how to reference the calling node in that context would be appreciated! If this isn't enough information, let me know what else i can do to explain my problem!
evt.target should get you the node that was actually clicked. Depending on the structure, you may need to do some other navigation from there, or use dijit.getEnclosingWidget().
If the MenuItems allow the events to bubble (I'm not sure; haven't used it myself), you could connect to the onClick() method of the Menu, so you've only got the single event listener in play.