MP3 player stops when collapsing div via jQuery

miguelkp

Member
Messages
304
Reaction score
7
Points
18
Hi.

I'm trying to embed a mp3 player into a sliding top panel (that can be opened and closed) made with jQuery. You can see here in action:

http://konsumopropio.x10hosting.com/test/
(it's in Spanish, so sorry if you feel uncomfortable surfing it)

The problem is that when you "close" the top panel, player stops. Except with IE (at least with IE8 ), where the player keep doing the job even once the top panel is collapsed.
Funny thing is: when you re-open the panel, the player remembers the position and starts playing from there.

The same happens if, for instance, I embed the player in the "Principal" ("Main" in English) section. When one changes to other section (tab) in the main horizontal nav bar, player also stops (again, except with IE).

I also tried non-flash-based players, like jPlayer (jQuery and HTML5 player) with exactly same results, so I don't think its a flash problem.
I guess it's a browser issue. Some of them (Firefox, Chrome and Opera mainly; didn't try Safari yet) stops "rendering" non-visible html portions (display:none;?) for performance optimization or something. Maybe the layout engines those browsers use (WebKit for Chrome, Gecko for Firefox, Presto for Opera) are the responsibles? I don't know.

Anyway, do you think there is any workaround for this behaviour? Any way to force that particular browsers rendering that particular portion of code?





BTW, if you detect any rendering error, I would appreciate if you tell me the error and your browser so I can fix it :)
 
Last edited:

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
Please create a minimal test case (including a link to a live page with non-minimized scripts) to work with. It's likely due to the display property of the hidden element, as you suppose, but it's much harder to confirm and fix the more extraneous code there is to wade through.

If it is the display that causes the flash player to stop running, there are other ways of hiding elements without disabling display: setting a dimensions to 0, or moving the element above or to the left of the page, for example.
 
Last edited:

miguelkp

Member
Messages
304
Reaction score
7
Points
18
The panel uses 'slideUp' effect, from jQuery library. I tried to trace code inside jquery-1.7.1.js file but can't see how it really works. I'm not good at all with JS yet, to be honest.
However, in slide.css I can see that #panel, the panel div ID, has 'display:none;' style, so I'm pretty sure that you're right and both the slideUp and slideDown jQuery effects work changing display CSS property at some point of slide animation.
But I don't know how to change from 'display' to an 'opacity' or 'height' approach. I guess we will try that SSCCEE.
Although, to tell you the truth, I've never done this before. Any SSCCE I mean. Hope this is enough for you to help me (and sorry in advance if it isn't; don't hesitate to tell me if you need more information).

Main links:
Link to downloadable SSCCE code: http://www.fileden.com/files/2012/3/23/3282040/ssccee_kpweb.rar
Live page with (if I understood it well) non-minimized scripts: http://konsumopropio.x10hosting.com/sscce

Extra links:
Here the slide.css file, where the panel style resides: http://konsumopropio.x10hosting.com/sscce/css/slide.css
Here the jQuery library: http://konsumopropio.x10hosting.com/sscce/js/jquery-1.7.1.js
And my own JS functions file http://konsumopropio.x10hosting.com/sscce/js/jquery.funtions.js (now I see that I mispelled 'functions' and put 'funtions' in file name, without 'c'. Maybe I'll change it in final version. It wouldn't prevent it from working, however. Just a typo in filename)


BTW, thanks for your reply.
 
Last edited:

leafypiggy

Manager of Pens and Office Supplies
Staff member
Messages
3,819
Reaction score
163
Points
63
http://api.jquery.com/slideUp/

The .slideUp() method in the jQuery library does the animation, and then sets the display property to "none."

Look at using an alternative/writing your own animation for it. Pretty simple to do a

Code:
elem.animate({
top: "-=50"
},1000);
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
That certainly makes it easier to step through, and makes it more obvious where the toggling code is hooked into the page. Note you can use an interactive debugger, such as Firebug (Chrome an Safari have one built in), to step through the code.

