I'm using MooTools and I've got the following code that I can't seem to get to execute. I'm expecting it to increase the width of the #bar element to 50px, then alert() with a "hi!", and then continue increasing the width of #bar to 200px. For whatever reason, it stops after "hi!" and won't continue to execute. What's up?
var myFx = new Fx.Tween($('bar'), {
duration: '500ms',
transition: 'sine:out',
link: 'chain'
});
myFx.start('width', '50').chain(
function() { alert('hi!'); },
function() { myFx.start('width', '200'); }
);
Fiddle
that's because your 2nd function does not call a method of the myFx class - which means, it won't advance the chain.
chain is a mixin into the Fx class. if you do an animation, it will auto try to callChain. since you do nothing of the sort, add this underneath the alert:
this.callChain();
this will work fine. perhaps the docs need changing as it's not obvious right now. http://jsfiddle.net/dimitar/nUWsU/8/
Related
I'm using Google Maps API and I have some troubles about InfoWindow.
Here is a summary :
I'm loading the InfoWindow's content when user clicks on a marker
The content is a partial view, loaded thanks to an Ajax call
In the .done callback, I call an asynchronous method which will insert data into the InfoWindow content. I need to do this because I want the InfoWindow main content to be displayed immediately, whereas this "bonus" information could be displayed after some tenths of seconds.
This perfectly works ; but I have a white strip on the right of my InfoWindow I can't remove (see the picture below)
However, the content I load is included in a <div> with a fixed width :
<div id="div-main-infoWindow">
<!-- All my content -->
</div>
And in my CSS, I wrote :
#div-main-infoWindow {
width:342px !important;
}
The loading of the InfoWindow, with more details, looks like this :
$.ajax({
url : "/my-url",
async : false,
contentType : "application/json; charset=utf-8",
dataType : "json",
type : "POST",
data : JSON.stringify(myModel)
}).done(function(response) {
MarkerContent = response.Content; //The HTML content to display
MyAsyncMethod().then(function(response) {
//do some formatting with response
return result; //result is just a small HTML string
}).done(function(result1, result2) {
//do some formatting with result1 and result2
$("#myNode").html(/*formatted result*/);
})
//info is a global variable defined as new google.maps.InfoWindow()
info.setOptions({
content: MarkerContent,
maxWidth: 342 //To be sure
});
info.open(map, marker);
});
});
The content is perfectly OK, the problem is all about this white strip.
Looking at my browser console (I reproduced it in ALL browsers), I can see this :
As you can see there, my <div> containing all my data loaded from my ajax call is OK with the good size (green rectangle, corresponding to the greyed zone in the screenshot), BUT the above divs (from Google API itself, into the red rectangles) have a bigger size, from which the problem is.
The only way I found is running this jQuery script modifying the InfoWindow internal structure :
$(".gm-style-iw").next().remove();
$(".gm-style-iw").prev().children().last().width(342);
$(".gm-style-iw").prev().children(":nth-child(2)").width(342);
$(".gm-style-iw").width(342);
$(".gm-style-iw").children().first().css("overflow", "hidden");
$(".gm-style-iw").children().first().children().first().css("overflow", "hidden");
$(".gm-style-iw").parent().width(342);
Note : gm-style-iw is the class name given by Google of the div containing all the content of the InfoWindow, the one hovered on the above screenshot. I also add this rule in my CSS :
.gm-style-iw {
width: 342px !important; //also tried with 100% !important, not better
}
It works in the console, however, it has no effect when written in the code itself, in the .done callback, or in the domready Google Maps' event...
However, in this late case, if I encapsulate the above jQuery script in a setTimeout(), it works !! I commented the asynchronous method, so it's not this one which is guilty, but it seems domready is executed whereas 100% of the InfoWindow is not still displayed - which is contrary to the doc.
I also tried to move my info.setOptions outside the .done callback and put it at after it, no effect.
So, how can I display a "normal" InfoWindow without this white strip on the right ?
I don't want to implement InfoBubble or other custom InfoWindow library. It's a personal project and I want to understand why and where the problem is. And of course, find a solution.
Thank you for your help !
It's a little bit more complex than you think.
Just some things:
did you notice that there is a close-button? Even when you remove the button the space will be there, because the API calculates the size of the other nodes based on this space
the tip must be in the center
there are additional containers for rounded borders and shadows
the size of the infoWindow will be calculated so that it fits into the viewport
the content must be scrollable when needed
the position of the infowindow must be set(therefore it's required to calculate the exact height of the infowindow)
Basically: all these things require to calculate exact sizes and positions, most of the nodes in the infowindow are absolute positioned, it's rather a technique like it will be used in DTP than you would use it in a HTML-document.
Additionally: the InfoWindows will be modified very often to fix bugs, a solution which works today may be broken tomorrow.
However, an approach which currently works for me:
set the maxWidth of the infowindow to the desired width - 51 (would be 291 in this case)
It's not possible to apply !important-rules via $.css , so it must be done via a stylesheet directly. To be able to access all the elements set a new class for the root-node of the infowindow(note that there may be infoWindows which you can't control, e.g. for POI's):
google.maps.event.addListener(infowindow,'domready',function(){
$('#div-main-infoWindow')//the root of the content
.closest('.gm-style-iw')
.parent().addClass('custom-iw');
});
the CSS:
.custom-iw .gm-style-iw {
top:15px !important;
left:0 !important;
border-radius:2px;
}
.custom-iw>div:first-child>div:nth-child(2) {
display:none;
}
/** the shadow **/
.custom-iw>div:first-child>div:last-child {
left:0 !important;
top:0px;
box-shadow: rgba(0, 0, 0, 0.6) 0px 1px 6px;
z-index:-1 !important;
}
.custom-iw .gm-style-iw,
.custom-iw .gm-style-iw>div,
.custom-iw .gm-style-iw>div>div {
width:100% !important;
max-width:100% !important;
}
/** set here the width **/
.custom-iw,
.custom-iw>div:first-child>div:last-child {
width:342px !important;
}
/** set here the desired background-color **/
#div-main-infoWindow,
.custom-iw>div:first-child>div:nth-child(n-1)>div>div,
.custom-iw>div>div:last-child,
.custom-iw .gm-style-iw,
.custom-iw .gm-style-iw>div,
.custom-iw .gm-style-iw>div>div {
background-color:orange !important;
}
/** close-button(note that there may be a scrollbar) **/
.custom-iw>div:last-child {
top:1px !important;
right:0 !important;
}
/** padding of the content **/
#div-main-infoWindow {
padding:6px;
}
Demo(as I said, may be broken tomorrow): http://jsfiddle.net/doktormolle/k57qojq7/
Bit late to the party here, but after searching for ages to achieve the same thing as the OP a thought occurred to me. The width seemed to be getting set by the parent element of .gm-style-iw so I just set the parent elements width to auto using jQuery and hey presto! So here is my code in the hope it may help someone in the future.
JS
$('.gm-style-iw').parent().css('width', 'auto');
CSS
.gm-style-iw {
width: auto !important;
top: 0 !important;
left: 0 !important;
}
I use this jQuery code to set the mouse pointer to its busy state (hourglass) during an Ajax call...
$('body').css('cursor', 'wait');
and this corresponding code to set it back to normal...
$('body').css('cursor', 'auto');
This works fine... on some browsers.
On Firefox and IE, as soon as I execute the command, the mouse cursor changes. This is the behavior I want.
On Chrome and Safari, the mouse cursor does not visibly change from "busy" to "auto" until the user moves the pointer.
What is the best way to get the reluctant browsers to switch the mouse pointer?
It is a bug in both browsers at the moment. More details at both links (in comments as well):
http://code.google.com/p/chromium/issues/detail?id=26723
and
http://code.google.com/p/chromium/issues/detail?id=20717
I would rather do it more elegantly like so:
$(function(){
$("html").bind("ajaxStart", function(){
$(this).addClass('busy');
}).bind("ajaxStop", function(){
$(this).removeClass('busy');
});
});
CSS:
html.busy, html.busy * {
cursor: wait !important;
}
Source: http://postpostmodern.com/instructional/global-ajax-cursor-change/
I believe this issue (including the mousedown problem) is now fixed in Chrome 50.
But only if you are not using the developer tools!!
Close the tools and the cursor should immediately respond better.
I got inspired from Korayem solution.
Javascript:
jQuery.ajaxSetup({
beforeSend: function() {
$('body').addClass('busy');
},
complete: function() {
$('body').removeClass('busy');
}
});
CSS:
.busy * {
cursor: wait !important;
}
Tested on Chrome, Firefox and IE 10. Cursor changes without moving the mouse. "!important" is needed for IE10.
Edit: You still have to move cursor on IE 10 after the AJAX request is complete (so the normal cursor appear). Wait cursor appears without moving the mouse..
Working solution on CodeSandbox
Some of the other solutions do not work in all circumstances. We can achieve the desired result with two css rules:
body.busy, .busy * {
cursor: wait !important;
}
.not-busy {
cursor: auto;
}
The former indicates that we are busy and applies to all elements on the page, attempting to override other cursor styles. The latter applies only to the page body and is used simply to force a UI update; we want this rule to be as non-specific as possible and it doesn't need to apply to other page elements.
We can then trigger and end the busy state as follows:
function onBusyStart() {
document.body.classList.add('busy');
document.body.classList.remove('not-busy');
}
function onBusyEnd() {
document.body.classList.remove('busy');
document.body.classList.add('not-busy');
}
In summary, although we have to change the cursor style to update the cursor, directly modifying document.body.style.cursor or similar does not have the intended effect, on some engines such as Webkit, until the cursor is moved. Using classes to affect the change is more robust. However, in order to reliably force the UI to update (again, on some engines), we have to add another class. It seems removing classes is treated differently from adding them.
First of all, you should be aware that if you have a cursor assigned to any tag within your body, $('body').css('cursor', 'wait'); will not change the cursor of that tag (like me, I use cursor: pointer; on all my anchor tag). You might want to look at my solution to this particular problem first : cursor wait for ajax call
For the problem that the cursor is only updated once the user move the mouse on webkit browsers, as other people said, there is no real solution.
That being said, there is still a workaround if you add a css spinner to the current cursor dynamically. This is not a perfect solution because you don't know for sure the size of the cursor and if the spinner will be correctly positioned.
CSS spinner following the cursor: DEMO
$.fn.extend(
{
reset_on : function(event_name, callback)
{ return this.off(event_name).on(event_name, callback); }
});
var g_loader = $('.loader');
function add_cursor_progress(evt)
{
function refresh_pos(e_)
{
g_loader.css({
display : "inline",
left : e_.pageX + 8,
top : e_.pageY - 8
});
}
refresh_pos(evt);
var id = ".addcursorprog"; // to avoid duplicate events
$('html').reset_on('mousemove' + id, refresh_pos);
$(window).
reset_on('mouseenter' + id, function(){ g_loader.css('display', 'inline'); }).
reset_on('mouseleave' + id, function(){ g_loader.css('display', 'none'); });
}
function remove_cursor_progress(evt)
{
var id = ".addcursorprog";
g_loader.css('display', 'none');
$('html').off('mousemove' + id);
$(window).off('mouseenter' + id).off('mouseleave' + id);
}
$('.action').click(add_cursor_progress);
$('.stop').click(remove_cursor_progress);
You will need to check if it is a touch device as well var isTouchDevice = typeof window.ontouchstart !== 'undefined';
In conclusion, you better try to add in your page a static spinner or something else that shows the loading process instead of trying to do it with the cursor.
Korayem's solution works for me in 100% cases in modern Chrome, Safari, in 95% cases in Firefox, but does not work in Opera and IE.
I improved it a bit:
$('html').bind('ajaxStart', function() {
$(this).removeClass('notbusy').addClass('busy');
}).bind('ajaxStop', function() {
$(this).removeClass('busy').addClass('notbusy');
});
CSS:
html.busy, html.busy * {
cursor: wait !important;
}
html.notbusy, html.notbusy * {
cursor: default !important;
}
Now it works in 100% cases in Chrome, Safari, Firefox and Opera.
I do not know what to do with IE :(
I don't think you'll be able to do it.
However, try changing the scroll position; it might help.
HERE is my solution:
function yourFunc(){
$('body').removeClass('wait'); // this is my wait class on body you can $('body').css('cursor','auto');
$('body').blur();
$('body').focus(function(e){
$('body')
.mouseXPos(e.pageX + 1)
.mouseYPos(e.pageX - 1);
});
}
As of jquery 1.9 you should ajaxStart and ajaxStop to document. They work fine for me in firefox. Have not tested in other browsers.
In CSS:
html.busy *
{
cursor: wait !important;
}
In javaScript:
// Makes the mousecursor show busy during ajax
//
$( document )
.ajaxStart( function startBusy() { $( 'html' ).addClass ( 'busy' ) } )
.ajaxStop ( function stopBusy () { $( 'html' ).removeClass( 'busy' ) } )
Try using the correct css value for the cursor property:
$('body').css('cursor','wait');
http://www.w3schools.com/CSS/pr_class_cursor.asp
I haven't tried this, but what about if you create a transparent div that is absolutely positioned and fills the viewport just before changing the CSS. Then, when the css is changed on the body, remove the div. This might trigger a mouseover event on the body, which might cause the cursor to update to the latest CSS value.
Again, I haven't tested this, but it's worth a shot.
Hey Guys, I have a nitty gritty solution which works on all browsers. Assumption is protoype library is used. Someone can write this as plain Javascript too. The solution is to have a div on top of all just after you reset the cursor and shake it a little bit to cause the cursor to move. This is published in my blog http://arunmobc.blogspot.com/2011/02/cursor-not-changing-issue.html.
$('*').css('cursor','wait'); will work everywhere on the page including links
hi sorry completely new to mootools used to jquery, have a container (saved to variable itemContent) which reveals,
after this a function galleryScroll is call which scrolls the element to the container saved to var itemScroll,
want to make sure itemContent is revealed before scroll function is called whats the best way to do this?
thanks
itemContent.reveal({
'height' : '100%',
duration: 1600,
}).addClass('open-content');
// should this fire this in a callback function so it fires once the container is revealed
galleryScroll.toElement(itemScroll);
Fx.Reveal extends Fx and as such, inherits all of it's events.
try via the element setter:
itemCount.set('reveal', {
onComplete: function(){
galleryScroll.toElement(this.element);
}
}.reveal({... });
you can also get the reveal instance:
var fxReveal = itemCount.get('reveal');
this will return the instance and you can set whatever you like to it like usual.
You can enable chaining with the link option.
itemContent.reveal({
'height': '100%',
duration: 1600,
link: 'chain'
}).addClass('open-content');
This example will hide, reveal and then alert. Please note that I need to get the reveal instance as the standard Element in mootools does not implement the Chain class.
document.id('first').set('reveal', {
duration: 'long',
transition: 'bounce:out',
link: 'chain'
}).dissolve().reveal().get('reveal').chain(function(){alert('message');});
To see it in action: http://jsfiddle.net/LKSN8/1/
I made this fiddle
http://jsfiddle.net/nAb6N/10/
As you can see I have 2 animators , a element and body class,
I am adding class to body after the first click on a element but once I click on body is not closing it. If I define animators as
var animators = $$('#opendiv,body');
it works ok except that I do not want the div to open on body click. I need it to close on body click.
Any help is appreciated.
Thank you!
Right. Seems as if you really require an outerClick pattern to close. Here's the one that is most notably used within mootools devs, allowing you to create a custom event, based on click:
Element.Events.outerClick = {
base : 'click',
condition : function(event){
event.stopPropagation();
return false;
},
onAdd : function(fn){
this.getDocument().addEvent('click', fn);
},
onRemove : function(fn){
this.getDocument().removeEvent('click', fn);
}
};
The way it works is: it is based on a normal click. upon adding, it adds the callback as a click event on the document. when a click happens within the element itself,it stops bubbling via event.stopPropagation();, else, it will bubble and the callback will run.
here's how it ties together after the above:
http://jsfiddle.net/dimitar/nAb6N/13/
(function() {
var opener = $('opendiv');
var boxtoopen = $('box');
boxtoopen.set('morph', {
duration: 700,
transition: 'bounce:out'
});
boxtoopen.addEvent('outerClick', function(event) {
boxtoopen.morph(".openOff");
opener.removeClass("hide");
});
opener.addEvent('click', function(e) {
e.stop();
boxtoopen.morph(".openOn");
this.addClass("hide");
});
})();
I have also 'outsourced' the morph properties to the CSS as it makes more sense, semantically.
P.S. note that you need mootools 1.4.3 or 1.4.5, but not 1.4.4 as there's a morph bug to do with units in that release. the jsfiddle above uses 1.4.6 (mootools edge).
Okay, so I have a site running Joomla and it is using the mootools 1.11 framework. I've fudged together a working version of this using examples from the mootools 1.2 framework but cannot get the two to co-exist even with the compatibility layer, without breaking other modules in the Joomla site.
Question
I have a couple of divs with a class of ".box_panel" and I have it so that they on mouseover they go from 50% opacity and back to 100% opacity on mouseleave. The problem I'm having is what is the code to set them to 50% onload?
In mootools 1.2 I used:
<body onload="$$('div.box_panel').fade(0.5);">
The code I'm using for the mouseover/mouseleave effects is:
window.addEvent('domready',function() {
//first, apply a class to each of your menu element
//$$('.links') puts every element wearing the .links class into an array
//$$('.links').each is to browse the array an apply a function to... each of them
$$('.box_panel').each(function(el, i) {
//there comes exactly your former fx statement except for
var ExampleFx = new Fx.Style(el, 'opacity', { //the fact i apply the effect on el
wait: false, //and wait: false which make the effect not waiting (very useful on the mouseout or mouseleave function...
opacity: 0.5,
duration: 500,
transition: Fx.Transitions.Quart.easeInOut
});
//and there i apply (always on el) the effect on mouseenter (similar in this case but often better than mouseover)
//and mouseleave (same for mouseenter but concerning mouesout)
el.addEvent('mouseleave', function() { ExampleFx.start(1, 0.5); });
el.addEvent('mouseenter', function() { ExampleFx.start(0.5, 1); });
});
});
Can you not just add ExampleFx.start(1, 0.5); before the last brackets (after the $$('.box_panel')... statement)?
Simple:
$$('.box_panel').effect('opacity', 0.5);
// run this right after your window.addEvent('domready', function() {
Edit: I were a bit wrong here. Mladen Mihajlovic answered completly correct. Also, here are some links for you:
MooTools 1.11 Documentation
MooTools 1.11 Demos