Kendo UI grid accessibility for button e.g. Excel Export - html

How can I set the icon of the grid button to aria-hidden="true"?
$("#grid").kendoGrid({
toolbar: ["excel"],
excel: {
allPages: true
},
dataSource: {
transport: {
read: {
url: "https://demos.telerik.com/kendo-ui/service/products",
dataType: "jsonp"
}
},
pageSize: 10
},
pageable: true
});
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2020.1.219/styles/kendo.default-v2.min.css"/>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2020.1.219/js/jszip.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2020.1.219/js/kendo.all.min.js"></script>
<div id="grid"></div>
Current html:
<div class="k-header k-grid-toolbar"><a role="button" class="k-button k-button-icontext k-grid-excel" href="#"><span class="k-icon k-i-file-excel"></span>Export to excel</a></div>
Desired result:
<div class="k-header k-grid-toolbar"><a role="button" class="k-button k-button-icontext k-grid-excel" href="#"><span aria-hidden="true" class="k-icon k-i-file-excel"></span>Export to excel</a></div>

The icon has class k-i-file-excel. Use that class to select the element and set the attribute:
$("#grid .k-i-file-excel").attr("aria-hidden","true");

You don't need to do anything.
Test your application with a keyboard and screen reader. Since you're not modifying tab indices, either the outer <a> tag will get the focus (and should be correctly announced as "Export to excel"), or nothing will. Your user will know what the button is for.

Related

Popover Bootstrap pass delay show and hide values by HTML attributte

