'; $output .= t('You may peruse a list of your current panels layouts and edit them, or click add to create a new page.'); $output .= '

'; break; case 'admin/panels/panel-page/add': $output = '

'; $output .= t('Choose a layout for your new page from the list below.'); $output .= '

'; break; } return $output; } /** * Implementation of hook_perm(). */ function panels_page_perm() { return array('create panel-pages', 'access all panel-pages'); } function panels_page_menu() { panels_page_load_include('menu'); panels_page_load_include('read'); $items = panels_page_admin_static_menu_items(); $items = panels_page_admin_dynamic_menu_items($items); return $items; } /** * Implementation of hook_menu_alter(). * * Delegates to an .inc file to reduce code load overhead. */ function panels_page_menu_alter(&$callbacks) { panels_page_load_include('menu'); return _panels_page_menu_alter($callbacks); } /*function panels_page_menu_link_alter(&$item, &$menu) { }*/ /** * Menu loader for some panels_page admin screens. Loads the panels_page * specified by the name arg, induces a 404 when a bad arg is provided. * * Use the empty string so that the behavior of callers that don't pass arg(6) * will be the same as callers who do pass arg(6), but arg(6) is empty. * * @param string $name * @param string $which * @return mixed */ function panels_page_admin_load($name, $which = '') { panels_page_load_include('write'); panels_load_include('plugins'); $panel_page = panels_page_load($name); panels_page_fetch_display($panel_page, $which); return is_object($panel_page) && !empty($panel_page->pid) ? $panel_page : FALSE; } /** * Menu loader for some panels_page admin screens. Loads the panels_page * specified by the name arg from the edit cache, or induces a 404 when a bad * arg is provided. * * Use the empty string so that the behavior of callers that don't pass arg(6) * will be identical to callers who do pass arg(6), but arg(6) is empty. * * @param string $name * @param string $which * @return mixed */ function panels_page_admin_cache_load($name, $which = '') { panels_page_load_include('write'); panels_load_include('plugins'); if (!empty($_POST)) { // FIXME With the way the menu system currently works, this is likely to be // fired AT LEAST six times per admin page request. BOLLOCKS. Time to // figure out yet another fracking caching method...maybe just right here? $panel_page = panels_cache_get('panel_object:panel_page', $name); } else { $panel_page = panels_page_load($name); panels_cache_set('panel_object:panel_page', $name, $panel_page); } panels_page_fetch_display($panel_page, $which); return is_object($panel_page) && !empty($panel_page->pid) ? $panel_page : FALSE; } /** * Determine the render-time behavior of panels_page. * * This function is basically the brains of the dynamic override system. * * @param $pid * @param $args * @return array $loader_data */ function panels_page_get_loader_data($pid, $args) { static $loader_data = array(); if (!empty($loader_data[$pid])) { return $loader_data[$pid]; } $load = &$loader_data[$pid]; panels_load_include('plugins'); panels_page_load_include('read'); $panel_page = panels_page_load($pid); // Handle static pages then duck out early. if (!($panel_page->loader_flags & PANELS_IS_DYNAMIC)) { $load['access'] = (bool) panels_page_access($panel_page); if ($load['access']) { panels_page_load_include('render'); $load['panels_page'] = panels_page_load($pid, TRUE); } return $load; } // At this point, we know we're handling a dynamic/override panels_page. // Start off by assuming that we won't fall back. $load['fallback'] = FALSE; $map = explode('/', $_GET['q']); // TODO Multiple p-pages per path will necessitate more complex logic here $wildcards = array_keys(explode('/', $panel_page->path), '%'); $map = _panels_page_rebuild_menu_map($map, $args, $wildcards); $load_objects = array(); foreach ($panel_page->arguments as $id => $argument) { $ignore = ($argument['default'] == 'ignore'); // FIXME The directness of this association is questionable $load_objects[$id] = array_shift($args); $context = !empty($load_objects[$id]) ? panels_argument_get_context($argument, $load_objects[$id]) : PANELS_ARG_IS_BAD; if (!is_a($context, 'panels_required_context') && !is_a($context, 'panels_context')) { if ($context & PANELS_ARG_USE_FALLBACK) { if ($panel_page->loader_flags & PANELS_HAS_FALLBACK_ROUTER) { $load['fallback'] = TRUE; break; } else if ($ignore) { continue; } } // TODO Are there other cases? If not, this else is an unnecessary overspecification else if ($context & PANELS_BAD_ARG && $ignore) { continue; } // Bail out and 404 if we get this far. // TODO should this 'business logic' be separated out? drupal_not_found(); } $panel_page->context[panels_argument_context_id($argument)] = $context; } // If we've determined that we're falling back, bail out. if ($load['fallback'] === TRUE) { panels_page_prepare_fallback_render($load, $map); return $load; } // We're now 100% certain we're proceeding with a panel_page render, so first // check the panels_page native access function. If that passes, then include // the render inc file and proceed inside there. $load['access'] = panels_page_access($panel_page); if (empty($load['access'])) { drupal_access_denied(); } panels_page_load_include('render'); panels_page_prepare_panels_render($load, $panel_page); return $load; } /** * Rebuild a drupal menu system-style $map using data passed in to the panels * callback handlers from the menu system. * * @param array $map * A incomplete menu map - it has only $_GET['q'] data initially - that this * callback will rebuild. * @param array $load_objects * The set of menu-loader-returned objects provided by the menu system to the * panels callback handlers. * @param array $positions * The positions within the path map (i.e., arg(0), arg(1), etc...) that the * loader objects correspond to. */ function _panels_page_rebuild_menu_map($map, $load_objects, $positions) { foreach ($positions as $key => $position) { $map[$position] = $load_objects[$key]; } return $map; } function panels_page_prepare_fallback_render(&$load, $map) { // Lifted from menu_get_item(). list($ancestors, $placeholders) = menu_get_ancestors(explode('/', $quickref->path)); if ($router_item = db_fetch_array(db_query_range('SELECT * FROM {panels_page_menu_store} WHERE path IN ('. implode (',', $placeholders) .') ORDER BY fit DESC', $ancestors, 0, 1))) { // FIXME Ideally we could skip some of this, much has already been loaded. $map = _menu_translate($router_item, $original_map); if ($router_item['access']) { $router_item['map'] = $map; $load['page arguments'] = array_merge(menu_unserialize($router_item['page_arguments'], $map), array_slice($map, $router_item['number_parts'])); } } $load['page callback'] = $router_item['page callback']; // $load['router item'] = $router_item; // $load['map'] = $map; // $load['title callback'] = '_menu_item_localize'; // $load['title arguments'] = array($router_item, $map); } /** * Check whether the current page request is allowed. * * Note that this handler is ONLY used by static panel_pages; the rest are all * handled internally by the master loader. * * @return boolean */ function panels_page_access_handler() { $args = func_get_args(); // Get the pid, which is passed in with a prepended string. $pid = substr(array_shift($args), 4); $loader_data = panels_page_get_loader_data($pid, $args); return $loader_data['access']; } /** * Execute the active page rendering callback. * * This is the master handler through which ALL (non-admin) panels_page-touched * callbacks pass. It takes the callback and arguments calculated by the main * brain, panels_page_get_loader_data(), and fires out the callback with its * arguments. * * @return mixed */ function panels_page_render_handler() { $args = func_get_args(); // Get the pid, which is passed in with a prepended string. $pid = substr(array_shift($args), 4); $loader_data = panels_page_get_loader_data($pid, $args); return call_user_func_array($loader_data['page callback'], $loader_data['page arguments']); // return node_view(node_load(1)); } function panels_page_title_handler() { $args = func_get_args(); // Get the pid, which is passed in with a prepended string. $pid = substr(array_shift($args), 4); $loader_data = panels_page_get_loader_data($pid, $args); if ($loader_data['fallback'] === TRUE) { return _menu_item_localize($loader_data['router item'], $loader_data['map']); } else { if (!$loader_data['panel page']->display->hide_title && $title = filter_xss_admin(panels_page_get_title($loader_data['panel page'], 'page', ''))) { return $title; } // TODO necessary? return ''; } } /** * Get the title for a panel page, given a context. * */ function panels_page_get_title($panel_page, $context = 'page', $default_title = NULL) { $title = _panels_page_get_title($panel_page, $context, $default_title); if (!empty($panel_page->keywords)) { $title = strtr($title, $panel_page->keywords); } return $title; } function _panels_page_get_title($panel_page, $op, $default_title) { if ($op == 'menu-parent' && $panel_page->menu_parent_title) { return $panel_page->menu_parent_title; } if (in_array($op, array('menu', 'menu-parent')) && $panel_page->menu_title) { return $panel_page->menu_title; } // Context has the highest priority if (!empty($panel_page->context)) { $title = NULL; foreach ($panel_page->context as $context) { if (empty($context->data)) { // Empty contexts can't provide titles continue; } if ($page_title = $context->get_page_title()) { $title = $page_title; } } if ($title) { return $title; } } // If no context returned a title use the display title configured in layout // settings if (!empty($panel_page->display->title)) { return $panel_page->display->title; } // Fall back on the panel default title if (!empty($panel_page->title)) { return $panel_page->title; } if (is_null($default_title)) { return t('No title'); } else { return $default_title; } } /** * Figure out if a panel is the current page; mostly useful in theming. * * This function will return NULL until panels_page_set_current() has been * properly called and loaded. */ function panels_page_get_current() { // Take advantage of our .inc organization to know if it's at all possible // that a current page has been loaded. if (function_exists('panels_page_set_current')) { $fubar = NULL; // PHP4 compatibility return panels_page_set_current($fubar); } return FALSE; } // --------------------------------------------------------------------------- // panel page administrative pages function panels_move_menu_tabs($path, $tab) { global $_menu; // Get my menu item. $my_mid = menu_get_active_item(); // Get my parent menu item. $my_parent = $_menu['items'][$my_mid]['pid']; // Check the existing children to see if there is a default local task // already. if (!isset($_menu['items'][$my_parent]['children'])) { $_menu['items'][$my_parent]['children'] = array(); } $local_tasks = FALSE; if ($my_parent != 1) { // We do not run this loop if the parent is the top level menu item // since that way lies madness. foreach ($_menu['items'][$my_parent]['children'] as $child_mid) { if ($_menu['items'][$child_mid]['type'] & MENU_IS_LOCAL_TASK) { $local_tasks = TRUE; break; } } } if (!$local_tasks) { // Move the administrative items from the admin menu to here. $admin_item = $_menu['path index'][$path]; $_menu['items'][$my_mid]['children'] = $_menu['items'][$admin_item]['children']; } else { // But if we do have tabs, just add the admin item itself to the tabs. // Get the menu item we want to move us to. $path .= $tab; $admin_item = $_menu['path index'][$path]; $_menu['items'][$my_parent]['children'][] = $admin_item; $_menu['items'][$admin_item]['title'] = t('Edit panel'); $_menu['items'][$admin_item]['weight'] += 50; $_menu['items'][$admin_item]['type'] = MENU_LOCAL_TASK; } } /** * Theme function to render our panel as a form. * * We need to do this so that the entire display is inside the form. */ function theme_panels_page_render_form($form) { $form['#children'] = panels_render_display($form['#display']); return theme('form', $form); } /** * Wrapper for panels_load_include() that specifically targets panels_page * include files. * @param string $include * The name of the panels_page include file, without the .inc extension. * TODO move me to an inc! */ function panels_page_load_include($include) { panels_load_include($include, 'panels_page/panels_page.'); } /** * Implementation of hook_panels_exportables(). */ function panels_page_panels_exportables($op = 'list', $panels = NULL, $name = 'foo') { static $all_panels = NULL; if ($op == 'list') { if (empty($all_panels)) { $all_panels = panels_page_load_all(); } foreach ($all_panels as $name => $panel) { $return[$name] = check_plain($name) . ' (' . check_plain(panels_page_get_title($panel)) . ')'; } return $return; } if ($op == 'export') { $code = "/**\n"; $code .= " * Implementation of hook_default_panel_pages()\n"; $code .= " */\n"; $code .= "function " . $name . "_default_panel_pages() {\n"; foreach ($panels as $panel => $truth) { $code .= panels_page_export($all_panels[$panel], ' '); $code .= ' $pages[\'' . check_plain($panel) . '\'] = $page;' . "\n\n\n"; } $code .= " return \$pages;\n"; $code .= "}\n"; return $code; } }