view,
*
* 'order' => array(
* 'fields' => array(
* 0 => array(
* 'field_name' => field_name,
* 'field_alias' => field_alias,
* 'handler' => handler,
* ),
* ..
* ),
* 'visible' => True/False,
* ),
*
* 'hierarchy' => array(
* 'field' => array(
* 'field_name' => field_name,
* 'field_alias' => field_alias,
* 'handler' => handler,
* ),
* 'visible' => TRUE/FALSE,
* ),
*
* 'types' = array(
* node_type1 => "root"/"leaf",
* node_type2 => "root"/"leaf",
* ..
* ),
*
* 'expand_links' = array(
* 'show' => TRUE/FALSE,
* 'default_collapsed' => TRUE/FALSE,
* ),
*
* 'view_window_extensions' = array(
* 'extension_top' => 3,
* 'extension_bottom' => 3,
* ),
*
* 'nodes' => array(
* nid1 => array(
* 'order' => array(
* 0 => value,
* 1 => value,
* ..
* ),
* 'parent' => value,
* ),
* ..
* ),
* );
*/
function _draggableviews_info($view, $info = NULL) {
$options = $view->style_plugin->options;
$fields = $view->field;
$results = $view->result;
// if there is already an info array just rebuild the nodes array and skip this section
if (!isset($info)) {
$info = array();
// extract draggableviews settings.
if (isset($options['tabledrag_order'])) {
foreach ($options['tabledrag_order'] as $field) {
if ($handler = _draggableviews_init_handler($field, $view)) {
$info['order']['fields'][] = array(
'handler' => $handler,
'field_name' => $field['field'],
'field_alias' => $fields[$field['field']]->field_alias,
);
}
else {
drupal_set_message(t('Draggableviews: Handler ') . $field['handler'] . t(' could not be found.'), 'error');
$info['order'] = array();
return $info;
}
}
$info['order']['visible'] = strcmp($options['tabledrag_order_visible']['visible'], 'visible') == 0 ? TRUE : FALSE;
if (count($info['order']['fields']) >= 2 && $options['tabledrag_hierarchy']['field'] != 'none') {
if ($handler = _draggableviews_init_handler($options['tabledrag_hierarchy'], $view)) {
$info['hierarchy'] = array(
'field' => array(
'handler' => $handler,
'field_name' => $options['tabledrag_hierarchy']['field'],
'field_alias' => $fields[$options['tabledrag_hierarchy']['field']]->field_alias,
),
'visible' => strcmp($options['tabledrag_hierarchy_visible']['visible'], 'visible') == 0 ? TRUE : FALSE,
);
if (isset($options['tabledrag_types'])) {
foreach ($options['tabledrag_types'] as $type) {
$info['types'][$type['node_type']] = $type['type'];
}
}
$info['expand_links'] = array(
'show' => strcmp($options['tabledrag_expand']['expand_links'], 'expand_links') == 0 ? TRUE : FALSE,
'default_collapsed' => strcmp($options['tabledrag_expand']['collapsed'], 'collapsed') == 0 ? TRUE : FALSE,
);
}
else {
drupal_set_message(t('Draggableviews: Handler ') . $field['handler'] . t(' could not be found.'), 'error');
}
}
$info['view_window_extensions'] = $options['draggableviews_extensions'];
if (!isset($info['view_window_extensions']['extension_top'])) $info['view_window_extensions']['extension_top'] = 3;
if (!isset($info['view_window_extensions']['extension_bottom'])) $info['view_window_extensions']['extension_bottom'] = 3;
}
}
// Hold a reference of the view object itself.
$info['view'] = &$view;
// Get all nodes and their properties.
$info['nodes'] = array();
if (isset($info['order'])) {
// loop through all resulting nodes
foreach ($results as $row) {
foreach ($info['order']['fields'] as $field) {
if (is_numeric($row->{$field['field_alias']})) {
$info['nodes'][$row->nid]['order'][] = (int)($row->{$field['field_alias']});
}
else {
// Default position of new nodes.
$info['nodes'][$row->nid]['order'][] = variable_get('draggableviews_default_on_top', 1) == 1 ? -1 : 99999;
}
}
if (isset($info['hierarchy'])) {
$info['nodes'][$row->nid]['parent'] = (int)($row->{$info['hierarchy']['field']['field_alias']});
}
}
}
return $info;
}
/*
* Quick Check Structure
*
* I used the word "Quick" because only visible nodes and only the very top hierarchy level will be checked. If the
* return is TRUE we can be sure that the structure will be displayed correctly. But errors that don't affect the
* current output can not be detected. Enhanced checks will be done when we have to rebuild a broken structure.
*
* We check for the following:
* - Wrong order values: The order values must constantly increase by 1, independent of the hierarchy level.
* - Parent mismatch: The parent_nid must equal with the nid we memorized before we entered the current hierarchy level.
*
* @param $inputs
* The structured info array. Look at _draggableviews_info(..) to learn more.
*
* return
* TRUE if structure is valid
*/
function _draggableviews_quick_check_structure($info) {
// Calculate views page offset.
$pager = $info['view']->pager;
$offset = $pager['items_per_page'] * $pager['current_page'] + $pager['offset'];
// Call function in checking mode (renumber = FALSE). The order value must begin with $offset.
return _draggableviews_ascending_numbers($info, $offset, FALSE);
}
/**
* Build hierarchy
*
* Although there shouldn't be any structure based errors after submit
* broken parents can be detected and repaired. All other structure based errors
* can not be detected. If there are any they will be detected by _draggableviews_quick_check_structure(..)
* and finally repaired by _draggableviews_analyze_structure(..).
*
* @param $info
* The structured information array
*/
function _draggableviews_build_hierarchy(&$info) {
$nodes = &$info['nodes'];
$input = &$info['input'];
foreach ($nodes as $nid => $prop) {
// get depth
if (($depth = _draggableviews_get_hierarchy_depth($nid, $input, $info)) === FALSE) {
// Error! The hierarchy structure is broken and could
// look like the following: (we're currently processing X)
// A
// --X
// --D
//
// The next steps:
// 1) bring it down to the root level
// 2) Set order fields to the minimum
$input[$nid]['parent'] = 0;
// We gracefully sidestep the order-loop
$depth = -1;
}
// Let's take a look at the following expample, to understand
// what is beeing done.
//
// A
// --B
// --C
// --X
// --D
// E
// Imagine we're currently processing X:
//
// We know that X is in depth=3, so we save the received
// weight value in the 3rd order field of node X.
//
// The 2nd order field must inherit the received weight of
// node C (the next parent). And the 1st order field must
// inherit the received weight of node A (the parent of C).
//
// When we finally order the view by weight1, weight2, weight3 then
// weight1 and weight2 from node X will always equal with
// those from node A and B, and weight3 defines the order of the 3rd level.
$temp_nid = $nid;
for ($i = $depth; $i >= 0; $i--) {
// we're operating top-down, so we determine the parents nid by the way
$nodes[$nid]['order'][$i] = $input[$temp_nid]['order'][0];
if (isset($info['hierarchy']) && $i > 0) {
if (!($temp_nid = $input[$temp_nid]['parent'])) {
// this line should never be reached assumed the depth
// was calculated correctly.
drupal_set_message(t('Undefined State called in draggableviews_build_hierarchy(..)'), 'error');
break;
}
}
}
if (isset($info['hierarchy'])) {
// Simply set the parent value
$nodes[$nid]['parent'] = $input[$nid]['parent'];
}
// Now set all unused weights to a minimum value. Otherwise
// it could happen that a child appears above its parent.
// The ? can be anything, unfortunately also > 5
//
// --A (3,5)
// B (3,?)
//
// To guaranteer that the ? is always the lowest, we choose
// the minimum.
$depth = ($depth == -1) ? 0 : $depth;
for ($i = $depth + 1; $i < count($info['order']['fields']); $i++) {
$nodes[$nid]['order'][$i] = $info['order']['fields'][$i]['handler']->get_minimum_value();
$nodes[$nid]['depth'] = $depth;
}
}
// Last but not least sort nodes and assign ascending numbers. This is necessary since this module supports paging.
_draggableviews_sort_nodes($nodes);
// calculate views page offset
$pager = $info['view']->pager;
$offset = $pager['items_per_page'] * $pager['current_page'] + $pager['offset'];
_draggableviews_ascending_numbers($info, $offset, TRUE);
}
/**
* Rebuild hierarchy
*
* This function is called when the structure is broken.
*
* @param $info
* The structured information array. Look at _draggableviews_info(..) to learn more.
*/
function _draggableviews_rebuild_hierarchy(&$info) {
// We backup the page settings and restore them after completing all operations.
$backup_pager = $info['view']->pager;
if ($backup_pager['items_per_page'] > 0) {
// We have to make sure that there's no hidden node with an order value that refers to the current page.
// If the items to display per page are limitated we load the entire view.
//@todo: We reduce the fields to a minimum because of performance issues.
_draggableviews_reload_info($info, 0, 0, 0);
}
// Calculate depth values.
// Nodes with broken parents will be brought down to the root level.
// These depth values will be used for both theming and repairing broken structures.
_draggableviews_calculate_depths($info);
// Detect and repair ordering errors.
// The nodes order values have to equal with the parents order values.
_draggableviews_check_order($info);
// The last issue we have to deal with is the order itself. Probably there
// are more many with the same order value what could lead to display errors.
// We just sort the nodes by their current order values and subsequent we assign ascending numbers.
_draggableviews_sort_nodes($info['nodes']);
_draggableviews_ascending_numbers($info, 0, TRUE);
// Save hierarchy.
_draggableviews_save_hierarchy($info);
// The structure should be valid now.
// Nonetheless let's make a final check for debugging reasons.
if (!_draggableviews_quick_check_structure($info)) {
drupal_set_message("Draggableviews: Rebuilding structure didn't work. The structure is broken.", "error");
}
// Re-execute view with original page settings.
_draggableviews_reload_info($info, $backup_pager['items_per_page'], $backup_pager['current_page'], $backup_pager['offset']);
}
/**
* (CHECK/WRITE) Ascending Numbers.
*
* This function is used for both renumbering and checking.
* Order values have to start with $offset.
*
* @param $info
* The structured info array. Look at _draggableviews_info(..) to learn more.
* @param $offset
* Where we start to count.
* @param $renumber
* Renumber or check.
*
* @return
* TRUE if no errors found.
*/
function _draggableviews_ascending_numbers(&$info, $offset = 0, $renumber = FALSE) {
// We need to hold
// 1) the last nid,
// 2) the last order value of each hierarchy level,
// 3) the parent's nid of each hierarchy level,
// 3a) the current depth (hierarchy level),
$last_nid = -1;
$last_order = array($offset);
$last_parent_nid = array(0);
$depth = 0;
foreach ($info['nodes'] as $nid => $values) {
$parent_nid = isset($info['hierarchy']) ? $values['parent'] : 0;
// Let's take a look at the following expample, to understand what is beeing done.
// The order value of the parent's level always equals with the parent's value.
//
// A (0 - -) First node of level0.
// --B (0 1 -) First node of level1. But we continue counting.
// --C (0 1 2) First node of level2. But we still continue counting.
// X (3 - -) Now we leave 2 levels (level2->level0). We still have to continue counting.
//
// Imagine we are currently processing X. We are leaving 2 levels and we need to determine the
// last order value that was used. First we check how many levels are beeing left:
$leave_hierarchy_levels = 0;
for ($i = 0; $i < $depth; $i++) {
if ($parent_nid == $last_parent_nid[$i]) {
// Found the level we go to. Calculate the number of levels that are beeing left.
$leave_hierarchy_levels = $depth - $i;
break;
}
}
if ($leave_hierarchy_levels > 0) {
// We leave some hierarchy levels. We simply inherit the order value of the level we come from.
$depth -= $leave_hierarchy_levels;
$last_order[$depth] = $last_order[$depth + $leave_hierarchy_levels];
// Remove obsoleted values from stack.
for ($i = 0; $i < $leave_hierarchy_levels; $i++) {
array_pop($last_parent_nid);
array_pop($last_order);
}
}
else if ($parent_nid == $last_nid) {
// We are entering a new level. This is the first child of the last node.
array_push($last_parent_nid, $last_nid);
array_push($last_order, $last_order[$depth]);
// Hold the previous order value of the last level.
$last_order[$depth]--;
$depth++;
}
else if ($parent_nid != $last_parent_nid[$depth]) {
// This node is neither a member of any previous hierarchy level
// nor a child of the last node (opening a new level)
// nor a member of the current hierarchy level
// There's something wrong!
if ($renumber) {
drupal_set_message("Something wrong in _draggableviews_ascending_numbers (". ($renumber ? 'WRITE' : 'CHECK') .").", "error");
}
return FALSE;
}
// This function is used for both renumbering and checking the hierarchy. Decide what we have to do:
if ($renumber) {
// Assign all order values.
for ($i = 0; $i <= $depth; $i++) {
$info['nodes'][$nid]['order'][$i] = $last_order[$i];
}
// Set all unused fields to the minimum value.
for ($i = $depth + 1; $i < count($info['order']['fields']); $i++) {
$info['nodes'][$nid]['order'][$i] = $info['order']['fields'][$i]['handler']->get_minimum_value();
}
}
else {
// Check structure.
$order = $values['order'][$depth];
if ($order != $last_order[$depth]) {
// This would cause troubles with paging.
// We better initiate a rebuild!
return FALSE;
}
}
$last_nid = $nid;
$last_order[$depth]++;
}
return TRUE;
}
/**
* Extend View Window
*
* In order to make it possible to drag from one page to another we have to extend the visible window of each page.
* We also have to make sure that parent nodes appear with all their children (..and child nodes with their parent).
*
* @param $info
* The structured info array. Look at _draggableviews_info(..) to learn more.
* @param $offset_top
* @param $offset_bottom
*
* @return
* An array containing the new, calculated range.
*/
function _draggableviews_extend_view_window(&$info, $extension_top = NULL, $extension_bottom = NULL) {
// Check page settings.
if ($info['pager']['items_per_page'] <= 0) {
// Nothin to do. Just return the actual range.
return array(
'first_index' => 0,
'last_index' => count($info['view']->result) - 1,
);
}
$items_per_page = $info['view']->pager['items_per_page'];
$current_page = $info['view']->pager['current_page'];
$offset = $info['view']->pager['offset'];
$first_index = $items_per_page * $current_page;
$last_index = $items_per_page * ($current_page + 1) - 1;
// Check permissions.
if (!user_access('Allow Reordering')) {
// Don't extend view window. Just return the actual range.
return array(
'first_index' => $first_index,
'last_index' => $last_index,
);
}
// Checks are done. Now extend the view window.
// First of all we need to load the entire view without paging options and reload the info array.
_draggableviews_reload_info($info, 0, 0, $offset);
$nodes = $info['nodes'];
// If the new index is out of range we'll use the last existing index. Calculate this index:
$total_index = count($nodes) - 1;
if (!isset($extension_top) && !isset($extension_bottom)) {
$extension_top = $info['view_window_extensions']['extension_top'];
$extension_bottom = $info['view_window_extensions']['extension_bottom'];
}
// Extend on top:
$first_index -= $extension_top;
if ($first_index < 0) {
// Be careful: $first_index < 0. So this is a subtraction!
$extension_top += $first_index;
if ($extension_top < 0) $extension_top = 0;
$first_index = 0;
}
// Extend on bottom:
$last_index += $extension_bottom;
if ($last_index > $total_index) {
$extension_bottom = $extension_bottom - ($last_index - $total_index);
if ($extension_bottom < 0) $extension_bottom = 0;
$last_index = $total_index;
}
if (isset($info['hierarchy'])) {
// There are possibly some child nodes that would be cut of their parents. To avoid this we localize
// the next parents (if needed) and use their index for the range. To analyze the nodes array we slice out
// all nodes before (the B's) and all nodes after (the a's) the current page (the -'s):
//
// B B B B B B B B B - - - - - - - - A A A A A A A A A A.
//
// Slice out all nodes before (currently not shown):
$nodes_before = array_slice($nodes, 0, $first_index, TRUE);
// Slice out all nodes after (currently not shown):
$nodes_after = array_slice($nodes, $last_index + 1, NULL, TRUE);
// Slice out all nodes that are currently shown:
$nodes_current = array_slice($nodes, $first_index, $last_index - $first_index + 1, TRUE);
$add_to_extension_top = 0;
$add_to_extension_bottom = 0;
$first_node = current($nodes_current);
if ($first_node['parent'] > 0) {
// The first node of the current page is a child node. Look for the next parent
// that is on the root level. We can't use foreach() because we iterate the wrong way.
$temp_node = end($nodes_before);
while ($temp_node !== FALSE) {
$add_to_extension_top++;
if ($temp_node['parent'] == 0) break;
$temp_node = prev($nodes_before);
}
}
// Check for possible children of the last node.
foreach ($nodes_after AS $temp_node) {
if ($temp_node['parent'] == 0) break;
$add_to_extension_bottom++;
}
// Update range.
$first_index -= $add_to_extension_top;
$last_index += $add_to_extension_bottom;
}
// Finally we re-execute the view an reload the info array. We need to add 1 to the number of items
// to show (e.g. show from index 5 to index 5: show 5-5+1=1 item).
_draggableviews_reload_info($info, $last_index - $first_index + 1, 0, $offset + $first_index);
// Mark extended nodes as "extension".
$nodes = &$info['nodes'];
for ($i = 0; $i < $extension_top + $add_to_extension_top; $i++) {
$nid = key($nodes);
$nodes[$nid]['extension'] = TRUE;
next($nodes);
}
end($nodes);
for ($i = 0; $i < $extension_bottom + $add_to_extension_bottom; $i++) {
$nid = key($nodes);
$nodes[$nid]['extension'] = TRUE;
prev($nodes);
}
return array(
'first_index' => $first_index,
'last_index' => $last_index,
);
}
/**
* Click Sort
*
* The nodes are already in the right order.
* Simply assign ascending values.
* Re-execute view and refresh info array.
*
* @param $info
* The structured info array. Look at _draggableviews_info(..) to learn more.
*/
function _draggableviews_click_sort(&$info) {
// Check permissions.
if (!user_access('Allow Reordering')) {
drupal_set_message(t('You are not allowed to reorder nodes.'), 'error');
return;
}
// If the items to display per page are limited we load the entire view.
$pager = $info['view']->pager;
if ($pager['items_per_page'] > 0) {
_draggableviews_reload_info($info, 0, 0, 0);
}
// First bring all child nodes down to the root level. We can't keep the hierarchy information
// because the nodes have been mixed up thoroughly.
if (isset($info['hierarchy'])) {
foreach ($info['nodes'] AS $nid => $values) {
$info['nodes'][$nid]['parent'] = 0;
$info['nodes'][$nid]['depth'] = 0;
}
}
// Assign ascending numbers
_draggableviews_ascending_numbers($info, 0, TRUE);
_draggableviews_save_hierarchy($info);
// Re-execute view with original page settings.
_draggableviews_reload_info($info, $pager['items_per_page'], $pager['current_page'], $pager['offset']);
}
/**
* Save Hierarchy
*
* @param $info
* The structured information array. Look at _draggableviews_info(..) to learn more.
*/
function _draggableviews_save_hierarchy($info) {
// Loop through all nodes.
foreach ($info['nodes'] as $nid => $prop) {
if (isset($info['hierarchy'])) {
$value = $prop['parent'];
$handler = $info['hierarchy']['field']['handler'];
$handler->save($nid, $value);
}
for ($i = 0; $i < count($info['order']['fields']); $i++) {
// Loop through all order fields.
$value = $prop['order'][$i];
$handler = $info['order']['fields'][$i]['handler'];
$handler->save($nid, $value);
}
}
}
/**
* Calculate Depths
*
* Nodes with broken parents will be brought down to the root level.
*
* @param $info
* The structured information array. Look at _draggableviews_info(..) to learn more.
*
* @return
* TRUE if no errors occured.
*/
function _draggableviews_calculate_depths(&$info) {
$error = FALSE;
// Loop through all rows the view returned.
foreach ($info['nodes'] as $nid => $prop) {
// Determine hierarchy depth of current row.
$info['nodes'][$nid]['depth'] = _draggableviews_get_hierarchy_depth($nid, $info['nodes'], $info);
if ($info['nodes'][$nid]['depth'] === FALSE) {
$error = TRUE;
$info['nodes'][$nid]['parent'] = 0;
$info['nodes'][$nid]['depth'] = 0;
}
}
return !$error;
}
/**
* Get Hierarchy Depth
*
* This function detects broken parents.
* Cycles are detected (if a child is the parent of its parent).
*
* @param $nid
* The nid of the node which should be processed.
* @param $nodes
* The nodes array. This can be both a nodes array or an input array.
* They share the same hierarchy properties.
* @param $info
* The structured info array. Look at _draggableviews_info(..) to learn more.
*
* @return
* The hierarchy depth if no occured, else FALSE.
*/
function _draggableviews_get_hierarchy_depth($nid, $nodes, $info) {
if (!isset($info['hierarchy'])) return 0;
$depth = 0;
$error = FALSE;
$temp_nid = $nid;
$used_nids = array($temp_nid);
while (!($error = !isset($nodes[$temp_nid])) && ($temp_nid = $nodes[$temp_nid]['parent']) > 0) {
// In order to detect cycles we use an array,
// where all used nids are saved in. If a node id
// occurs twice -> return FALSE.
$cycle_found = array_search($temp_nid, $used_nids);
// The isset(..) is necessary because in PHP-Versions <= 4.2.0 array_search() returns NULL
// instead of FALSE if $temp_nid was not found.
if (isset($cycle_found) && $cycle_found !== FALSE) {
drupal_set_message(t("Draggableviews: A cycle was found."));
return FALSE;
}
$used_nids[] = $temp_nid;
$depth++;
}
if ($error) {
// If loop breaked caused by an error.
return FALSE;
}
return $depth;
}
/**
* Detect and Repair Order Values
*
* The nodes order value has to equal with the parents order value.
*
* @param $info
* The structured information array. Look at _draggableviews_info(..) to learn more.
*
* @return
* TRUE if no error occured.
*/
function _draggableviews_check_order(&$info) {
$error = FALSE;
foreach ($info['nodes'] as $nid => $prop) {
if (_draggableviews_check_node_order($nid, $info) == FALSE) {
$error = TRUE;
}
}
return $error;
}
/**
* Check Node Order Value
*
* We rely on the correctness of depth values and parent values.
* The order values of each level have to equal with the values of the parent nodes.
*
* @param $nid
* The node id to check.
* @param $info
* The structured information array. Look at _draggableviews_info(..) to learn more.
*
* @return
* TRUE if no errors were found.
*/
function _draggableviews_check_node_order($nid, &$info) {
$error = FALSE;
$nodes = &$info['nodes'];
$temp_nid = $nodes[$nid]['parent'];
for ($i = $nodes[$nid]['depth'] - 1; $i >= 0; $i--) {
// We're operating top-down, so we determine the parents nid by the way.
if ($nodes[$nid]['order'][$i] != $nodes[$temp_nid]['order'][$i]) {
$nodes[$nid]['order'][$i] = $nodes[$temp_nid]['order'][$i];
$error = TRUE;
}
$temp_nid = $nodes[$temp_nid]['parent'];
}
return !$error;
}
/**
* Reload Info Array
*
* @param $info
* The structured info array. Look at _draggableviews_info(..) to learn more.
* @param $items_per_page
* @param $current_page
*/
function _draggableviews_reload_info(&$info, $items_per_page = NULL, $current_page = NULL, $offset = NULL) {
// Re-execute the view because order values may have changed.
_draggableviews_re_execute_view($info['view'], $items_per_page, $current_page, $offset);
// Reload nodes of the info array.
$info = _draggableviews_info($info['view'], $info);
}
/**
* Re-execute View
*
* @param $view
* The view object.
* @param $items_per_page
* @param $current_page
* @param $offset
*/
function _draggableviews_re_execute_view(&$view, $items_per_page = NULL, $current_page = NULL, $offset = NULL) {
if (isset($items_per_page)) $view->set_items_per_page($items_per_page);
if (isset($current_page)) {
$view->pager['current_page'] = $current_page;
// Views pager use global variables where all already known information is dumped in.
// We need to change the global variable $pager_page_array in order to set the page to 0 because
// this variable would force the current page to another value. (see views/includes/view.inc:#717, function execute())
global $pager_page_array;
$pager_page_array[$view->pager['element']] = $current_page;
}
if (isset($offset)) $view->set_offset($offset);
$view->executed = FALSE;
$view->execute();
}
/**
* Get Handler Instance
*
* @param $field
* The field options specified in the style plugin.
* @param $view
* The view object.
*
* @return
* A handler instance.
*/
function _draggableviews_init_handler($field, &$view) {
if (isset($field['handler'])) {
$handler_info = draggableviews_discover_handlers($field['handler']);
$file = $handler_info['path'] .'/'. $handler_info['file'];
if ($handler_info['path'] && $handler_info['file'] && file_exists($file)) {
require_once($file);
$handler = new $handler_info['handler'];
$handler->init($field['field'], $view);
return $handler;
}
else {
return FALSE;
}
}
else {
return FALSE;
}
}
/**
* Sort Nodes
*
* @param $nodes
* The nodes array to sort.
*/
function _draggableviews_sort_nodes(&$nodes) {
uasort($nodes, '_draggableviews_compare_nodes');
}
/**
* Compare Nodes (used by uasort)
*
*
* @param $node1
* @param $node2
*
* @return
* < or > or ==
*/
function _draggableviews_compare_nodes($node1, $node2) {
// The first difference will be significant. If they equal in each level we
// "survive" the loop and end up with return 0.
for ($i = 0; $i < count($node1['order']); $i++) {
// First compare the order values..
if ($node1['order'][$i] < $node2['order'][$i]) return -1;
if ($node1['order'][$i] > $node2['order'][$i]) return 1;
}
return 0;
}