I'm needing to pass different values delay for show and hide attributes to a popover, and I'm needing an HTML attribute solution. I've tested this code and it works passing an string in data-delay attribute. I'm using Bootstrap 3.
<span style="white-space: nowrap;" data-toggle="popover" data-delay="1000" data-trigger="hover" data-html="true" data-content="content of my popover>
How can I pass different values for show and hide delays using HTML attributes?
Thanks in advance!
You can use the data-delay attribute, however this will set both the 'show' and 'hide' time delays. If you wish to set them individually you'll need to configure the popover. With jQuery you can easily do so:
$(function() {
// This will enable and configure all popovers present in the page
$('[data-toggle="popover"]').popover({
delay: {
"show": 500,
"hide": 100
}
})
})
.container {
padding-top: 40px;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<div class="container">
<a tabindex="0" class="btn btn-lg btn-success" role="button" data-toggle="popover" data-trigger="focus" title="Dismissible popover" data-content="And here's some amazing content. It's very engaging. Right?">click me</a>
</div>
You can pass a number or an object. Therefore, you can specify 'show' and 'hide' delays like this :
<span
data-toggle="popover"
data-delay="{'show':0, 'hide':200}"
data-trigger="hover"
data-html="true"
data-content="content of my popover"
>
TEST
</span>
for Bootstrap v5, you can instantiate it like this:
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(el => {
if (el.hasAttribute('data-bs-delay-show')) {
return new Tooltip(el, {
delay: {
show: el.getAttribute('data-bs-delay-show'),
hide: el.getAttribute('data-bs-delay-hide') || 0,
},
});
}
return new Tooltip(el);
});
and then use data-bs-delay-show and data-bs-delay-hide attributes on the element.

Why do bootstrap tooltips not work in bootstrap modals?

My tooltips are working on the mainpage perfectly. In a modal which is generated later by an ajax call the tooltips won't work.
I have included the following code inside the generated modal (result of the ajax call).
To re-ini the tooltips
<script>
$('.tooltips').tooltip();
</script>
In the html of the modal
<button class="btn btn-lg default tooltips blue-madison" type="submit"
name="O" data-container="body" data-placement="top"
data-original-title="THIS TEXT FOR TOOLTIPS">
<i class="fa fa-industry blue-madison"></i> BUTTON1
</button>
<button class="btn btn-lg default tooltips green-jungle" type="submit"
name="P" data-container="body" data-placement="top"
data-original-title="THIS TEXT FOR TOOLTIPS">
<i class="fa fa-user green-jungle "></i> BUTTON2
</button>
Why don't the tooltips show- what I'm doing wrong?
The issue is because of the z-index of modal and tooltip. You can try this,
.tooltip {
z-index: 100000000;
}
Probably it's because you should call $('.tooltips').tooltip(); after the modal's content have been inserted in the document.
Otherwise, please post a fiddle with your current code where we can test it.
Another solution is to bind the tooltip to the modal using the container option:
$('#modal').on('shown.bs.modal', function() {
console.log("modal show");
$('.tooltips').tooltip({
container: $(this)
});
});
Maybe this helps someone: I had a case when needed with ajax to populate & display a bootstrap modal (render view) on click (calling showModal(url, event) below); bootstrap tooltip and also fengyuanchen/datepicker were unresponsive, so I managed to trigger them after detecting modal loading, like this:
function showModal(url, event) {
$.when(
$.ajax({
url: url,
method: 'GET',
success: function (data) {
$('#modal-wrapper').html(data);
}
})
).then(function() {
$('.loaded_modal').modal().on('shown.bs.modal', function() {
$('[data-toggle="datepicker"]').datepicker({
format: "dd/mm/yyyy",
autoclose: true,
todayHighlight: true,
zIndex: 1070,
container: '.modal'
});
$('.modal [data-toggle="tooltip"]').tooltip({trigger: 'hover'});
// could also be on click {trigger: 'hover click'}
});
});
If you are using react I had success with a different answer. All you have to
do is give the parent container a ref and then in the overlayTrigger component you just have to pass in the ref as a param to the container.
import React, { Component } from 'react';
import { OverlayTrigger, Tooltip } from 'react-bootstrap';
class random extends Component {
constructor(props) {
super(props);
this.ref= React.createRef()
}
render() {
return (
<div ref={this.ref}>
<OverlayTrigger
placement="top"
container={this.ref}
overlay={
<Tooltip data-container="body">Some text</Tooltip>
}
>
<span className="d-inline-block">
<i className="mdi mdi-help-circle pointer"></i>
</span>
</OverlayTrigger>
</div>
);
}
}
Best way to fix this behaviour is by adding this prop inside your md-tooltip:
md-z-index="9999"
or a different z-index.
No need to hardcode this in the css.
You can also define the z-index in your scope variable inside your controller as the following
// in controller
$scope.btnOptions = {
isOpen:false,
label: 'test button',
class: 'md-scale',
zIndex: 99999
};
in you html ( normally I would use {{}} to print the variable, but I'm on laravel so I used <% %> instead
<md-button aria-label="Édit" class="md-fab md-raised md-mini">
<md-tooltip md-direction="top" md-z-index="<% btnOptions.zIndex %>">Mode édition</md-tooltip>
<i class="far fa-edit"></i>
</md-button>

Durandaljs generating sub menu from json

Alright, I am fairly new to durandal. I am really struggling getting trying to accomplish this.
Here is what I am trying to do: There is a main navigation that is compromised of an inbox, draft, submitted, etc. Clicking on these, gives the user a submenu that comes out to the side of the main navigation. This submenu is generated by json data that I get from the server. Clicking an an option from the submenu should open the document in a viewer viewmodel based on the id of the document.
Ex.
User clicks on inbox
2. Menu comes out that has documents from their inbox. User clicks on view
3. Document that is clicked is displayed to the user.
4. So when they get to this point, I want the url to be mysite.com/#inbox/viewer/123456 (123456 is documentid)
I just haven't been able to find decent examples that are similar to this, and was wondering if someone could help point me in the right direction.
I kind of did it by making each main navigation link to a module, and have a document window in each of those modules, but I thought there had to be a better way. So what I am trying to do is keep my subnavigation in the shell. I don't want to have a module for each of my main navigation items.
Here is my shell code right now:
shell.js
define(['durandal/system', 'services/logger', 'plugins/router', 'durandal/activator'], function (system, logger, router, activator) {
//#region Internal Methods
function log(msg, data, showToast) {
logger.log(msg, data, system.getModuleId(shell), showToast);
}
function logError(msg, data, showToast) {
logger.logError(msg, data, system.getModuleId(shell), showToast);
}
function navigateRoute(hashValue) {
var target = hashValue.hash;
$("body").addClass("subnav-active");
document.cookie = "subNav=true";
$(target).addClass("current");
router.navigate(target, {replace: true, trigger: false });
}
var routes = [
{ route: '', hash: '#home', moduleId: 'home', title: '', nav: false, cssClass: 'icon-inbox' },
{ route: 'inbox', hash: '#inbox', moduleId: 'inbox', title: 'Inbox', nav: true, cssClass: 'icon-inbox' },
{ route: 'drafts', hash: '#drafts', moduleId: 'drafts', title: 'Drafts', nav: true, cssClass: 'icon-file-alt' },
{ route: 'submitted', hash: '#submitted', moduleId: 'submitted', title: 'Submitted', nav: true, cssClass: 'icon-hand-right' },
{ route: 'completed', hash: '#completed', moduleId: 'completed', title: 'Completed', nav: true, cssClass: 'icon-check' },
{ route: 'settings', hash: '#settings', moduleId: 'settings', title: 'Settings', nav: true, cssClass: 'icon-cog' }
];
//#endregion
var shell = {
activate: function () {
router.on('router:route:not-found', function (fragment) {
logError('No Route Found', fragment, true);
});
return router.makeRelative({ moduleId: 'viewmodels' }) // router will look here for viewmodels by convention
.map(routes) // Map the routes
.buildNavigationModel() // Finds all nav routes and readies them
.activate(); // Activate the router
}
,
router: router,
navigateRoute: navigateRoute
};
return shell;
});
shell.html
<div class="main-wrapper wrapper">
<div class="container_template">
<header class="pageheader">
<nav class="mobile-nav">
<a class="menu-button" href="#main-navigation">
<i class="icon-reorder"></i><span>Menu</span>
</a>
</nav>
<h1 class="logo">template</h1>
<nav class="nav-user">
<a class="close" href="#">
<i class="icon-chevron-right"></i>
<span>Main</span>
</a>
</nav>
</header>
<!-- Begin Header/Navigation -->
<div class="main-navigation" role="banner">
<div class="main-navigation-inner inner">
<nav class="navigation">
<ul data-bind="foreach: router.navigationModel">
<li>
<a class="nav-button" data-bind="attr: {'data-target': hash,}, css: {'nav-button' : isActive, active: isActive }, click: function(hash) { $root.navigateRoute(hash);return true},">
<i data-bind="css: cssClass"></i>
<span data-bind="html: title"></span>
</a>
</li>
</ul>
</nav>
</div>
</div>
<!-- End Header/Navigation -->
<!-- Sub Navigation Elements -->
<!--This is my sbumenu-->
<div id="inbox" class="navigation-sub">
<div class="navigation-sub-inner inner">
<div class="navigation-sub-header">
<a class="close" href="#">×</a>
<h3>Inbox</h3>
</div>
<div class="navigation-sub-search">
<form>
<input type="text" placeholder="Search" />
<button>Go</button>
</form>
</div>
<ul data-bind="contentsOfInbox">
<li>
<a data-bind="href : linktoDocuemntViewer" href="" class="form-open">
<i class="icon-file-alt"></i><span data-bind="html: NameofDocumentHere"></span>
<span class="date" data-bind="html: DateOfDocumentHere"></span>
</a>
</li>
</ul>
</div>
</div>
<!-- End SUB NAV -->
<!--Begin Main-->
<!--Documents would appear here-->
<div class="main" data-bind=" router: { cacheViews: false }">
</div>
<!-- End Main -->
</div>
Thanks for any help
For what you are trying to do it sounds like using the navigationModel will not work. From my experience, the navigationModel and route are a 1 to 1 relationship. What you are trying to do is have one route with parameters tied to multiple menu items. To do this you should separate your menus and routes. Remember at the heart of everything you are just binding javascript objects and collections to html elements. The router.navigationModel property is just that, a collection of javascript objects that is built from your defined routes. When you call .buildNavigationModel() that is what it is doing, building up a new collection of javascript objects for you to bind to your menu html. There is nothing stopping you from creating a completely new property on your shell viewmodel that contains your own custom collection of javascript menu objects and binding that to your UL/LI navigation html. If you make this new menu collection a computedObservable you could then add to it in a lazy fashion as you needed to and since it is bound with knockout, changes would appear in the UI automatically. I have done this on a number of different projects and it works fine. I build a menu table in the backend and then just return only the items that the user has access to and use that to build my UI menu. To make navigation work, I keep the urlhash in the table and bind that to the anchor tags. When you are creating routes, you don't have to set the hash property, the router plugin will take care of that for you. So for your requested example, create a menu collection like this:
{ displayname: 'Inbox' cssClass: 'icon-inbox', urlHash: '' children[
{ displayname: 'Doc 1' cssClass: 'icon-message', urlHash: 'inbox/viewer/12345' },
{ displayname: 'Doc 2' cssClass: 'icon-message', urlHash: 'inbox/viewer/12346' },
{ displayname: 'File 1' cssClass: 'icon-message', urlHash: 'inbox/viewer/12347' }]}
create a route like this:
{ route: 'inbox/viewer/:messageId', moduleId: 'home', title: '', nav: false, cssClass: 'icon-inbox' },
see the durandal docs for info on passing parameters to routes
expose this menu as a computedObesrvable from your shell and bind that to you UL/LI menu html instead of the router.NavigationModel. When needed, change the contents of the children property of the inbox menu with new data from the server.

jQuery UI Dialog not opened for second time

jQuery UI Dialog not opened for second time
I have series of data as below
html
<a href="javascript:void(0);" class="popup_1" pop_val="abc" >Dummy Text</a>
<a href="javascript:void(0);" class="popup_1" pop_val="vbg" >Dummy Text</a>
<a href="javascript:void(0);" class="popup_1" pop_val="aere" >Dummy Text</a>
<a href="javascript:void(0);" class="popup_1" pop_val="vbb" >Dummy Text</a>
<div id="dialog" title="TEST MODAL">
Loading...
</div> <!-- dialog -->
jQuery
Script One
This one runs perfect
<script>
$(".popup_1").bind('click', function (e) {
var pop_value = $(this).attr("pop_val");
console.log(pop_value);
$("#dialog").dialog({
autoOpen: false,
width: 700,
modal: true,
});
$("#dialog").dialog("open");
});
</script>
Script Two
This script, runs for the first time and second time its not working,
instead it gives an error
Uncaught TypeError: Object [object HTMLAnchorElement] has no method
'attr'
[ var pop_value = $(this).attr("pop_val"); ]
<script>
$(".popup_1").bind('click', function (e) {
var pop_value = $(this).attr("pop_val");
console.log(pop_value);
$("#dialog").dialog({
autoOpen: false,
width: 700,
modal: true,
});
$.post("ajx_page.cfm?PID="+pop_value, {}, function(return_data){
$("#dialog").html(return_data);
});
$("#dialog").dialog("open");
});
</script>
I have no clue, why it throws an error. I have gone throught other question on SO, but could not get perfect solution.

HTML inside Twitter Bootstrap popover

I am trying to display HTML inside a bootstrap popover, but somehow it's not working. I found some answers here but it won't work for me. Please let me know if I'm doing something wrong.
<script>
$(function(){
$('[rel=popover]').popover({
html : true,
content: function() {
return $('#popover_content_wrapper').html();
}
});
});
</script>
<li href="#" id="example" rel="popover" data-content="" data-original-title="A Title">
popover
</li>
<div id="popover_content_wrapper" style="display: none">
<div>This is your div content</div>
</div>
You cannot use <li href="#" since it belongs to <a href="#" that's why it wasn't working, change it and it's all good.
Here is working JSFiddle which shows you how to create bootstrap popover.
Relevant parts of the code is below:
HTML:
<!--
Note: Popover content is read from "data-content" and "title" tags.
-->
<a tabindex="0"
class="btn btn-lg btn-primary"
role="button"
data-html="true"
data-toggle="popover"
data-trigger="focus"
title="<b>Example popover</b> - title"
data-content="<div><b>Example popover</b> - content</div>">Example popover</a>
JavaScript:
$(function(){
// Enables popover
$("[data-toggle=popover]").popover();
});
And by the way, you always need at least $("[data-toggle=popover]").popover(); to enable the popover. But in place of data-toggle="popover" you can also use id="my-popover" or class="my-popover". Just remember to enable them using e.g: $("#my-popover").popover(); in those cases.
Here is the link to the complete spec:
Bootstrap Popover
Bonus:
If for some reason you don't like or cannot read content of a popup from the data-content and title tags. You can also use e.g. hidden divs and a bit more JavaScript. Here is an example about that.
you can use attribute data-html="true":
<a href="#" id="example" rel="popover"
data-content="<div>This <b>is</b> your div content</div>"
data-html="true" data-original-title="A Title">popover</a>
Another way to specify the popover content in a reusable way is to create a new data attribute like data-popover-content and use it like this:
HTML:
<!-- Popover #1 -->
<a class="btn btn-primary" data-placement="top" data-popover-content="#a1" data-toggle="popover" data-trigger="focus" href="#" tabindex="0">Popover Example</a>
<!-- Content for Popover #1 -->
<div class="hidden" id="a1">
<div class="popover-heading">
This is the heading for #1
</div>
<div class="popover-body">
This is the body for #1
</div>
</div>
JS:
$(function(){
$("[data-toggle=popover]").popover({
html : true,
content: function() {
var content = $(this).attr("data-popover-content");
return $(content).children(".popover-body").html();
},
title: function() {
var title = $(this).attr("data-popover-content");
return $(title).children(".popover-heading").html();
}
});
});
This can be useful when you have a lot of html to place into your popovers.
Here is an example fiddle: http://jsfiddle.net/z824fn6b/
You need to create a popover instance that has the html option enabled (place this in your javascript file after the popover JS code):
$('.popover-with-html').popover({ html : true });
I used a pop over inside a list, Im giving an example via HTML
<a type="button" data-container="body" data-toggle="popover" data-html="true" data-placement="right" data-content='<ul class="nav"><li><a href="#">hola</li><li><a href="#">hola2</li></ul>'>
You only need put data-html="true" in the link popover. Is gonna work.
This is an old question, but this is another way, using jQuery to reuse the popover and to keep using the original bootstrap data attributes to make it more semantic:
The link
<a href="#" rel="popover" data-trigger="focus" data-popover-content="#popover">
Show it!
</a>
Custom content to show
<!-- Let's show the Bootstrap nav on the popover-->
<div id="list-popover" class="hide">
<ul class="nav nav-pills nav-stacked">
<li>Action</li>
<li>Another action</li>
<li>Something else here</li>
<li>Separated link</li>
</ul>
</div>
Javascript
$('[rel="popover"]').popover({
container: 'body',
html: true,
content: function () {
var clone = $($(this).data('popover-content')).clone(true).removeClass('hide');
return clone;
}
});
Fiddle with complete example:
http://jsfiddle.net/tomsarduy/262w45L5/
This is a slight modification on Jack's excellent answer.
The following makes sure simple popovers, without HTML content, remain unaffected.
JavaScript:
$(function(){
$('[data-toggle=popover]:not([data-popover-content])').popover();
$('[data-toggle=popover][data-popover-content]').popover({
html : true,
content: function() {
var content = $(this).attr("data-popover-content");
return $(content).children(".popover-body").html();
},
title: function() {
var title = $(this).attr("data-popover-content");
return $(title).children(".popover-heading").html();
}
});
});
On the latest version of bootstrap 4.6, you might also need to use sanitize:false for adding complex html.
$('.popover-with-html').popover({ html : true, sanitize : false })
I really hate to put long HTML inside of the attribute, here is my solution, clear and simple (replace ? with whatever you want):
<a class="btn-lg popover-dismiss" data-placement="bottom" data-toggle="popover" title="Help">
<h2>Some title</h2>
Some text
</a>
then
var help = $('.popover-dismiss');
help.attr('data-content', help.html()).text(' ? ').popover({trigger: 'hover', html: true});
You can change the 'template/popover/popover.html' in file 'ui-bootstrap-tpls-0.11.0.js'
Write: "bind-html-unsafe" instead of "ng-bind"
It will show all popover with html.
*its unsafe html. Use only if you trust the html.
For Bootstrap >= 5.2
To enable HTML content in Popovers: data-bs-html="true"
Example:
<a href="#"
data-bs-toggle="popover"
data-bs-title="A Title"
data-bs-html="true"
data-bs-content="This is <strong>bold</strong>">popover</a>
Doc: https://getbootstrap.com/docs/5.3/components/popovers/#options
You can use the popover event, and control the width by attribute 'data-width'
$('[data-toggle="popover-huongdan"]').popover({ html: true });
$('[data-toggle="popover-huongdan"]').on("shown.bs.popover", function () {
var width = $(this).attr("data-width") == undefined ? 276 : parseInt($(this).attr("data-width"));
$("div[id^=popover]").css("max-width", width);
});
<a class="position-absolute" href="javascript:void(0);" data-toggle="popover-huongdan" data-trigger="hover" data-width="500" title="title-popover" data-content="html-content-code">
<i class="far fa-question-circle"></i>
</a>
Actually if you're using Bootstrap5 with Django then their method of passing in content as a string is perfect and in line with Django's template inclusion. You can create a template file with whatever partial HTML that you need, so for example, there is not X-editable for Bootstrap5 that seems to work, so maybe you'd want to make a line edit together with Ok|Cancel buttons as content. Anyway, this is what I mean:
<button data-bs-content="{% include './popover_content.html' %}" type="button" class="btn btn-lg btn-danger" data-bs-toggle="popover" title="Popover title" >
Click to toggle popover
</button>
Where my settings.py templates section looks like this:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True, # True is necessary for django-bootstrap5 to work!
'OPTIONS': {
'debug': True,
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
I keep my templates (of every single app) in a <project dir>/templates/<app name> folder. I have MyMainApp/popover_content.html right beside MyMainApp/home.html wher the above example code was tested. But if you keep your templates in each app's Django folder, then you'll need to add "MyApp/templates" to the TEMPLATES[0]{'DIRS': ['MyApp/templates', 'MyApp2/templates']} list.
So at least this will give you the ability to put your popover HTML in the usual, syntax-highlighted Django template format, and makes good use of modularizaton of your Django template into components.
I'm personally going to use it to make an editable label (title and description fields of some data in my app).
One drawback is that if you use doublequotes (") when including: "{% include './popover_content.html' %}", then you must use single quotes all throughout the popover_content.html` template.
You also need to enable html for popovers, so your site-wide popover initializer would go:
<script type="text/javascript">
$(document).ready(() => {
var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'))
var popoverList = popoverTriggerList.map(
function (popoverTriggerEl) {
return new bootstrap.Popover(popoverTriggerEl, {
html: true,
});
});
});
</script>
Here is the (unstyled) result. In conclusion, use the default-provided string method of passing in, and pass in an included Django template file. Problem solved!