When I am dynamically removing an element that has a bootstrap tooltip and the cursor is still hover, The tooltip stay on screen even if we move the cursor.
I tried to hide the tooltips before I remove the element, but it seems that it doesn't work.
function hidelm(){
$("#nav").html("");
}
$('[data-toggle="tooltip"]').tooltip();
setTimeout(function(){hidelm();},5000);
<div id="nav">
<div data-toggle="tooltip">some content</div>
</div>
Default behaviour is on focus and hover. Disable like this:
$('[data-toggle="tooltip"]').tooltip({
trigger : 'hover'
});
In my case I want to keep default behavior. So I write a function to remove dead tooltips.
$(() => {
// Save interval id to clean it later
let interval;
// Init bs-tooltip
$("body").tooltip({
selector: '[data-toggle=tooltip]',
}).on('shown.bs.tooltip', () => {
// Remove dead tooltips
// Interval callback is set, do not need more
if (interval) {
return;
}
// Set interval callback
interval = setInterval(() => {
// Search for all tooltips
const $tooltips = $('body > .tooltip');
if ($tooltips.length === 0) {
// No tooltips, interval can be cleared
clearInterval(interval);
interval = null;
return;
}
// Loop through tooltips
$tooltips.each((i,tooltip) => {
// Do tooltip has its initiator?
if ($(`[aria-describedby="${tooltip.id}"]`).length === 0) {
// No. It is dead tooltip, remove it.
tooltip.remove();
}
});
}, 1500); // Clean tooltips every 1500ms
});
});
In your html:
<span class="icon ico-check" aria-hidden="true" data-toggle="tooltip" title="Correct"></span>
Related
In iOS safari, OverlayTrigger with trigger="focus" isn't able to dismiss when tapping outside. Here is my code:
<OverlayTrigger
trigger="focus"
placement="right"
overlay={ <Popover id="popoverID" title="Popover Title">
What a popover...
</Popover> } >
<a bsStyle="default" className="btn btn-default btn-circle" role="Button" tabIndex={18}>
<div className="btn-circle-text">?</div>
</a>
</OverlayTrigger>
I know that this is a known bug for Bootstrap cuz this doesn't even work on their own website in iOS, but does anyone know any method to go around it? It would be the best if it is something that doesn't require jQuery, but jQuery solution is welcome. Thanks.
OK, since no one else gives me a work around, I worked on this problem with my co-worker together for 3 days, and we came up with this heavy solution:
THE PROBLEM:
With trigger="focus", Bootstrap Popover/Tooltip can be dismissed when CLICKING outside the Popover/Tooltip, but not TOUCHING. Android browsers apparently changes touches to clicks automatically, so things are fine on Android. But iOS safari and browsers that is based on iOS safari (iOS chrome, iOS firefox, etc...) don't do that.
THE FIX:
We found out that in React Bootstrap, the Overlay component actually lets you customize when to show the Popover/Tooltip, so we built this component InfoOverlay based on Overlay. And to handle clicking outside the component, we need to add event listeners for both the Popover/Tooltip and window to handle both 'mousedown' and 'touchstart'. Also, this method would make the Popover have its smallest width all the time because of the padding-right of the component is initially 0px, and we make based on the width of some parent component so that it is responsive based on the parent component. And the code looks like this:
import React, { Component, PropTypes as PT } from 'react';
import {Popover, Overlay} from 'react-bootstrap';
export default class InfoOverlay extends Component {
static propTypes = {
PopoverId: PT.string,
PopoverTitle: PT.string,
PopoverContent: PT.node,
// You need to add this prop and pass it some numbers
// if you need to customize the arrowOffsetTop, it's sketchy...
arrowOffsetTop: PT.number,
// This is to be able to select the parent component
componentId: PT.string
}
constructor(props) {
super(props);
this.state = {
showPopover: false,
popoverClicked: false
};
}
componentDidMount() {
// Here are the event listeners and an algorithm
// so that clicking popover would not dismiss itself
const popover = document.getElementById('popoverTrigger');
if (popover) {
popover.addEventListener('mousedown', () => {
this.setState({
popoverClicked: true
});
});
popover.addEventListener('touchstart', () => {
this.setState({
popoverClicked: true
});
});
}
window.addEventListener('mousedown', () => {
if (!this.state.popoverClicked) {
this.setState({
showPopover: false
});
} else {
this.setState({
popoverClicked: false
});
}
});
window.addEventListener('touchstart', () => {
if (!this.state.popoverClicked) {
this.setState({
showPopover: false
});
} else {
this.setState({
popoverClicked: false
});
}
});
// this is to resize padding-right when window resizes
window.onresize = ()=>{
this.setState({});
};
}
// This function sets the style and more importantly, padding-right
getStyle() {
if (document.getElementById(this.props.componentId) && document.getElementById('popoverTrigger')) {
const offsetRight = document.getElementById(this.props.componentId).offsetWidth - document.getElementById('popoverTrigger').offsetLeft - 15;
return (
{display: 'inline-block', position: 'absolute', 'paddingRight': offsetRight + 'px'}
);
}
return (
{display: 'inline-block', position: 'absolute'}
);
}
overlayOnClick() {
this.setState({
showPopover: !(this.state.showPopover)
});
}
render() {
const customPopover = (props) => {
return (
{/* The reason why Popover is wrapped by another
invisible Popover is so that we can customize
the arrowOffsetTop, it's sketchy... */}
<div id="customPopover">
<Popover style={{'visibility': 'hidden', 'width': '100%'}}>
<Popover {...props} arrowOffsetTop={props.arrowOffsetTop + 30} id={this.props.PopoverId} title={this.props.PopoverTitle} style={{'marginLeft': '25px', 'marginTop': '-25px', 'visibility': 'visible'}}>
{this.props.PopoverContent}
</Popover>
</Popover>
</div>
);
};
return (
<div id="popoverTrigger" style={this.getStyle()}>
<a bsStyle="default" className="btn btn-default btn-circle" onClick={this.overlayOnClick.bind(this)} role="Button" tabIndex={13}>
<div id="info-button" className="btn-circle-text">?</div>
</a>
<Overlay
show={this.state.showPopover}
placement="right"
onHide={()=>{this.setState({showPopover: false});}}
container={this}>
{customPopover(this.props)}
</Overlay>
</div>
);
}
}
In the end, this is a heavy work around because it is a big amount of code for a fix, and you can probably feel your site is slowed down by a tiny bit because of the 4 event listeners. And the best solution is just tell Bootstrap to fix this problem...
here's the function:
$('.popoutlink').on('click', function() {
var box = $('#' + $(this).data('box'));
box.siblings().hide();
box.toggle("slide", { direction: "left" }, 500);
box.siblings().hide();
});
the two siblings.hide statements are because I'm in the middle of trying to figure out why I'm left with two slideouts on screen if I click on two buttons in rapid succession.
The html is:
<div class="col-md-2">
<div class="popoutlink" data-box="p1">1</div>
<div class="popoutlink" data-box="p2">2</div>
<div class="popoutlink" data-box="p3">3</div>
<div class="popoutlink" data-box="p4">4</div>
<div class="popoutlink" data-box="p5">5</div>
</div>
<div class="col-md-10 bb" style="height: 400px;">
<div class="popout" id="p1"><h1>panel 1</h1></div>
<div class="popout" id="p2">
<h1>panel 2</h1>
</div>
If I click on two buttons quickly then two windows are left on screen. I would like the siblings to hide before the selected div appears.
I have tried using promise.done():
box.siblings().hide(200).promise().done(function(){
box.toggle("slide", { direction: "left" }, 500);
});
to no effect. Adding box.toggle to hide as a callback:
box.siblings().hide(200, function(){
box.toggle("slide", { direction: "left" }, 500);
});
was very funny but not useful.
How do I get the siblings to go away reliably before I show the selected div no matter how quickly I click the buttons?
You see it here just click on the numbered boxes quickly
Thanks
If I understand your question, this should help:
https://jsfiddle.net/Twisty/3mbh5p0r/
jQuery UI
$(function() {
$('.popoutlink').on('click', function() {
var box = $('#' + $(this).data('box'));
$(".popout").hide();
//box.siblings().hide();
box.toggle("slide", {
direction: "left"
}, 500);
//box.siblings().hide();
});
});
When any of the "links" are clicked, they are all hidden and then only the one whom was clicked is toggled.
Update
A little more testing of .hide() versus .css("display", "none") revealed that changing the CSS was a faster method. This page talks about how it's immediate but I found that it wasn't as fast.
The matched elements will be hidden immediately, with no animation.
This is roughly equivalent to calling .css( "display", "none" ),
except that the value of the display property is saved in jQuery's
data cache so that display can later be restored to its initial value.
If an element has a display value of inline and is hidden then shown,
it will once again be displayed inline.
And:
Note that .hide() is fired immediately and will override the animation
queue if no duration or a duration of 0 is specified.
I did try using the callback, which made it worse. The callback should be triggered when the hide animation is complete, yet it added the element of animating the hide operation. Even when the speed was 0, it was slower.
So I advise this:
$(function() {
$('.popoutlink').on('click', function() {
$(".popout").css("display", "none");
$('#' + $(this).data('box')).show("fast");
});
});
I want to show a context menu on right click of the series plotted in High charts. I am not able to find any option in High charts to do this. Can any one suggest a way to achieve this requirement.
Well it is 2019 and there still isn't a solution for this that comes with the base HighCharts download. I have found a way to manipulate the LEFT click, in order to show a menu of sorts. Now I understand this may not be the best case scenario, but you still have full access to all of the data from the click, and will still be able to do normal drill down functionality etc. You just might have to rework it. This is a TypeScript example, but can easily be replicated to JavaScript with a few edits.
Please excuse the lack of CSS for the menu.
Your functions initialized before the chart. The variable is used to keep the menu from disappearing and is NOT mandatory here.
let callDrillDown = () => {
alert('drill1');
}
let callDrillDown2 = () => {
alert('drill2');
}
let mouseIn: boolean;
This is the bread and butter, during the click, you're pulling the <div> from the HTML and adding an onclick action to it.
plotOptions: {
column: {
events: {
click: (event: any) => {
let contextMenu = document.getElementById('contextMenu');
let contextMenuItem1 = document.getElementById('contextMenuItem1');
let contextMenuItem2 = document.getElementById('contextMenuItem2');
contextMenuItem1.onclick = callDrillDown;
contextMenuItem2.onclick = callDrillDown2;
contextMenu.onmouseenter = () => {
mouseIn = true;
};
contextMenu.onmouseleave = () => {
mouseIn = false;
setTimeout(() => {
if (!mouseIn) {
contextMenu.setAttribute('style', 'display: none');
}
}, 1000);
};
contextMenu.setAttribute('style', 'top: '
+ event.pageY + 'px; left:'
+ event.pageX + 'px;');
}
}
}
}
Inside of the body add the HTML
<div id="contextMenu" style="display: none" class="contextMenu">
<div id="contextMenuItem1">Data</div>
<div id="contextMenuItem2">Data2</div>
</div>
Here is the jsFiddle. Hope this helped.
I did the solution below. Hope it helps.
plotOptions: {
series: {
point: {
events: {
contextmenu: function (e) {
$('#constext-menu-div').css({top: e.chartY, left: e.chartX});
$('#constext-menu-div').show();
console.log(e);
},
click: function(){
$('#constext-menu-div').hide();
}
}
}
}
},
"http://jsfiddle.net/c42Ms/45/"
It is not built-in functionality, but you can use custom-events extention and then catch right click. Last step will be show/hide any div with menu.
Is it possible to check if a sortable item has moved from left to right more than x pixels?
Here is a place to play:http://jsfiddle.net/qfgd9/4/
For instance if the user moves item1 more than 200px do something
if( drag > 200 ) {
alert( "something" );
}
JQUERY:
$( "#sortable" ).sortable({
});
HTML:
<div id="sortable">
<div>item1</div>
<div>item2</div>
<div>item3</div>
</div>
<div id="check"></div>
Try this: http://jsfiddle.net/lotusgodkk/GCu2D/262/
You can get the difference in left offset from ui object by using originalPosition and position . Hence by the difference in their values you can easily find the movement.
$(function () {
$("#sortable").sortable({
sort: function (event, ui) {
var move = (ui.position.left - ui.originalPosition.left);
$('#check').text(move);
if(move>200){
alert('moved beyond 200px'); //Do something.
}
}
});
});
I am calling a function whenever someone press enter in the textarea. Now I want to disable new line or break when enter is pressed.
So new line should work when shift+enter is pressed. In that case, the function should not be called.
Here is jsfiddle demo:
http://jsfiddle.net/bxAe2/14/
try this
$("textarea").keydown(function(e){
// Enter was pressed without shift key
if (e.keyCode == 13 && !e.shiftKey)
{
// prevent default behavior
e.preventDefault();
}
});
update your fiddle to
$(".Post_Description_Text").keydown(function(e){
if (e.keyCode == 13 && !e.shiftKey)
{
// prevent default behavior
e.preventDefault();
//alert("ok");
return false;
}
});
Below code is to prevent to getting resize the "textarea", avoid scroll bar inside textarea, and also prevent to get into next line when enter key is pressed.
style.css
textarea {height:200px; width:200px;overflow:hidden;resize: none;}
index.html
<textarea></textarea>
Script.js
$("textarea").keydown(function(e){
// Enter pressed
if (e.keyCode == 13)
{
//method to prevent from default behaviour
e.preventDefault();
}
});
React: textarea w/ value and onChange event
const PreventTextAreaEnter = () => {
const [comment, setComment] = useState();
const handleTextArea = (e) => {
console.log({e}) // Destructure to get a more accurate log
// Return if user presses the enter key
if(e.nativeEvent.inputType === "insertLineBreak") return;
setComment(e.target.value);
};
return (
<>
<textarea value={comment} onChange={ (e) => { handleTextArea(e) } />
</>
)
}
$(".Post_Description_Text").keypress(function(event) {
if (event.which == 13) {
alert("Function is Called on Enter");
event.preventDefault(); //Add this line to your code
}
});
For Angular Users
While there are existing working solutions, if anyone comes across this question using Angular, you can disable new lines with the following:
Add <textarea ng-trim="false" ng-model='your.model' ...
In your controller, add:
$scope.$watch('your.model', function(newvalue, oldvalue) {
if (newvalue && newvalue.indexOf('\n') > -1) {
$scope.your.model = oldvalue;
}
});
use the input tag instead of textArea tag in your HTML