I would like to have the jQueryUI tooltip work on disabled Buttons and Inputs as well. How can I make this happen?
Included is a sample showing various inputs and buttons, both enabled and disabled and how the jQueryUI tooltip seems to skip evaluation of the disabled elements.
Please click on the field/button labels to open the tooltips. My users don't like hover based tooltips on INPUTs and hover does not work on mobile.
If you hover over the disabled INPUT and BUTTON the browser tooltip will appear but not the jQueryUI version. This is obvious because the browser version does not evaluate the HTML but shows it raw.
Note: This question is NOT a duplicate of Show tooltip for disabled items, because that question does not ask about actual disabled tags (buttons or inputs)
// Disable HOVER tooltips for input elements since they are just annoying.
$("input[title]").tooltip({
disabled: true,
content: function() {
// Allows the tooltip text to be treated as raw HTML.
return $(this).prop('title');
},
close: function(event, ui) {
// Disable the Tooltip once closed to ensure it can only open via click.
$(this).tooltip('disable');
}
});
// Basic tooltips for the Buttons only but format HTML.
$("button[title]").tooltip({
content: function() {
// Allows the tooltip text to be treated as raw HTML.
return $(this).prop('title');
}
});
/* Manually Open the Tooltips */
$(".ui-field-help").click(function(e) {
var forId = e.target.getAttribute('for');
if (forId) {
var $forEl = $("#" + forId);
if ($forEl.length)
$forEl.tooltip('enable').tooltip('open');
}
});
// The following is only to load the CSS....
function loadCSS(filename) {
var file = document.createElement("link");
file.setAttribute("rel", "stylesheet");
file.setAttribute("type", "text/css");
file.setAttribute("href", filename);
document.head.appendChild(file);
}
loadCSS("https://code.jquery.com/ui/1.12.1/themes/start/jquery-ui.css");
.ui-field-help {
text-decoration: underline;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"></script>
<table width=100%>
<tr>
<td><label for="A000" class="ui-field-help">Enabled Input</label></td>
<td><input type="Text" id="A000" title="title #A000<hr>Fancy <i>HTML</i>..."></td>
</tr>
<tr>
<td><label for="B000" class="ui-field-help">Disabled Input</label></td>
<td><input disabled=disabled type="Text" id="B000" title="title #B000<hr>Fancy <i>HTML</i>..."></td>
</tr>
<tr>
<td><label for="E000" class="ui-field-help">Enabled Button</label></td>
<td><button id="E000" title="title #E000<hr>Fancy <i>HTML</i>...">Enabled Button</button></td>
</tr>
<tr>
<td><label for="D000" class="ui-field-help">Disabled Button</label></td>
<td><button disabled=disabled type="Text" id="D000" title="title #D000<hr>Fancy <i>HTML</i>...">Disabled Button</button></td>
</tr>
</table>
After not finding the answer I resolved the problem by looping through all disabled items with a [title] and processing them individually to move the tooltip to the label for that input element.
$("[title]:disabled", $container).each(function (ix, el) {
// Since the jQueryUI tooltips don't work on disabled controls we remove them
// and then attempt to add them to the elements label.
var title = el.title;
el.title = ''; // Clear the title to avoid the browser tooltip
// Look for a Label attached to the element and add the tooltip there.
$('label[for=' + el.id + ']').attr('title', title).tooltip({
content: function () {
// Allows the tooltip text to be treated as raw HTML.
return $(this).prop('title');
}
});
});
Related
I would like to show a tooltip on a text input that has a ui-state-disabled class.
I took a peek to the tooltip source code and I couldn't find something that checks against that particular class. So I don't know why it won't show.
As far as I can tell, the elements aren't disabled per se, they just have a class applied to them.
So, how can I show a tooltip on elements that have that class? I don't want to use a wrapper or anything like that. Maybe extending through widget factory...
Here's a sample code
HTML
<input name="#1" class="text" data-tooltip="message A">
<input name="#2" class="text" data-tooltip="message B">
<br>
<button id="disable">disable input #2</button>
<button id="enable">enable input #2</button>
JS
$(".text").each(function()
{
$(this).tooltip({
content: $(this).data("tooltip"),
items: ".text"
});
});
$("#disable").click(function()
{
$("input[name='#2']").addClass("ui-state-disabled");
});
$("#enable").click(function()
{
$("input[name='#2']").removeClass("ui-state-disabled");
});
FIDDLE: https://jsfiddle.net/hn1o4qs2/
See the doc (http://api.jqueryui.com/tooltip/):
In general, disabled elements do not trigger any DOM events.
Therefore, it is not possible to properly control tooltips for
disabled elements, since we need to listen to events to determine when
to show and hide the tooltip. As a result, jQuery UI does not
guarantee any level of support for tooltips attached to disabled
elements. Unfortunately, this means that if you require tooltips on
disabled elements, you may end up with a mixture of native tooltips
and jQuery UI tooltips.
Solution with wrapper
Your HTML:
<span class="input-container" data-tooltip="message A">
<input name="#1" class="text">
</span>
<span class="input-container" data-tooltip="message B">
<input name="#2" class="text">
</span>
<br>
<button id="disable">
disable input #2
</button>
<button id="enable">
enable input #2
</button>
Your Javascript
$(".input-container").each(function()
{
$(this).tooltip({
content: $(this).data("tooltip"),
items: ".input-container"
});
});
// ... The rest is the same
Solution with fake disabled-property
Here you can use a readonly attribute and a custom class for disabled input.
Playground: https://jsfiddle.net/5gkx8qec/
As I've stated in my question, I needed to get this working without adding a container or anything like that. And I was willing to extend the widget somehow...
So I read the source code more carefully and searched throught the whole repository for ui-state-disabled, and found that in widget.js there is an _on() method that at some point performs a check against that class and a flag called suppressDisabledCheck
A comment in code says
// Allow widgets to customize the disabled handling
// - disabled as an array instead of boolean
// - disabled class as method for disabling individual parts
This was very important, it gave me the clue that this check could be overriden. So a quick search in google and the widget factory had the answer:
Automatically handles disabled widgets: If the widget is disabled or
the event occurs on an element with the ui-state-disabled class, the
event handler is not invoked. Can be overridden with the
suppressDisabledCheck parameter.
So basically I did this:
$.widget("ui.tooltip", $.ui.tooltip,
{
options: {
allowOnDisabled: false
},
_on: function()
{
var instance = this;
this._super(instance.options.allowOnDisabled, {
mouseover: "open",
focusin: "open",
mouseleave: "close",
focusout: "close"
});
}
});
And then used it like this:
$(".text").each(function()
{
$(this).tooltip({
allowOnDisabled: true,
content: $(this).data("tooltip"),
items: ".text"
});
});
EDIT 2022-09-15
I was having some trouble with this implementation, so I've changed it a little bit
$.widget("ui.tooltip", $.ui.tooltip,
{
options: {
allowOnDisabled: false
},
_create: function()
{
this._super();
var instance = this;
this._on(instance.options.allowOnDisabled, {
mouseover: "open",
focusin: "open",
mouseleave: "close",
focusout: "close"
});
}
});
I have an igGrid from Infragistics using IgniteUI version 16.2.
I'm trying to make the rows draggable using the "draggable" library from jQuery UI version 1.11.4 (combined with jQuery version 1.11.3).
My "droppable" target is a div outside of the igGrid.
I'm able to drag and drop the rows just fine as long as I stay within the grid. However, as soon as I try to drag the row outside of the grid, the grid starts to scroll.
Here is my jQuery that turns the rows into "draggable" elements:
$("#grid > tbody > tr").draggable({
helper: "clone",
revert: "invalid",
cursorAt: { bottom: 0, left: 0 },
start: function (evt, ui) {
// get the id of the row being dragged
var row_id = ui.helper.prevObject.data("id");
// get a reference to the <tr> being dragged
var original_row_element = $("#grid > tbody > tr[data-id='" + row_id + "']");
// get the collection of all <tr>'s that come after the selected row
var all_rows_after_the_original = original_row_element.nextAll("tr");
// move all those rows to a temporary holding <div> outside of the grid
$("#temp_row_holder").append(all_rows_after_the_original);
},
stop: function (evt, ui) {
// get all those rows that we moved out of the grid earlier
var all_rows_after_the_original = $("#temp_row_holder").children("tr");
// move the <tr>'s back into the grid
$("#grid > tbody").append(all_rows_after_the_original);
}
});
And here is the scrollable portion of my grid once it has been rendered by the Infragistics library:
<div id="grid_scroll" class="ui-iggrid-scrolldiv ui-widget-content igscroll-touchscrollable" data-scroll="true" data-onedirection="true" data-xscroller="#grid_hscroller" style="overflow-x: hidden; overflow-y: auto; height: 311px;">
<table id="grid" role="grid" aria-describedby="grid_scroll" cellpadding="0" cellspacing="0" border="0" class="ui-iggrid-table ui-widget-content" style="table-layout: fixed;">
<colgroup></colgroup>
<tbody role="rowgroup" class="ui-widget-content ui-iggrid-tablebody ui-ig-record ui-iggrid-record">
<tr data-id="c3bf5936-8786-e711-8135-caf5c8230062" role="row" tabindex="0" class="open-hand-pointer ui-draggable ui-draggable-handle"></tr>
<tr class="ui-ig-altrecord ui-iggrid-altrecord open-hand-pointer ui-draggable ui-draggable-handle" data-id="a2a54d20-5a83-e711-8135-caf5c8230062" role="row" tabindex="0"></tr>
<tr data-id="ca784490-cb82-e711-8135-caf5c8230062" role="row" tabindex="0" class="open-hand-pointer ui-draggable ui-draggable-handle"></tr>
<tr class="ui-ig-altrecord ui-iggrid-altrecord open-hand-pointer ui-draggable ui-draggable-handle" data-id="4d95ba39-cd81-e711-8135-caf5c8230062" role="row" tabindex="0"></tr>
<tr data-id="7b02f501-cb81-e711-8135-caf5c8230062" role="row" tabindex="0" class="open-hand-pointer ui-draggable ui-draggable-handle"></tr>
</tbody>
</table>
</div>
As you can see, my current solution is to remove all sibling <tr>'s from the grid so it won't scroll when I drag my row. This solution is working just fine, but it's obviously not acceptable from the end-user perspective because all of their rows suddenly disappear when they start dragging.
It seems like there would be some CSS or javascript that could modify the grid on the "start" event to prevent it from scrolling. I have also tried fiddling with the overflow-y property because to my CSS-ignorant brain, that seems like the obvious answer, but nothing has helped.
EDIT : Here is a JS Fiddle as requested
You can use scroll option. It is true by default and causes auto-scrolls while dragging. You need scroll: false for prevent auto-scrolls like this:
$("#GRIDRFDList > tbody > tr").draggable({
helper: "clone",
revert: "invalid",
cursorAt: { bottom: 0, left: 0 },
scroll: false // Add this line
});
Online output (fiddle)
This sorts in one direction, but not the other. Is there something wrong with the table specifications. It wold be great if someone could post an HTML sample that has sorting working in both directions on a column with dollar values that include commas in them.
// create sorter
<script type="text/javascript" id="js">
$(document).ready(function() {
// call the tablesorter plugin
$("table.tablesorter").tablesorter({
// enable debug mode
debug: false
});
});
</script>
Not sure if a prefix is needed here (table.tablesorter):
// add parser through the tablesorter addParser method
<script type="text/javascript" id="js">
$.tablesorter.addParser({
// set a unique id
id: 'money',
is: function(s) {
// return false so this parser is not auto detected
return false;
},
format: function(s) {
return s.toLowerCase().replace("\$","").replace(",","");
},
// set type, either numeric or text
type: 'numeric'
});
Not sure if table.tablesorter is needed here:
// specify column
$(function() {
$("table.tablesorter").tablesorter({
headers: {
// column to be handled specially
7: {
sorter:'money'
}
}
});
});
</script>
The following is the top of the table:
<table cellspacing="1" class="tablesorter">
<thead>
<tr>
<th>Name</th>
<th>Major</th>
<th>Gender</th>
<th>English</th>
<th>Japanese</th>
<th>Calculus</th>
<th>Overall grades</th>
<th>Money</th>
</tr>
</thead>
<tbody>
<tr>
<td>Student01</td>
<td>Languages</td>
<td>male</td>
<td>80</td>
<td>70</td>
<td>75</td>
<td>bad</td>
<td>$1.00</td>
</tr>
Since you are working with numbers, you'll need to parse the string into a real number. Change this line in your parser:
format: function(s) {
return parseFloat( s.toLowerCase().replace("\$","").replace(",","") );
}
I have a table with left and right col. Inside the cols, some small tables (as elements) from PHP loop.
I would like to make possible to drag and drop the elements from left to right cols AND also change the sort inside the col itself. Very hard for me !
Here's my code :
HTML part (left col but the right one is the same)
<style>
.deplace{
cursor:move;
}
</style>
<table width="100%" border="0" cellpadding="0" cellspacing="0"><tr>
<td id="leftMenu" valign="top" style="width:180px;height:800px;border:1px solid black">
<?php
while($rowg = mysql_fetch_assoc($sqlg)){
echo '<table width="100%" cellpadding="5" cellspacing="2"
style="background-color:#CCC;border: 1px solid black;height:100px"
class="deplace" id="left_'.$rowg['id'].'" modulename="'.modif_nom($rowg['module']).'" sourceid="'.$rowg['id'].'">
echo '<tr><td" align="center" style="width:100%">'.$rowg['module'].'</td></tr>';
echo '</table>';
}
?>
</td></tr></table>
And the JS code :
<script language="javascript" type="text/javascript">
$(document).ready(function() { //
$('#leftMenu').Sortable({
//revert: true,
accept: 'deplace',
axis : 'vertically',
onchange: function(event, ui) {
serial = $.SortSerialize('leftMenu');
$.ajax ( {
url : "xhr.php?source=leftMenu",
type : "get",
data : serial.hash,
success: function(data){alert(data);}
});
}
});
$('#rightMenu').Sortable({
//revert: true,
accept: 'deplace',
axis : 'vertically',
onchange: function(event, ui) {
serial = $.SortSerialize('rightMenu');
$.ajax ( {
url : "xhr.php?source=rightMenu",
type : "get",
data : serial.hash,
success: function(data){alert(data);}
});
}
});
//only the functions to move the tables from left to right
$('#rightMenu').draggable({
revert:false,
helper:'original',
});
$('#leftMenu').droppable({
over:function(event, ui){
alert('dropped');
}
});
});
</script>
So, like that, it seems there's a conflict between the functions. If I only let the sortable functions, it's OK but I can't do anything in the receiver col and I would like to send a request to PHP to update a mysql table.
Thanks a lot for your help !
There are a few issues with your code:
Sortable is lower-case
SortSerialize does not exist, I think you mean sortable("serialize")
$('#rightMenu').draggable should be changed to $('#rightMenu').children().draggable because you want to drag the elements inside the menu
Have a look at the jQuery UI Sortable doc too.
I have a list like so:
<ol id="page_items">
<li>
<label for="page_body_1">Content Area 1</label>
<textarea name="page_body_1" class="page_content_area" rows="10"></textarea>
</li>
<li>
<label for="page_body_2">Content Area 2</label>
<textarea name="page_body_2" class="page_content_area" rows="10"></textarea>
</li>
</ol>
When the page loads, #page_items turns into a tinyMCE editor. What I want is for the element that defines whether or not the li elements are being sorted to be the <label> but no other child elements of li. So the only element that starts the sort is the label.
Here's my jQuery:
$(document).ready(function(){
$("#page_items").sortable({
activate: function(event, ui) {
var EditorID = ui.item.find('textarea').attr('id');
if ( EditorID ){
tinyMCE.execCommand("mceRemoveControl", false, EditorID);
$('#'+EditorID).hide();
}
},
stop: function(event, ui) {
var EditorID = ui.item.find('textarea').attr('id');
if ( EditorID ){
$('#'+EditorID).show();
tinyMCE.execCommand("mceAddControl", false, EditorID);
delete EditorID;
}
}
});
});
In case anyone is wondering, I'm disabling the tinyMCE because in FireFox, moving an iFrame around the DOM clears it's contents and doesn't allow focus back on it.
Is there a way to cancel the sortable if the element clicked isn't the label?
If anyone has any code clean-up suggestions they are also welcome!
Thanks.
This turned out to be a sortable option that I didn't see before (I looked... oh I looked). The handle option is what I need. This initializes a sortable with the handle option specified.
Simply...
$(document).ready(function(){
$("#page_items").sortable({
handle: 'label'
});
});