Accessibility JS Function "Role" Attribute - javascript

I'm trying to write a JS function that would give empty heading elements (h1, and h2...)a “role” attribute value of “presentation”.
This is my first time working with accessibility in my projects and would love some help!

If they're empty, do they need to be there at all? The most correct thing is just to remove them.
However, you can use document.querySelectorAll() to get all the headings, then look inside each one to see whether they are empty. If they are, you can set the role attribute. The following code is very quick and dirty, but will get you some of the way.
var headings = document.querySelectorAll("h1,h2,h3,h4,h5,h6");
// iterate through each heading
Array.prototype.forEach.call (headings, function (node) {
// remove all white space
var theTextContent = node.textContent.replace(/\s/g,'');
// see if there's anything left in the string
if (theTextContent.length < 1) {
// node contains no visible text, mark it as presentation
node.setAttribute("role", "presentation");
}
} );
BUT this is a risky heuristic. Some headings might not contain text nodes, yet still appear as text on screen (e.g. they may have a background image in CSS representing a text in bitmap form). Instead of adding role="presentation" to these, you absolutely should add an aria-label with the correct heading text, otherwise you'll be violating at least two WCAG success criteria. ("Images of Text" and "Headings and Labels").
If you were using style attributes it might look something like this:
<h1 aria-label="welcome" style="background:url(welcome.png);"></h1>

Related

Codemirror: Retrieve character index from span tag

So I have a codemirror instance on the left of a document, and an iframe on the right. When the code is updated in the editor, it is written to the iframe.
During this rewrite, I add an index to each and every element that is created using jQuery's $.data function so that whenever the user hovers their mouse over the element it can be highlighted in the editor.
So far I have managed to pick out the required element's position in the editor in terms of where its generated <span class="cm-tag cm-bracket"> tag is and give it a class of cm-custom-highlight.
My question is - is there any way to turn an instance of a source span tag into an actual selection within the editor?
Update: Answered my own question - see below! You can check out my resulting code here.
I answered my own question! How about that?
Turns out CodeMirror has a neat little list of nodes in its display container. All I needed to do was loop through CodeMirror.display.renderedView[lineNumber].measure.map and test each text node's parentNode property to see if it was the same as the span I had highlighted.
The map array is structured like so:
[
0: 0
1: 1
2: text
3: 1
4: 5
...
]
Every text node here refers to a piece of code in the editor and the numbers before and after refer to its character index, so it was pretty easy to find the index that I needed:
var span = $('span.cm-custom-highlight', CodeMirror.display.lineDiv),
lineNumber = span.closest('.CodeMirror-line').closest('div[style]').index(),
lineView = CodeMirror.display.renderedView[lineNumber].measure.map,
char = 0;
for(var i in lineView.measure.map)
{
if(!char &&
typeof lineView.measure.map[i] == 'object' &&
lineView.measure.map[i].parentNode && span[0] == lineView.measure.map[i].parentNode)
{
char = lineView.measure.map[i - 1];
}
}
Sure it's a little messy, but it gets the job done nicely.
You will get better results when using markText rather than directly messing with the editor's DOM. The DOM and view data structure aren't part of the interface, and will change between versions. The editor can also update its DOM at any moment, overriding the changes you made.

How can I create tags using Rangy.js without a class attribute?

I've been playing with Rangy.js for selection ranges and so far really like it. I'm looking to wrap a selection range's text nodes within a certain tag and toggle this upon button click. I have it working great using the cssClassApplierModule with the exception of (and it makes sense due to the name) I HAVE to also give the dom element a class that it's applying to itself.
So right now when I select a range and apply for instance a strong tag, my end result is:
Text text text <strong class="test"> selected text </strong> text text text
And I'd like it to be:
Text text text <strong> selected text </strong> text text text
The code I have so far is as follows:
function gEBI(id) {
return document.getElementById(id);
}
var action;
function toggleAction() {
action.toggleSelection();
}
rangy.init();
// Enable buttons
var cssClassApplierModule = rangy.modules.CssClassApplier;
// Next line is pure paranoia: it will only return false if the browser has no support for ranges,
// selections or TextRanges. Even IE 5 would pass this test.
if (rangy.supported && cssClassApplierModule && cssClassApplierModule.supported) {
action = rangy.createCssClassApplier("test", {
elementTagName: "strong",
elementProperties: { }
});
var toggleActionButton = gEBI(nsID);
toggleActionButton.disabled = false;
toggleActionButton.ontouchstart = toggleActionButton.onmousedown = function () {
toggleAction();
return false;
};
}
I tried "" and null instead of "text" as the css class being passed, and it will toggle, but no longer toggle off and is obviously not the correct solution.
Any help appreciated.. Thanks!
Rangy's CSS class applier won't let you do this, unfortunately. The fundamental problem is that it relies on the CSS class to decide which elements and text nodes to surround or add/remove classes from. It's considerably simpler to detect the presence of a class than the more general case of detecting a style, such as boldness.
I did some work last year on a more ambitious and generic execCommand module that would do what you want. It got as far as a working demo but I got bogged down in tricky edge cases and stopped working on it. I do intend to go back to it but it's likely to be months before anything is ready.

