select vs checkboxes? Arg. */ function viewselector_elements() { //dprint_r("In selector elements"); $type['views_node_selector'] = array( '#input' => TRUE, '#process' => array('viewselector_process_element' => array()), '#view' => 'frontpage', '#multiple' => false, '#page' => 0, '#collapsed' => false, '#collapsible' => false, '#arguments' => array(), ); return $type; } function viewselector_process_element($element) { include_once 'viewselector.inc'; //dprint_r("Processing:"); //dprint_r($element['#value']); $element['#tree'] = true; // turn default values into the proper values if (!isset($element['#value']['selected']) || !is_array($element['#value'])) { if (is_array($element['#value'])) { foreach($element['#value'] as $key => $value) { if (is_int($key)) { $element['#value']['selected'][] = $value; } } } else { $tmp = $element['#value']; unset($element['#value']); $element['#value']['selected'] = $tmp; } } // the clone is necessary in case we're on php5 and we run on the same // view multiple times in a single form (quite possible really) $view = drupal_clone(views_get_view($element['#view'])); _viewselector_add_title_if_empty($view); if ($element['#multiple']) { $item_value = is_array($element['#value']['selected']) ? $element['#value']['selected'] : array(); } else { $item_value = $element['#value']['selected']; } // add the selection field $props = array ( // these next items are shoved into the field to pass to the themeing func 'multiple' => $element['#multiple'], 'setval' => $item_value, 'parent_name' => $element['#name'] . '[selected]', 'parent_id' => $element['#id'] . '-selected', 'super_parents' => array_merge($element['#parents'], array('selected')), ); _viewselector_add_selection_column($view, $props); // modify the view to use the exposed filters // this will happen if anyone clicks any non submitting form button if (isset($element['#value']['filters'])) { _viewselector_edit_filters($view, $element['#value']['filters']); } // get the exposed filters form before we remove them manually $filter_form = _viewselector_filters_form($view); // change the view to a table based view // remove the normal exposed filters $view->page_type = 'table'; $view->viewselector = true; $view->exposed_filter = array(); // save the view for render time -- no changes to the view after this point $element['#view'] = $view; // if someone intentionally filtered, we return to page zero, to avoid invalid values if ($element['#value']['filter_button']) { $element['#value']['pager']['pages'] = 0; } // reset the page to 0 if it is greater than the max possible pages $page_data = _viewselector_get_page_data($view, $element['#arguments']); $page_opts = array(); $max = 0; for($i = 0; $i < $page_data['pages']; ++$i) { $page_opts[$i] = t('Page') . ' ' . ($i + 1); $max = max($max, $i); } // update the page if we have a value for it if (isset($element['#value']['pager']['pages'])) { $element['#page'] = $element['#value']['pager']['pages'] > $max ? 0 : $element['#value']['pager']['pages']; } // build the view as specified in the element. just for counting $view_nodes = _viewselector_build_view_from_element($element, 'items'); // use the result of the query to build a list of possible nodes to select $options = array(); if (!empty($view_nodes['items'])) { foreach($view_nodes['items'] as $node) { $options[$node->nid] = ''; } } // find any missing nodes (ie. things that won't be in the view) // in theme_views_node_selector, we'll put them in their own table. $missing = array(); // make sure there is a selected value, or we get extra queries later if (isset($element['#value']['selected'])) { if (is_array($element['#value']['selected'])) { foreach($element['#value']['selected'] as $nid) { if (!isset($options[$nid])) { $missing[$nid] = true; } } } else if (!isset($options[$element['#value']['selected']])) { $missing[$element['#value']['selected']] = true; } } $element['#missing'] = array_keys($missing); // add the missing nodes to the options list foreach($element['#missing'] as $new_opt) { $options[$new_opt] = ''; } // a set of checkboxes or radio buttons to make sure the form // passes validation $element['selected'] = array ( '#type' => $element['#multiple'] ? 'checkboxes' : 'radios', '#options' => $options, '#required' => $element['#required'], '#title' => $element['#title'], //'#parents' => array_merge($element['#parents'], array('selected')), ); // if there are no exposed filters, dispense with the form if ($filter_form) { // the exposed filters $element['filters'] = $filter_form; $element['filters']['filter_button'] = array ( '#type' => 'button', '#value' => t('Filter results'), '#name' => $element['#name'] . '[filter_button]', ); } // form based pager // hide on views with only 1 page or no pages // also hide if paging is turned off if (count($page_opts) > 1 && $view->use_pager) { $element['pager']['pages'] = array ( '#type' => 'select', '#options' => $page_opts, '#title' => t('Select another page'), '#value' => $element['#page'], ); $element['pager']['go'] = array ( '#type' => 'button', '#value' => t('Go!'), '#name' => $element['#name'] . '[go]', ); } //dprint_r("about to return element"); //dprint_r($element['options']['#options']); return $element; } function theme_views_node_selector($element) { // dprint_r("In theme views node selector"); // dprint_r($element); $view = $element['#view']; // clone the view _prior_ to building it $missing_view = drupal_clone($view); // build the real view $built = _viewselector_build_view_from_element($element); // some other stuff in our element array $filters = $element['filters']['#children']; $pager = $element['pager']['#children']; $missing = $element['#missing']; if (!empty($missing)) { dprint_r($missing); // making the already selected table // the only filter we want is nid in missing array $missing_view->filter = array(); $missing_view->filter[] = array ( 'vid' => $missing_view->vid, 'tablename' => '', 'field' => 'node2.nid', // set to node.nid when this gets into views 'value' => $missing, 'operator' => 'OR', 'options' => '', 'position' => 0, 'id' => 'node2.nid', // set to node.nid when this gets into views ); // remove some caching of queries and other data // we do not need on the "missing" table unset($missing_view->query); unset($missing_view->countquery); unset($missing_view->num_rows); unset($missing_view->page_empty); unset($missing_view->page_header); unset($missing_view->page_footer); // make our faked view $tbl = views_build_view('embed', $missing_view); if ($tbl) { $missing_table = '

' . t('Currently Selected') . "

\n"; $missing_table .= $tbl; $missing_table .= '
'; } } // the entire bundle of output goes in one div $element['#children'] = '
'; // add the filters, if any if ($filters) { $element['#children'] .= '
' . $filters . '
'; } // add the "missing" table, if any $element['#children'] .= $missing_table; // users always seen something, regardless $element['#children'] .= '
'; if ($built) { $element['#children'] .= '

' . t('Select Content') . "

\n"; $element['#children'] .= $built; } else { $element['#children'] .= t('No content to display. You may not make any selections at this time.'); } $element['#children'] .= '
'; // finally, the pager, if there is one. if ($pager) { $element['#children'] .= '
' . $pager . '
'; } $element['#children'] .= '
'; // add the standard required textualizin' $element['#title'] .= $element['#required'] ? ' *' : ''; unset($element['#value']); // fieldsets can have values? strange.... return theme('fieldset', $element); } /*** Defining some views related stuff ***/ /** * Here we create a fake column for use in views. This fake column will hold * our select boxes/radios. */ function viewselector_views_tables() { $tables['selector'] = array ( 'name' => 'viewselector', 'provider' => 'internal', // won't show up in external list. 'fields' => array( 'select' => array( 'name' => t('Node: Select'), 'handler' => 'viewselector_handler_selector', 'sortable' => true, 'option' => '', 'notafield' => 'true', 'help' => t("This should only be used by the viewselector form widget."), ), ), ); /* the 'nid' filter should be added to the default views_node.inc table. the inner join is just to get the functionality I need w/o patching views (yet) */ $tables['node2'] = array ( 'name' => 'node', 'provider' => 'internal', // won't show up in external list. 'join' => array( 'left' => array( 'table' => 'node', 'field' => 'nid', ), 'right' => array( 'field' => 'nid', ), 'type' => 'inner', ), 'filters' => array( 'nid' => array( 'name' => t('Node: Include/Exclude Nodes in View'), 'field' => 'nid', 'operator' => 'views_handler_operator_or', 'value' => viewselector_handler_filter_nid_value_form('frontpage'), 'value-type' => 'array', 'help' => t('This filter allows you to limit your view to only apply to some specific nodes. You can limit your view to a specific list of nodes, or you can exclude specific nodes from every being returned.'), ), ), ); return $tables; } function viewselector_handler_filter_nid_value_form($view) { $form['vns'] = array ( '#type' => 'views_node_selector', '#view' => $view, '#multiple' => true, ); return $form; } /** * This function sticks the select element (checkbox or radio) into the built * view. */ function viewselector_handler_selector($fieldinfo, $fielddata, $value, $data) { // if multiple, we use check boxes, if single we use radio buttons if ($fielddata['multiple']) { //dprint_r("I should be making checkboxes"); $element = array ( '#name' => $fielddata['parent_name'] . '[' . $data->nid . ']', '#id' => $fielddata['parent_id'] . '-' . $data->nid, '#return_value' => $data->nid, '#parents' => $fielddata['super_parents'], ); // dprint_r($fielddata['setval']); if (in_array($data->nid, $fielddata['setval'] )) { $element['#value'] = true; } //dprint_r($element); return theme('checkbox', $element); } else { //dprint_r("I should be making radios"); $element = array ( '#name' => $fielddata['parent_name'], '#value' => $fielddata['setval'], '#return_value' => $data->nid, '#parents' => $fielddata['super_parents'], ); return theme('radio', $element); } } /** * Hide the above from views */ function viewselector_form_alter($form_id, &$form) { include_once 'viewselector.inc'; if ($form_id == 'views_edit_view') { // hide the selection field during view creation unset($form['field']['add']['id']['#options']['selector.select']); } } /* FOR TESTING ONLY */ /** * Implementation of hook_help() */ function viewselector_help($section) { switch ($section) { case 'admin/modules#description': return t('A testing module for a form element to select nodes based on views'); } } /** * Implementation of hook_menu(). */ function viewselector_menu($may_cache) { $items = array(); if ($may_cache) { $items[] = array('path' => 'viewselector', 'title' => t('testing view selector'), 'callback' => 'viewselector_testpage', 'access' => true); } return $items; } function viewselector_testpage() { if ($_GET['edit']['view']) { $edit = $_GET['edit']; $form['vns'] = array ( '#type' => 'views_node_selector', '#title' => 'Your test form', '#view' => $edit['view'], '#page' => $edit['page'] ? $edit['page'] - 1 : 0, '#multiple' => $edit['multiple'], '#arguments' => explode(',', $edit['args']), '#required' => $edit['required'], '#default_value' => $edit['multiple'] ? explode(',', $edit['defaults']) : $edit['defaults'], ); } else { $options = array(); $default_views = _views_get_default_views(); $res = db_query("SELECT name FROM {view_view} ORDER BY name"); while ($view = db_fetch_object($res)) { $options[$view->name] = $view->name; } if(is_array($default_views)) { foreach($default_views as $key => $view) { $options[$key] = $view->name; } } $form['view'] = array ( '#type' => 'select', '#title' => 'Pick a view to use', '#options' => $options, ); $form['page'] = array ( '#type' => 'textfield', '#title' => 'If you want to start on a given page, put the number in here' ); $form['args'] = array ( '#type' => 'textfield', '#title' => 'Args: if you need arguments, put in a comman separated list. eg. 1,34,foo' ); $form['multiple'] = array ( '#type' => 'checkbox', '#title' => 'Check this box to make it a multiple form (i.e. checkboxes instead of radios)', ); $form['defaults'] = array ( '#type' => 'textfield', '#title' => 'Put in the node id(s) of the default values. If you are using a multiple form, comma separate the list.' ); $form['required'] = array ( '#type' => 'checkbox', '#title' => 'Check this box to make it a required form element', ); $form['#method'] = 'GET'; } $form['submit'] = array ( '#type' => 'submit', '#value' => 'submit', ); return drupal_get_form('viewselector_test_form', $form); } function viewselector_test_form_submit($id, $form) { //dprint_r("In viewselector_test_form_submit"); //dprint_r($form); if (is_array($form['vns']['selected'])) { drupal_set_message("(Ignore zeros) You selected: " . implode(', ', $form['vns']['selected'])); } else { drupal_set_message("You selected: " . $form['vns']['selected']); } return 'viewselector'; } /* function viewselector_init() { dprint_r("In init function"); dprint_r("POST:"); dprint_r($_POST); dprint_r("GET:"); dprint_r($_GET); } */