Accordion + morphtabs = odd problem

9 views
Skip to first unread message

wheatstraw

unread,
Jul 2, 2008, 4:51:44 PM7/2/08
to MooTools Users
I have a slight issue in all browsers.

I am using morphTabs inside one tab in an Accordion. When it first
loads, everything is great but when I go to the second tab and then
back to the first, all of the accordion elements are expanded.

Here is an example: http://www.wrtdesign.com/wrt-new/work.php

Thank you in advance.

johnwait

unread,
Jul 2, 2008, 6:41:46 PM7/2/08
to MooTools Users
Hi,

On preliminary inspection, this is what I found:
1) the Accordion hides all div.element upon creation (i.e. sets
{ display: none; } )
2) Morphtabs, the way it's designed (since it can support Ajax-filled
content), always re-inject HTML code with-in each <div id="..."
class="morphtabs_panel"> tags
3) So when re-inserted all div.element defaults back to normal (i.e.
with CSS property 'display' set to ''), hence the reason why all the
accordion section get "expanded" (though they are in fact not
contracted... so to speak...)

I can't get a local copy to run (for a reason the tabs content just
fly past...), but setting div.element with the default CSS property
'display' set to 'none' (either inline or within <style> tags) should
fix the issue. The only slight problem I can think of is that for
clients not supporting the accordion script/Javascript/etc. the
sections of the accordion will be hidden by default. Either this or
else hack the Morphtabs code to hide panels after injection, if panels
are configured to (like add new CSS class to panels, like
'morphtabs_defaulthide' and have MorphTabs::fill() hide content it
element has the aforementioned class)

Let me know what you do and if it works.

Jonathan R.-Brochu

johnwait

unread,
Jul 2, 2008, 7:16:35 PM7/2/08
to MooTools Users
Oops, made a little mistake...

For the hack, you would add the class to all div.element tags, *not*
div.morphtabs_panel ones.
Then, within MorphTabs::fill(), after the line

element.set('html', contents);

you would do something like:

element.getChildren('.morphtabs_defaulthide').setStyle('display',
'none');

Hope it clears things up.

Jonathan

wheatstraw

unread,
Jul 2, 2008, 7:54:29 PM7/2/08
to MooTools Users
Thank you for the response. I'm not quite sure I understand the CSS
part. If the fill is being set to none and the css is being set to
none...then nothing is showing. Sorry, I just don't quite understand.

johnwait

unread,
Jul 2, 2008, 9:53:38 PM7/2/08
to MooTools Users
[Note to self: next time use Firebug to see how things work]

OK. The hack (rev.3?) really should have been

element.getChildren('.morphtabs_defaulthide').setStyle({
height: '0px',
visibility: 'hidden',
opacity: '0'
});

to properly mimic the Accordion hiding a section.

-----
OK. I just read your last message while writing this. Here's the
explanation before I get further. As defined in HTML-4.01, an element
can have multiple classes, so if you have:

<div id="oneDiv" class="element"> [...] </div>

you can also have:

<div id="myDiv" class="element another_class"> [...] </div>

without it causing any problems. It's expected to be valid. This means
the element with id "myDiv" will receive all styles defined for the
class "element" as well as all styles defined for the class
"another_class". Now this last div (with id "myDiv") is seen as having
both the class 'element' and the class 'another_class'. And this even
if one or any of the classes don't have any styles defined (i.e. isn't
defined in CSS's <style> tags). It serves as another mean to select
elements (hence the usefulness of CSS selectors) using only the id or
just *one* single class. So if, with MooTools, you do

var elemArray1 = $$('div.element'); // an array of div elements with
class 'element'
var elemArray2 = $$('div.another_class'); // an array of div elements
with class 'another_class'

both elemArray1 and elemArray2 arrays will contain the div
"myDiv" (along with all other matching elements). It also means that

var bool1 = $('myDiv').hasClass('element'); // sets bool1 to true
var bool2 = $('myDiv').hasClass('another_class'); // sets bool2 to
true

will both return true. So you can use classes to 'flag' elements,
without causing widget/script to break by changing the one class or
id.

So the hack really involved (1) adding the class
"morphtabs_defaulthide" to all your <div class="element">, without
anything breaking, to get something like this:

<p class="toggler">City + Region</p>
<div class="element morphtabs_defaulthide">- <a href="[..]">[..]</a>
- <a href="[..]">[..]</a>
- <a href="[..]">[..]</a>
[..]
</div>
<p class="toggler">Civic</p>
<div class="element morphtabs_defaulthide">- <a href="[..]">[..]</a>
- <a href="[..]">[..]</a>
- <a href="[..]">[..]</a>
[..]
</div>

and so on; and (2) changing the fill() function within Morphtabs.js to

fill: function(element, contents) {
if(this.options.useAjax) {
this.getContent();
} else {
element.set('html', contents);
var children = element.getChildren('.morphtabs_defaulthide');
if (children) {
children.setStyles({
height: '0px',
visibility: 'hidden',
opacity: '0'
});
}
}
},

so as to support resetting your <div class="element
morphtabs_defaulthide"> (which contain the accordion sections) to a
hidden state, as set by the Accordion plugin when first run.
-----

OK. But even with the hack, it still won't work. Aactually, the hack
is useless!

