Commit f2e5a0c5 authored by merlinofchaos's avatar merlinofchaos

Initial D6 work -- this includes only panels.module stuff. Right now the drag...

Initial D6 work -- this includes only panels.module stuff. Right now the drag & drop display editor works, layout, layout settings and render works. Special features such as cache and styles may or may not work.
parent 2b47b8c8
The API for expanding the panels module comes in two pieces. First there is the
layout API, which adds to the list of layouts you need. Second is the content
types API, which lets modules supply content to the panels. Natively, panels
module supports the content types of 'block', which just renders the output
of a block, 'node' which simply renders a node_view, 'custom' which allows the
user to enter custom content with filtering, and finally 'views' because I
wrote them both.
Where to put your code:
=======================
With both types, there are two ways to implement a new type. First, you can
implement the hook in your module and provide the necessary data. Or you
can create a .inc file in the right format, and drop it into the proper
directory in the panels module. Both are very similar, and only requires
a minor naming adjustment.
When using the .inc file, in place of 'hook' in the various hooks, use
panels_FILENAME.
Creating a new Layout Type:
===========================
A layout consists of 4 things:
1) A bit of HTML in a theme function. I use heredoc notation to make it
extra easy to convert these to .tpl.inc files in case they are to
be overridden in php template.
2) A bit of CSS to describe how the layout should be, well, laid out.
3) An icon that is 50x75 which gives the user a visual indication of
what the layout looks like.
4) An implementation of hook_panels_layouts() to tell panels the necessary
information.
hook_panels_layouts returns an array with the following information:
'module' => The module name providing this. This is necessary because it
uses drupal_get_path('module', $module) to get the proper
path for included CSS.
'title' => The title of the layout presented to the user. Use t().
'icon' => The filename of the icon to use when listing avialable layouts.
'theme' => The theme function that contains the HTML, without the theme_
part.
'css' => The CSS file.
'content areas' => an array in the form of 'name' => t('Title') of content
areas supported by the layout. For example, the simple
2 column layout uses array('left' => t('Left side'),
'right' => t('Right side')); -- the name is the internal
identifier. Your theme function will see it as
$content['name'] (so twocol gets $content['left'] and
$content['right']).
Creating a new Content Type:
============================
Content types require 1 hook and two callbacks. The hook defines what content
types are available, the first callback displays the content in a dashboard,
and the other callback does all of the administrative functions.
hook_panels_content_types returns an array with the following information:
'callback' => The function to display the content.
'admin' => The function to administer the content.
The callback function receives one argument: The $configuration array, as
defined by the administrative callback.
The administrative callback recieves 3 arguments:
$op -- the operation to perform. See below.
&$arg1 -- The first argument should be a reference and its meaning varies
based on the op.
$arg2 -- The second argument is optional, not a reference, and should
default to NULL.
Administrative operations:
'list': $arg1 is the configuration array.
This op is called when panels lists what content is in a content
area. It generally returns something similar to this:
return '<strong>Views</strong>: ' . $view->name . ' (' . $view->description . ')';
'add button': arguments not used here.
This op is called to display the 'add content type' button; it can also
display additional information (such as the list of blocks or the
autocomplete to select a node).
The actual button should look something like this:
$form['submit'] = array(
'#type' => 'button',
'#value' => t('Add view'),
);
And it's a good idea to do this, but it's not required:
$form['#prefix'] = '<div class="container-inline">';
$form['#suffix'] = '</div>';
'add': $arg1 == the $configuration array
This op is called to see if your add button has been clicked. It *must*
start off by checking to see if this is true:
if ($_POST['op'] != t('Add view')) {
return;
}
If it is true, it should process that information and return a $configuration
array populated from whatever other form items were presented in 'add button'
and whatever defaults make sense.
'edit': $arg1 == the $configuration array
This op is called to provide an edit form for a content type. It *must*
ensure *all* information from the conf array is available, even if it
is just hidden; panels has no way to remember this data between form
clicks, so any data not put here will be lost. No buttons need to be
added to the form.
'validate': $arg1 == $form_values, $arg2 == $form
Called to validate the 'edit' form above.
'save': $arg1 == $form_values
Called to convert a $form_values back into a $configuration array. All
of the default types just send $form_values back as $configuration,
but if you need to do some kind of transformation, this is where it
happens.
# $Id$
The most current (usually -dev) version of the Panels 2 API Documentation can be
found online at http://doxy.samboyer.org/panels2/.
Simply activate the module. The tables you need will be installed.
Then, go to administer >> panels
Select 'add'.
Choose a layout; a simple one is best if you're just exploring.
Choose a URL for your new panel page. 'panel/test' is good if you're just exploring.
Add some content to each of the areas.
Click save, then click on the URL in the list to see what your new page looks like.
# $Id$
Place the module files in the appropriate directory. If you're not sure,
try 'sites/all/modules'.
Then navigate to administer >> site building >> modules and activate
the panels module, along with any of the accompanying side modules you'd like to use.
The Panels module itself only provides an API - you MUST install these other modules
if you want to do much of anything.
# $Id$
Known Issue http://drupal.org/node/191771
'Node' panes can have two titles or have two title areas.
Cause:
Content that comes into a pane is already formatted, and this happens
in theme('node'). theme('node') assumes it will be printing a title
most of the time. However, Panels wants the titles of panes to be
consistent, so it removes the title from the node to prevent your
node.tpl.php from printing it. The result is often an empty h2 which
has odd effects.
Solution:
Add an if statement to your node.tpl.php to prevent printing that h2
if $node->title is empty.
Known Issue http://drupal.org/node/186454
Internet Explorer is really bad about making the rightmost panel
fall beneath the others.
Cause:
Internet explorer calculates margins and padding differntly from
everyone else, and this makes it entirely too easy for widths
to add up to greater than the amount of allotted space, despite
using percentage widths.
Solution:
There are two solutions to this problem:
1) In your theme, try to eliminate padding from the the <div>
that directly contains your content; you can do this by
adding an empty <div> inside it that surrounds the content
and very specifically is set to margin: 0 and padding: 0
2) if that doesn't work, override the widths of the panel-panel
divs and reduce them by 1 or 2%; usually this will give IE
enough space to quit pushing things around.
Known Issue http://drupal.org/node/154351
TinyMCE, FCKEditor and other wysiwyg editors really blow up on Panels
content editing.
Cause:
The modal dialogs that Panels uses are very particular about javascript
and these editors are too much for them. Also, these editors get
cranky about complicated forms with several text areas.
Solution:
Disable these editors on all of your panels admin pages. The important
URLs are admin/panels/* and panels/ajax/*. More details instructions
may follow if someone familiar with these systems submits a patch at
the above drupal.org URL.
Known Issue http://drupal.org/node/180650
The rounded corners style shows up as just a small graphic rather than
a full box around the panels as it shoujld.
Cause:
The rounded corners CSS relies on the ID for the panel, but the ID is
optional.
Solution:
Make sure your panel has an ID of some sort. With mini panels there is
no easy workaround as mini panels currently do not have IDs of their
own.
Known Issue http://drupal.org/node/165745
You see a message similar to this:
Table 'drupal.panels_info' doesn't exist query: SELECT * FROM panels_info
WHERE path = 'front_page_new' in...
The important piece of information is 'panels_info'.
Cause:
The Meta Tags module (also known as nodewords.module) directly reads the
the panels tables and modifies its forms to add the tags. Unfortunately
for this module, Panels has changed *greatly* in the leap from 1.0 to
2.0 and the tables aren't the same. However, the nodewords module doesn't
yet know this. Look in the nodewords issue queue for panels patches and
you should find something.
Known Issue http://drupal.org/node/153399
The drag and drop content UI doesn't seem to work at all under Safari.
Cause:
Safari 2 has some serious problems with the javascript code.
Solution:
Upgrade to Safari 3 if possible. If not, use an an alternative browser
such as Firefox or Opera.
Known Issue http://drupal.org/node/207859
When using the secure pages module, the Panels administrative UI gives
unhelpful "An error occurred" popups when trying to add or edit content.
Cause:
The secure pages module tries to move the entire administrative section
of the site to HTTPS, but Panels' AJAX calls are using a path that
secure pages doesn't know about. When trying to make non-secure ajax calls
from a secure page, the browser denies the call.
Solution:
The solution is to simply add panels/* to your Secure Pages configuration.
\ No newline at end of file
The panels module is the ideological son, successor to and almost complete
replacement for the dashboard module. This module allows you to create pages
that are divided into areas of the page. Where the dashboard module only gave
four areas--top, bottom, left and right--this one is a completely flexible
system that includes a couple of 2 column and 3 column layouts by default, but
is also highly extensible and other layouts can be plugged in with a little HTML
and CSS knowledge, with just enough PHP knowledge to be able to edit an include
file without breaking it.
Perhaps most importantly, unlike the dashboard module it requires no fiddling
with PHP code to include the things you want; the interface lets you add blocks,
nodes and custom content just by selecting and clicking.
If you want to override the CSS of a panel, the easiest way is to just copy
the CSS into your theme directory and tweak; panels will look there before
including the CSS from the module, and if it exists, will not include the
module's CSS. If you want to just change a tiny bit but keep the basic
structure, just add your changes to your style.css instead.
If you're having problems with IE and your panels falling below your sidebars,
try setting the width of the main panel area (example, .panel-2col-stacked) to
98%.
# $Id$
Welcome to Panels 2.
A little documentation should go here, but Panels 2 is a beast - you're best
off checking the online handbook on Drupal.org, or the developer/API docs,
which are available at http://doxy.samboyer.org/panels2/
TODO:
This is a brief list of the things that may still need to be done. No guarantee
of them ever getting done.
content type: phptemplate
access control to pages
access control to content types
dashboard node extension
# $Id$
PLEASE NOTE THAT THIS FILE CONTAINS VERY OUTDATED INFORMATION, KEPT ONLY FOR HISTORICAL PURPOSES.
For the current plans related to Panels2, you should consult the groups.drupal.org Panels group:
http://groups.drupal.org/panels
Here's a rough sketch of the work plan shortly prior to the 5.x-2.0-beta4 release:
5.x-beta3 ==> beta4 ==> beta5 ==> RC1 ==> RCs... ==> 5.x RELEASE!! ==> 5.x-2.1
|
6.x port ==> 6.x RCs... ==> 6.x RELEASE!! ==> 6.x-2.1
|
6.x-3.x-ALPHA ==> (FUTURE OF PANELS)
==========================================================
TODO:
X = DONE
o = TODO
- = Skipped/postponed
ajax/js
o remove panels_hidden, use only javascript
o Remove 'panels_set' and use the broken up drupal_get_form functions
rather than drupal_get_form for our multi-step stuff.
X Add permission checking to all the ajax functions
o Break up panels_ajax into separate entry areas [mostly done]
o ensure complete degradability
X Make sure the icons on the 'change layout' page are clickable
X Loading animation for panels-modal
X Make the titlebar outside of the overflow in the modal
o Change show/hide to use AJAX.
X Write my own drag & drop
modules
X panels node
X mini-panel
o panels-profile
o panels-dashboard-compat (upgrade all the old dashboard installs)
panels common
o update settings to use categories like the 'add content' popup now does.
o Clean up and better document this code
panels page
X panels page 'default' panels
X allow panel-page to use $arg/$node/$node-type/$user substitution like Views
X allow panel-page to get a context; allow modules to provide this context.
X allow panel-page to do menu item & tab like Views.
X provide 'edit' tab for panels pages
X allow setting to not display blocks
o Clone panels page
mini panels
X Allow mini panels to require an argument (and thus be just panel content)
content types
- Allow creating new custom blocks.
X Get all 'block' settings into blocks.
X Remove all calls to the 'admin' callback
X Make panels_get_content_type() like using for layout
X Translate views to new content format
X Translate node to new content format
X Translate custom to new content format
X Allow content types to be aware of panel context.
X Allow content types to include or exclude themselves based upon context.
X Figure out a way for blocks to easily have per-block icons
X sort blocks in content type list
X sort views in content type list
X add weight so custom and node will float up
X make forms fit a bit better
X Allow display to have 'arguments' that can be passed on to Views
more fluidly
X give views.inc setting to NOT use arguments.
X unify title overriding.
X node_content type
X taxonomy term types
o user types
o views context sensitive conversions
layouts
X Allow each layout to have settings
X Create a flexible layout where you can quickly create arbitrary layouts
X Fix the div div problem in all layouts
icons
X Change configure icon
X Change remove pane icon
X Find add content icon
X Create icons for content types
Flexible layout
o Allow fixed width sidebars
o Use a slider to control widths
Styles:
o Convert DND to a style
X Rounded corners style
Arguments:
X taxonomy argument
X user argument
panels API
X Provide method to directly edit/configure an individual content block if viewer has permissions
X Provide method to control pane visibility. Make sure this is controllable from the admin so that not all users can get to it.
X Change add content to be per panel
X Make Cancel actually cancel
X Wrap calls to existing callbacks
X Make a function to simply get the IDs of all content-types
X Allow panels_edit_display to restrict available content to a preprepared list
X Use cache instead of putting everything in $_SESSION
X create panels_render_display() (or panels_display_render)
X Allow API to accept context
X Allow API to accept content
X Allow API to accept arguments
General:
o CSS class/id name cleanup and unification.
o Make sure core blocks that require context are labelled as such.
Documentation
o Creating new panel modules that use the API
o Creating new content types
o Creating new layouts
o Creating new styles
o Creating new arguments
o Themeing panels
o Doing interesting things with Panels
<?php
// $Id$
/**
* @file arguments/nid.inc
*
* Plugin to provide an argument handler for a node id
*/
function panels_nid_panels_arguments() {
$args['nid'] = array(
'title' => t("Node ID"),
// keyword to use for %substitution
'keyword' => 'node',
'description' => t('Restricts the argument to a node id.'),
'context' => 'panels_nid_context',
'settings form' => 'panels_nid_settings_form',
'settings form submit' => 'panels_nid_settings_form_submit',
'displays' => 'panels_nid_displays',
'choose display' => 'panels_nid_choose_display',
);
return $args;
}
/**
* Discover if this argument gives us the node we crave.
*/
function panels_nid_context($arg = NULL, $conf = NULL, $empty = FALSE) {
// If unset it wants a generic, unfilled context.
if ($empty) {
return panels_context_create_empty('node');
}
if (!is_numeric($arg)) {
return FALSE;
}
$node = node_load($arg);
if (!$node) {
return FALSE;
}
if (array_filter($conf['types']) && empty($conf['types'][$node->type])) {
return FALSE;
}
return panels_context_create('node', $node);
}
/**
* Settings form for the argument
*/
function panels_nid_settings_form($conf) {
$options = array();
foreach (node_get_types() as $type => $info) {
$options[$type] = $info->name;
}
$form['types'] = array(
'#title' => t('Node types'),
'#type' => 'checkboxes',
'#options' => $options,
'#description' => t('You can restrict this argument to use the checked node types. Arguments from non-conforming node types will be ignored, and Panels will behave as if no argument were given. Leave all unchecked to impose no restriction.'),
'#default_value' => $conf['types'],
'#prefix' => '<div class="clear-block">',
'#suffix' => '</div>',
);
$form['own_default'] = array(
'#title' => t('Use different default display'),
'#type' => 'checkbox',
'#description' => t('If checked, when this argument is present it will use its own display rather than the default. Node types not selected in the "Own display" field will use this one.'),
'#default_value' => $conf['own_default'],
);
$form['displays'] = array(
'#title' => t('Own display'),
'#type' => 'checkboxes',
'#options' => $options,
'#default_value' => $conf['displays'],
'#description' => t('Each checked node type will get its own special display to layout its content. Only node types set above should be set here. Node types not set here will use the default display.'),
'#prefix' => '<div class="clear-block">',
'#suffix' => '</div>',
);
return $form;
}
/**
* There appears to be a bit of a bug with the way we're handling forms; it causes
* 'checkboxes' to get invalid values added to them when empty. This takes care
* of that.
*/
function panels_nid_settings_form_submit(&$values) {
$types = node_get_types();
if (!empty($values['types'])) {
foreach ($values['types'] as $type => $value) {
if (empty($types[$type])) {
unset($values['types'][$type]);
}
}
}
if (!empty($values['displays'])) {
foreach ($values['displays'] as $type => $value) {
if (empty($types[$type])) {
unset($values['displays'][$type]);
}
}
}
}
/**
* What additional displays does this argument provide?
*/
function panels_nid_displays($conf, $id) {
$displays = array();
if (!empty($conf['own_default'])) {
$displays['default'] = array(
'title' => t('Node ID @id Default', array('@id' => $id)),
'context' => 'node',
);
}
if (is_array($conf['displays'])) {
$options = array();
foreach (node_get_types() as $type => $info) {
$options[$type] = $info->name;
}
foreach (array_keys(array_filter($conf['displays'])) as $type) {
$displays[$type] = array(
'title' => t('Node ID @id @type', array('@id' => $id, '@type' => $options[$type])),
// Tell it to base the template for this display off of the default.
'default' => 'default',
'context' => 'node',
);
}
}
return $displays;
}
/**
* Based upon the settings and the context, choose which display to use.
*/
function panels_nid_choose_display($conf, $context) {
if (empty($context->data)) {
return;
}
if (!empty($conf['displays'][$context->data->type])) {
return $context->data->type;
}
// Please note that 'default' is a special display.
if (!empty($conf['own_default'])) {
return 'default';
}
// Empty return says to use the default display.
return;
}
<?php
// $Id$
/**
* @file arguments/nid.inc
*
* Plugin to provide an argument handler for a Node add form
*/
function panels_node_add_panels_arguments() {
$args['node_add'] = array(
'title' => t("Node add form"),
// keyword to use for %substitution
'keyword' => 'node_type',
'description' => t('Displays the node add form for a content type.'),
'context' => 'panels_node_add_context',
'settings form' => 'panels_node_add_settings_form',
'settings form submit' => 'panels_node_add_settings_form_submit',
'displays' => 'panels_node_add_displays',
'choose display' => 'panels_node_add_choose_display',
);
return $args;
}
/**
* Discover if this argument gives us the node we crave.
*/
function panels_node_add_context($arg = NULL, $conf = NULL, $empty = FALSE) {
// If unset it wants a generic, unfilled context.
if (!isset($arg)) {
return panels_context_create_empty('node_add_form');
}
if (array_filter($conf['types']) && empty($conf['types'][$arg])) {
return FALSE;
}
return panels_context_create('node_add_form', $arg);
}
/**
* Settings form for the argument
*/
function panels_node_add_settings_form($conf) {
$options = array();
foreach (node_get_types() as $type => $info) {
$options[$type] = $info->name;
}
$form['types'] = array(
'#title' => t('Node types'),
'#type' => 'checkboxes',
'#options' => $options,
'#description' => t('You can restrict this argument to use the checked node types. Arguments from non-conforming node types will be ignored, and Panels will behave as if no argument were given. Leave all unchecked to impose no restriction.'),
'#default_value' => $conf['types'],
'#prefix' => '<div class="clear-block">',
'#suffix' => '</div>',
);
$form['own_default'] = array(
'#title' => t('Use different default display'),
'#type' => 'checkbox',
'#description' => t('If checked, when this argument is present it will use its own display rather than the default. Node types not selected in the "Own display" field will use this one.'),
'#default_value' => $conf['own_default'],
);
$form['displays'] = array(
'#title' => t('Own display'),
'#type' => 'checkboxes',
'#options' => $options,
'#default_value' => $conf['displays'],
'#description' => t('Each checked node type will get its own special display to layout its content. Only node types set above should be set here. Node types not set here will use the default display.'),
'#prefix' => '<div class="clear-block">',
'#suffix' => '</div>',
);
return $form;
}
/**
* There appears to be a bit of a bug with the way we're handling forms; it causes
* 'checkboxes' to get invalid values added to them when empty. This takes care
* of that.
*/
function panels_node_add_settings_form_submit(&$values) {
$types = node_get_types();
if (!empty($values['types'])) {
foreach ($values['types'] as $type => $value) {
if (empty($types[$type])) {
unset($values['types'][$type]);
}
}
}
if (!empty($values['displays'])) {
foreach ($values['displays'] as $type => $value) {
if (empty($types[$type])) {
unset($values['displays'][$type]);
}
}
}
}
/**
* Based upon the settings and the context, choose which display to use.
*/
function panels_node_add_choose_display($conf, $context) {
if (empty($context->form)) {
return;
}
if (!empty($conf['displays'][$context->node_type])) {
return $context->node_type;
}
// Please note that 'default' is a special display.
if (!empty($conf['own_default'])) {
return 'default';
}
// Empty return says to use the default display.
return;
}
/**
* What additional displays does this argument provide?
*/
function panels_node_add_displays($conf, $id) {
$displays = array();
if (!empty($conf['own_default'])) {
$displays['default'] = array(
'title' => t('Node add form @id Default', array('@id' => $id)),
'context' => 'node',
);
}
if (is_array($conf['displays'])) {
$options = array();
foreach (node_get_types() as $type => $info) {
$options[$type] = $info->name;
}
foreach (array_keys(array_filter($conf['displays'])) as $type) {
if (!empty($options[$type])) {
$displays[$type] = array(
'title' => t('Node add form @id @type', array('@id' => $id, '@type' => $options[$type])),
// Tell it to base the template for this display off of the default.
'default' => 'default',
'context' => 'node',
);
}
}
}
return $displays;
}
<?php
// $Id$
/**
* @file arguments/nid.inc
*
* Plugin to provide an argument handler for a Node edit form
*/
function panels_node_edit_panels_arguments() {
$args['node_edit'] = array(
'title' => t("Node edit form"),