Is it possible to calculate (compute) resulting css style manually?

Is it possible to compute resulting css style on the element manually (without need to render it)?
Lets say I'm supposed to have an HTML structure:
<p style="some_style1">
<span style="some_style2">
<span style="some_style3">
TEXT
</span>
</span>
</p>
I know what are some_style1, some_style2, some_style3 in terms of JS object (for example i have data for each element like: {font: 'Times New Roman' 12px bold; text-align: center;})
I want to MANUALLY (without need to render in browser the whole structure) compute resulting style that will effect "TEXT".
What algorithm (or solution) should I use?
There exist browsers that don't need rendering in a window (headless browser). You can load a page and query what you want. It won't be easier than in a normal browser to obtain what you ask though.
JSCSSP is a CSS parser written in cross-browser JavaScript that could be a first step to achieve what you want from scratch or quite. Give it a stylesheet and it'll tell you what a browser would've parsed. You still must manage:
the DOM,
inheritance of styles,
determine which rules apply to a given element with or without class, id, attributes, siblings, etc
priorities of selectors
etc
Its author is D. Glazman, co-chairman of the W3C CSS group and developer of Kompozer, NVu and BlueGriffon so it should parse CSS as expected :)
The simplest thing I can think of is to wrap the whole thing in a a container that you set display: none on, and append it to the DOM. The browser won't render it, but you'll then be able to query the computed style.
Here's an example showing how jQuery can't find the style information when the structure isn't connected to the DOM, but when it is, it can:
jQuery(function($) {
// Disconnected structure
var x = $("<p style='color: red'><span style='padding: 2em'><span style='background-color: white'>TEXT</span></span></p>");
// Get the span
var y = x.find("span span");
// Show its computed color; will be blank
display("y.css('color'): " + y.css('color'));
// Create a hidden div and append the structure
var d = $("<div>");
d.hide();
d.append(x);
d.appendTo(document.body);
// Show the computed color now; show red
display("y.css('color'): " + y.css('color'));
// Detach it again
d.detach();
function display(msg) {
$("<p>").html(String(msg)).appendTo(document.body);
}
});
Live copy | source
I can't guarantee all values will be exactly right, you'll have to try it and see; browsers may defer calculating some things until/unless the container is visible. If you find that some properties you want aren't calculated yet, you may have to make the div visible, but off-page (position: absolute; left: -10000px);
I found some articles about this: Can jQuery get all styles applied to an element on Stackoverflow.
Also this one on quirksmode: Get Styles that shows the following function:
function getStyle(el,styleProp)
{
var x = document.getElementById(el);
if (x.currentStyle)
var y = x.currentStyle[styleProp];
else if (window.getComputedStyle)
var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp);
return y;
}
This allows you to query for style properties
Styles override each other in the order in which they're defined: So anything in some_style3 that overrides the same selector in some_style2, say, will do. Otherwise, it will just be a union of the sets of selectors.
EDIT Some selectors won't override, but instead act relatively on a previous definition, so you've got to be careful about that.

Get specified texts in a div, than search for them in a different div

