I noticed that tabs were not being rendered in the order I coded them:

$form['example1']['tab1'] = array('#type' => 'tabpage',
					    '#title' => t('My Groups'),
					    '#content' => t($mygroups_view)
					   );	

$form['example1']['tab2'] = array('#type' => 'tabpage',
					    '#title' => t('My Photos'),
					    '#content' => $mygallery_view
					   );	
														
$form['example1']['tab3'] = array('#type' => 'tabpage',
					    '#title'	=> t('My Posts'),
					    '#content'	=> t($myactivity_view)
					   );

It seems that the culprit is lines 76 and 77 in tabs.module:


// Sort the elements by weight.
uasort($element, "_element_sort");

Without commenting out the sort in the module, is there an argument I can pass though the tabs_render() function to disable the sorting?

Comments

nedjo’s picture

Try assigning explicit #weight attributes to each tab page.

ebeyrent’s picture

That did the trick - thanks!

nedjo’s picture

I'm not sure why the uasort is reordering items that don't have an explicit weight set. A problem with how I implemented it?

nedjo’s picture

Status: Active » Closed (fixed)
nedjo’s picture

Title: Disable Sorting? » Tabs sort order incorrect
Category: support » bug
Status: Closed (fixed) » Active

Reopening and marking http://drupal.org/node/172848 a duplicate.

Looking for ideas on why uasort is reordering. Here are the relevant lines in tabs.module:


  // Sort the elements by weight.
  uasort($element, "_element_sort");

And here is _element_sort() from common.inc:


/**
 * Function used by uasort in drupal_render() to sort structured arrays
 * by weight.
 */
function _element_sort($a, $b) {
  $a_weight = (is_array($a) && isset($a['#weight'])) ? $a['#weight'] : 0;
  $b_weight = (is_array($b) && isset($b['#weight'])) ? $b['#weight'] : 0;
  if ($a_weight == $b_weight) {
    return 0;
  }
  return ($a_weight < $b_weight) ? -1 : 1;
}

robloach’s picture

Removing the sort fixed the issue for me as most applications of the jsTools Tabs module don't implement #weight and use their own sorting methods. Panels Tabs, for example, just puts the items in the order in which they should be displayed.

  // Sort the elements by weight.
  //uasort($element, "_element_sort");

Could you try this in your situation? If it works for other applications, I'll make a patch for it.

jamesJonas’s picture

This code only applies to using the Tab module inside of JStools (not Panels Tab). This is how I fixed the issue:

  $form['toptabs']['secondtabs'] = array(
    '#type' => 'tabpage',
    '#title' => t('Tab Title'),
    '#content' => t('A tab description.'),
    '#weight' => '-3',
  );
  $form['toptabs']['secondtabs']['tabset1'] = array(
    '#type' => 'tabset',
  );
// Tab A
  $form['toptabs']['secondtabs']['tabset1']['tab1'] = array(
    '#type' => 'tabpage',
    '#title' => t('Second Title A'),
    '#content' => t('Second Title A Content'),
    '#weight' => '-8',
  );
// Tab B
  $form['toptabs']['secondtabs']['tabset1']['tab2'] = array(
    '#type' => 'tabpage',
    '#title' => t('Second Title B'),
    '#content' => t('Second Title B Content'),
    '#weight' => '-6',
  );

I set the weight for both the first and second set of tabs.

nedjo’s picture

I implemented support for explicit #weight because in some cases we need it. This follows what we do with other form elements. The challenge is to identify the bug in the implementation, as I noted above (#5).

reg’s picture

Commenting out uasort will break routines that rely on it. Try this:

foreach ($element AS $value)
if (array_key_exists($value, '#weight')) {
uasort($element, "_element_sort");
break;
}

This will call the sort routine only if a '#weight' tag is found in the right place. NOTE: there is a '#weight' tag at the root level of the array otherwise we could do this without a loop.

reg’s picture

Commenting out uasort will break routines that rely on it. Try this:

  foreach ($element AS $value)
		if (array_key_exists($value, '#weight')) {
			uasort($element, "_element_sort");
			break;
	  }

This will call the sort routine only if a '#weight' tag is found in the right place. NOTE: there is a '#weight' tag at the root level of the array otherwise we could do this without a loop.

reg’s picture

Found I had to add a little more checking after installing more modules. My guess is that some of them aren't quite as stringent as they should be on what they pass. In any case, here is the code updated:

  // Sort the elements by weight.
  foreach ($element AS $value)
    if (is_array($value) && array_key_exists('#weight', $value)) {
      uasort($element, "_element_sort");
      break;
    }
nedjo’s picture

Status: Active » Needs review

Thanks for the troubleshooting. I've applied an attempted fix to HEAD and the DRUPAL_5 branch, which is simply to assign the elements a default #weight value in the hook_elements() implementation. Untested. Anyone want to test and mark this issue accordingly?

robloach’s picture

Although I haven't tested it yet, Wim added the #weight to Panels Tabs here and here. It should be good now.

nedjo’s picture

Status: Needs review » Fixed

The issue was that uasort() changes the order of array elements even if there is no reason to reorder them.

I've added code to give all unweighted tabs an explicit incremental weight.

Anonymous’s picture

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.