Why? Because (of course! it's clear now...) Morphtabs breaks the
Accordion: upon initialization, Morphtabs removes from the DOM and
stores away content of the panels (except for the first one) and
injects/replaces it in a wrapper only when needed (i.e. when a tab is
clicked). So by the time you switch to another panel (after the first
one), elements have in fact just been created & injected and thus
don't have any event attached to handlers of the Accordion previously
created. So clicking on the togglers doesn't do anything.

Now I don't really see an easy fix to this. It wouldn't be a problem
if Morphtabs was hiding panels instead or destructing/re-injecting
them. Here are the options I see:

- Use another plugin for that tabs functionality (not ideal, I know)
- Modify heavily Morphtabs to work around it's incompatibility with
Accordion (event worse)
- Somehow re-create the accordion after each tab/panel switch (does
Morphtabs raise events?)
- Create a wrapper class around Morphtabs and overide the fill()
function to re-attach event handlers to togglers after injection.
(that would be my best bet)

But first look around to see if anybody stumbled upon the same problem
and if any fix has been found.

Oh, wait, I may have something working...

Jonathan

johnwait

unread,
Jul 2, 2008, 11:33:37 PM7/2/08
to MooTools Users
Hi again.

If still you're looking for a solution, here's one. Replace both of
your window.addEvent('domready', function() { [..] }); with the
following (I suggest copy-pasting):

var MorphTabsWithAccordion = new Class({

Extends: MorphTabs,

options: {
acc_params: {
container: null,
options: {},
togglers: null,
elements: null
}
},

initialize: function(element, options, accordion_options) {
this.parent(element, options);
$extend(this.options.acc_params, accordion_options);
(function(that){
that.accordion = new Accordion(
this.container,
this.options,
this.togglers,
this.elements
);
}.bind(this.options.acc_params))(this);
},

fill: function(element, contents) {
this.parent(element, contents);
(function(that){
that.accordion = new Accordion(
this.container,
this.options,
this.togglers,
this.elements
);
}.bind(this.options.acc_params))(this);
}
});

window.addEvent('domready', function() {
var morphTabs = new MorphTabsWithAccordion('morphTabs',{
height:'',
width:'400px',
panelStartFx: 'slide:left',
panelEndFx: 'slide:right'
},
// Accordion's arguments, as an object
{
container: $('accordion'),
togglers: 'p.toggler',
elements: 'div.element',
options: {
opacity: true,
alwaysHide: true,
show: 15,

onActive: function(toggler, element){
toggler.setStyle('margin-bottom','7px');
},

onBackground: function(toggler, element){
toggler.setStyle('margin-bottom','7px');
}
}
});
});

Basically, this is "an accordion within a Morphtabs class". It's a new
class, MorphTabsWithAccordion, that extends the original MorphTabs one
and adds code to create an accordion (1) when the object is first
initialized, and (2) re-create one every time you switch tab. It may
not be efficient to create (I should say bind) an accordion every
time, but given the way MorphTabs behave by design, it may be the only
real good solution. You gotta thank MooTools' beautiful class
inheritance here.

By the way, the original code (and thus this one as well) throws an
error on IE since it doesn't like setting negative values to the
'height' property, and this happens when MorphTabs is first
initialized (this has to do with the 'height' option you're passing to
MorphTabs/MorphTabsWithAccordion)

Hope all this will help.

Cheers.

Jonathan Richard-Brochu.

wheatstraw

unread,
Jul 3, 2008, 9:03:35 AM7/3/08
to MooTools Users
You're insane! Thank you SO much.
> ...
>
> read more »

wheatstraw

unread,
Jul 3, 2008, 9:09:56 AM7/3/08
to MooTools Users
Can I credit you (you're company) in anyway in the script?

On Jul 2, 11:33 pm, johnwait <jonathan.bro...@gmail.com> wrote:
> ...
>
> read more »

wheatstraw

unread,
Jul 3, 2008, 9:56:33 AM7/3/08
to MooTools Users
Oddly enough, it doesn't seem to work in ie7, everything stays fully
expanded and the tabs are inactive.

On Jul 2, 11:33 pm, johnwait <jonathan.bro...@gmail.com> wrote:
> ...
>
> read more »

johnwait

unread,
Jul 4, 2008, 12:12:47 AM7/4/08
to MooTools Users
Hi again,

(I hope you're still reading the thread)

The only error I get with IE7, like I mentioned in my last message, is
related to the fact that an empty string is passed as the 'height'
option when the MorphTabs object is initialized. MorphTabs doesn't
(yet) do any checks on those params, and uses it straight-away like
so:

this.panelHeight = this.options.height.toInt() -
(this.titles[0].getSize().y + 4);

which in your case gives ''.toInt(), returnin NaN (not a number).
After that, at every other places where this.option.height or
this.panelHeight is used the code fails (IE7 doesn't like setting
invalid values to style properties), just because of the empty string.
Eventually, MorphTabs should sets itself default values and only
override them if options passed are valid. If I set the height to
something, like:
[..]
height:'600px',
width:'400px',
[..]
the entire code works as expected (accordion and tabs) and without
throwing errors in IE7 (on my machine at least). Find yourself a value
and set the height to something, then it should work.

By the way, I noticed the spacing between all togglers changes when a
toggler is clicked for the first time, and I guess it's not meant to
do so. This is because in your <style> tags you set for H3.toggler a
margin-bottom of 4px, but in the event handlers (passed with the
accordion's options) it changes to 7px. Unless this is on purpose,
your should set both to the same value.

Cheers.

Jonathan Richard-Brochu
> ...
>
> read more »

wheatstraw

unread,
Jul 6, 2008, 11:10:40 AM7/6/08
to MooTools Users
Thank you again!
> > > > hidden state, as set by...
>
> read more »
Reply all
Reply to author
Forward
0 new messages