I am trying to get texts from a div, than i want to search for these titles on the same page, but in a different div. And if one of the title exist there, i want to put some text after it. I tried to do it, but i don't know what is the problem. Last time i tried it with this jquery code:
var cim = $.trim($('.hirblokk span.comments:contains("új")').parent(".hirblokk").children("h3").text());
jQuery.each(cim, function(X) {
$("ul.s_hir.show li.hir a:contains(X)").find("small").append(" (Új!)");
return (this == cim.length);
});
As you can see i put the texts what i wanted to 'cim'(it is working). Than i tried (line 3) to check if one of the 'ul.s_hir.show li.hir a' contains one of the text, and if it containes, i put (append) something in the small tag (there is a small tag inside a tag : Text..)(this is not working). I tried it in more ways, but none of them worked.
If i write:
$("ul.s_hir.show li.hir a:contains(a)").find("small").append(" (Új!)");
than it will put ' (Új)' after every small tag when the a contains a character. So it looks like the problem is how i want to check if it a contains one of the text.
Oh, and i can get more than whan text for example: 'I am new' and 'Oh, hello darling' and only one of them contains *ul.s_hir.show li.hir a*
I'm not sure I have fully understood what text you want to search, but I see several problems:
your cim var is a single string: as jQuery docs explains, the result of the .text() method is a string containing the combined text of all matched elements http://api.jquery.com/text/ . So if you have multiple elements matched with your selector, cim will be a string of all text concatenated.
jQuery.each() iterate on each character of cim, and X is the index of the character in the string, not the value
in your third line, X is not evaluated as a var because it's in double quotes.
I don't understand what you're expecing with return (this == cim.length) : you're comparing a number (cim.length) with a string (the value of each currently evaluated).
Try something like this:
// titles contain all the h3 elements you're searching
var titles = $('.hirblokk span.comments:contains("új")').parent(".hirblokk").children("h3"));
// you're iterating on each title
jQuery.each(titles, function(index,title) {
// you're searching links elements containing each title text
var text = $.trim($(title).text());
$("ul.s_hir.show li.hir a:contains("+text+")").find("small").append(" (Új!)");
});

Applying DIV/Span tag to a word by specific co-ordinates

Sample HTML Data
<body style="width:300px;">
<h3>Long-Text</h3>
A simple tool to store and display texts longer than a few lines.
The search button will highlight all the words matching the name of objects that are members of the classes listed in searchedClasses, itself a member of the KeySet class. The highlighted words are hypertext.
Edit invokes wscripts/acedb.editor, which by default launches emacs. Edit that file to start another editor in its place.
Save will recover from the emacs but will not destroy it.
Read will read a text file, so you could Search it.
**general** grep is a way to annotate a set of longtexts versus the searchedClasses. It outputs an ace file that you can then hand check and read back in acedb to create XREF from longTexts to genes etc.
<h3>World Wide NotePad</h3>
World wide notepad is a small text editor similar to Microsoft's notepad but has some more useful features like an auto typer to make typing the same sentence or word more easy, also World Wide NotePad has a text to speech feature which reads all text in the current open document and speaks it out load to you.
<h3>Etelka Wide Text Pro Bold Italic</h3>
</body>
For example -> "general" (between ** ) is at x=0 and y=465. I know the x,y position. But How to highlight a word located at specific location ?
Let me explain once again. I want to highlight a word by location.
for example I have a location value (x,y)=(0,625). I want to extract the first word by that location ( assume - at that location - we have word "World" ) Then how to highlight that word ?
Edit :
Here Y co-ordinate is absolute position of entire html document.
The only method I can think of involves wrapping every word in a span element, and then using document.elementFromPoint(x,y) to get the span element at the given location. Something like this:
function highlightWordAtXY(x, y) {
// Get the element containing the text
var par = document.elementFromPoint(x, y),
// textContent or innerText ?
t = "textContent" in par ? "textContent" : "innerText",
// Get the text of the element. No pun intended on the par[t].
text = par[t],
result;
// Wrap a span around every word
par.innerHTML = text.replace(/\b(\w+)\b/g, "<span>$1</span>");
// Get the elementFromPoint again, should be a span this time
result = document.elementFromPoint(x, y);
// Check that we actually clicked on a word
if (result == par)
return false;
// Wrap HTML text around the text at x, y
result[t] = '<span class="highlight">' + result[t] + '</span>';
// Restore the content with the wrapped text
par.innerHTML = par[t];
}
Example at http://jsfiddle.net/BSHYp/1/show/light/ - click a word and watch it highlight.
Some important caveats here:
Each block of text must be wrapped in an element (such as <p> or <div>). You should be wrapping paragraphs in <p> tags anyway,
The element at the given location (x, y) must only have text in it, no child HTML elements. Text nodes with sibling HTML elements will have them removed (e.g. Clicking "Some" or "here" in Some <b>text</b> here will remove the <b> tags). Dividing them into separate <span> elements would be the only solution without building a much more complex routine,
IE will throw an "Unknown runtime error" if you try and add a block level element to a <p> tag,
On very, very, very large blocks of text you might run into performance issues. Break them up where applicable.

Categories

Resources