jQuery ultimately uses hide to, well, hide an element, which sets the display to "none". It isn't designed to change how hiding is implemented, so coming up with a solution may be difficult. Off the top of my head:

  • Patch jQuery.fn.hide and jQuery.fn.show to change how the panel is hidden. Save the previous values in local variables so the new functions can call them for any elements you want to hide the old way. You'll have to take into account that toggle checks whether an element is hidden by seeing whether it matches the ":hidden" element; hiding the element by setting the width & height to 0 should work, but may need additional tweaking. This technique is a minor example of Aspect Oriented Programming. It would look something like:
    Code:
    (function() {
        var keepDisplay = {'panel':true};
            _fn_hide = jQuery.fn._hide,
            _fn_show = jQuery.fn._show;
    
        jQuery.fn._hide = function () {
            var args = [].slice.apply(arguments);
            $(this).each(function () {
                if (this.id in keepDisplay) {
                   this.style.height = this.style.width = 0;
                   this.style.position='absolute';
                } else {
                   _fn_hide.apply($(this),args);
                }
            });
        };
        
        jQuery.fn._show = function () {
            var args = [].slice.apply(arguments);
            $(this).each(function () {
                if (this.id in keepDisplay) {
                   this.style.height = this.style.width = '';
                    this.style.position='';
                } else {
                    _fn_show.apply($(this),args);
                }
            });
        };
    })();
  • The toggle method takes an optional callback. Instead of patching hide and show, you could pass a function to toggle that hides the panel as above and re-sets the panel's display to "block".
  • Besides the toggle animation method, there's a toggle event method, which is invoked when you pass multiple functions to toggle instead of a number and a function. With this, you'd have to write the toggle functions yourself to show the "Abbrir" and "Cerrar" panel buttons, and to move the panel up and down with (e.g.) animate.
  • Since you already have separate buttons to open and close the panel, forgo toggle and set a separate "click" handler for each button. This option is otherwise quite similar to the preceding. This is probably the simplest and most robust option.
    Code:
    $(function() {
        /* Get the height to offset the panel when hiding */
        var height = $('#panel').height();
        /* Hide the top part of the panel by moving it off the top of the screen.
         * The top panel is already relatively positioned.
         */
        $('#toppanel').css({top: -height});
        $('#panel').css({display: 'block'});
    
        $("#toggle>a.open").click(function (evt) {
            $("#toppanel").animate({top:0}, function() {
                $("#toggle>a.open").hide();
                $("#toggle>a.close").show();
            });
        });
    
        $("#toggle>a.close").click(function(evt) {
            $("#toppanel").animate({top: -height}, function() {
                $("#toggle>a.open").show();
                $("#toggle>a.close").hide();
            }); 
        });
    });

There are other options as well, along with variations on the above, but that should be enough to get you started.
 
Last edited:

miguelkp

Member
Messages
304
Reaction score
7
Points
18
Solved!

Misson, your last approach works like a charm. Furthermore, a piece of plug&play code, perfect for a Javascript total inept like me hahaha :tongue:
I would give you reputation again but the forum doesn't let me give you reputation so soon.
Working in Firefox, Chrome and Opera. I think it won't be necessary to try in Safari.


And also, thanks for your help, leafypiggy. I also tried your way before, but I couldn't make it work as intended (surely due to my lack of Javascript skills plus my frustration: I've been working on this error for 4 days or so). I attempted to make a new animation outside the jQuery file, since I don't what to change it (I'll call the jquery.js from googleapis). Everything I was trying ended in epic fails XD.
So as you can imagine, I eventually preferred this other way. As I said, thanks anyway for the time you spent reading the problem and replying.
 
Last edited:

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
As per the sig, code is not intended as a drop-in solution; study it to understand what it does. With its self-invoked anonymous function and use of the "around" advice pattern (replacing a function with one that wraps it), the first code sample has more to teach about JS. The last mostly demonstrates how to make use of some jQuery methods, plus a little about CSS (use of relative positioning and the "top" property; see also the CSS 2.1 spec on relative positioning).
 

miguelkp

Member
Messages
304
Reaction score
7
Points
18
Ok, althought this was solved, I wanted to go a bit futher and kept searching more info.
Finally I found this piece of code in jQuery UI documentation (Tabs section) that also may be also useful to people that reaches this thread looking for a solution of that 'browsers-don't-render-hidden-elements' issue.

Why does...
...my slider, Google Map, sIFR etc. not work when placed in a hidden (inactive) tab?

Any component that requires some dimensional computation for its initialization won't work in a hidden tab, because the tab panel itself is hidden via display: none so that any elements inside won't report their actual width and height (0 in most browsers).

There's an easy workaround. Use the off-left technique for hiding inactive tab panels. E.g. in your style sheet replace the rule for the class selector ".ui-tabs .ui-tabs-hide" with

Code:
.ui-tabs .ui-tabs-hide {
    position: absolute;
    left: -10000px;
}
 
Last edited:
Top