? forms.patch ? includes/form.inc Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.476 diff -u -r1.476 common.inc --- includes/common.inc 31 Aug 2005 18:37:30 -0000 1.476 +++ includes/common.inc 1 Sep 2005 22:27:10 -0000 @@ -1915,6 +1915,7 @@ require_once './includes/file.inc'; require_once './includes/unicode.inc'; require_once './includes/image.inc'; + require_once './includes/form.inc'; // Set the Drupal custom error handler. set_error_handler('error_handler'); // Emit the correct charset HTTP header. Index: includes/unicode.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/unicode.inc,v retrieving revision 1.4 diff -u -r1.4 unicode.inc --- includes/unicode.inc 25 Aug 2005 21:14:16 -0000 1.4 +++ includes/unicode.inc 1 Sep 2005 22:27:18 -0000 @@ -81,7 +81,8 @@ $options = array(UNICODE_SINGLEBYTE => t('Standard PHP: operations on Unicode strings are emulated on a best-effort basis. Install the PHP mbstring extension for improved Unicode support.', array('%url' => 'http://www.php.net/manual/nl/ref.mbstring.php')), UNICODE_MULTIBYTE => t('Multi-byte: operations on Unicode strings are supported through the PHP mbstring extension.', array('%url' => 'http://www.php.net/manual/nl/ref.mbstring.php')), UNICODE_ERROR => t('Invalid: the current configuration is incompatible with Drupal.')); - return form_item(t('String handling method'), $options[$status]); + $form['settings'] = array(type => 'item', title =>t('String handling method'), value => $options[$status]); + return $form; } /** @@ -449,3 +450,4 @@ } } + Index: misc/drupal.css =================================================================== RCS file: /cvs/drupal/drupal/misc/drupal.css,v retrieving revision 1.116 diff -u -r1.116 drupal.css --- misc/drupal.css 31 Aug 2005 21:17:26 -0000 1.116 +++ misc/drupal.css 1 Sep 2005 22:27:27 -0000 @@ -626,3 +626,8 @@ background-image: url('menu-collapsed.png'); } +/* +** Temporary CSS for porting of drupal forms. +*/ +form { border: 3px solid red; } +form.form-api { border : 0px; } Index: modules/block.module =================================================================== RCS file: /cvs/drupal/drupal/modules/block.module,v retrieving revision 1.178 diff -u -r1.178 block.module --- modules/block.module 25 Aug 2005 21:14:16 -0000 1.178 +++ modules/block.module 1 Sep 2005 22:27:44 -0000 @@ -54,15 +54,18 @@ $items = array(); if ($may_cache) { - $items[] = array('path' => 'admin/block', 'title' => t('blocks'), + $items[] = array('path' => 'admin/display/regions', 'title' => t('regions'), 'access' => user_access('administer blocks'), - 'callback' => 'block_admin'); - $items[] = array('path' => 'admin/block/list', 'title' => t('list'), + 'callback' => 'block_admin', + 'type' => MENU_LOCAL_TASK); + $items[] = array('path' => 'admin/display/regions/list', 'title' => t('list'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10); - $items[] = array('path' => 'admin/block/configure', 'title' => t('configure block'), + + $items[] = array('path' => 'admin/display/regions/configure', 'title' => t('configure block'), 'access' => user_access('administer blocks'), 'callback' => 'block_admin_configure', 'type' => MENU_CALLBACK); + $items[] = array('path' => 'admin/block/delete', 'title' => t('delete block'), 'access' => user_access('administer blocks'), 'callback' => 'block_box_delete', Index: modules/blog.module =================================================================== RCS file: /cvs/drupal/drupal/modules/blog.module,v retrieving revision 1.225 diff -u -r1.225 blog.module --- modules/blog.module 29 Aug 2005 19:58:49 -0000 1.225 +++ modules/blog.module 1 Sep 2005 22:27:57 -0000 @@ -204,16 +204,17 @@ // Note: $item->description has been validated on aggregation. $node->body = ''. check_plain($item->title) .' - '. $item->description .' ['. check_plain($item->ftitle) ."]\n"; } + } if (function_exists('taxonomy_node_form')) { - $output .= implode('', taxonomy_node_form('blog', $node)); + $form['taxonomy'] = taxonomy_node_form('blog', $node); } - $output .= form_textarea(t('Body'), 'body', $node->body, 60, 20, '', NULL, TRUE); - $output .= filter_form('format', $node->format); + $form['body'] = array(type => 'textarea', title => t('Body'), default_value => $node->body, required => TRUE, weight => 1); + $form = array_merge($form, filter_form($node->format)); - return $output; + return $form; } /** Index: modules/blogapi.module =================================================================== RCS file: /cvs/drupal/drupal/modules/blogapi.module,v retrieving revision 1.55 diff -u -r1.55 blogapi.module --- modules/blogapi.module 30 Aug 2005 15:22:29 -0000 1.55 +++ modules/blogapi.module 1 Sep 2005 22:28:10 -0000 @@ -218,10 +218,10 @@ return blogapi_error(t('You do not have permission to create the type of post you wanted to create.')); } - node_save(&$node); + node_save($node); if ($node->nid) { watchdog('content', t('%type: added %title using blog API.', array('%type' => ''. t($node->type) .'', '%title' => theme('placeholder', $node->title))), WATCHDOG_NOTICE, l(t('view'), "node/$node->nid")); - return $nid; + return $node->nid; } return blogapi_error(t('Error storing post.')); @@ -276,7 +276,7 @@ foreach ($terms as $term) { $node->taxonomy[] = $term->tid; } - node_save(&$node); + node_save($node); if ($node->nid) { watchdog('content', t('%type: updated %title using blog API.', array('%type' => ''. t($node->type) .'', '%title' => theme('placeholder', $node->title))), WATCHDOG_NOTICE, l(t('view'), "node/$node->nid")); return true; Index: modules/book.module =================================================================== RCS file: /cvs/drupal/drupal/modules/book.module,v retrieving revision 1.314 diff -u -r1.314 book.module --- modules/book.module 30 Aug 2005 15:22:29 -0000 1.314 +++ modules/book.module 1 Sep 2005 22:28:33 -0000 @@ -231,27 +231,38 @@ * Implementation of hook_form(). */ function book_form(&$node) { - $output = form_select(t('Parent'), 'parent', ($node->parent ? $node->parent : arg(4)), book_toc($node->nid), t('The parent that this page belongs in. Note that pages whose parent is <top-level> are regarded as independent, top-level books.')); + $form['parent'] = array( + type => 'select', title => t('Parent'), default_value => ($node->parent ? $node->parent : arg(4)), options => book_toc($node->nid), + description => t('The parent that this page belongs in. Note that pages whose parent is <top-level> are regarded as independent, top-level books.') + ); if (function_exists('taxonomy_node_form')) { - $output .= implode('', taxonomy_node_form('book', $node)); + $form['taxonomy'] = taxonomy_node_form('blog', $node); } - $output .= form_textarea(t('Body'), 'body', $node->body, 60, 20, '', NULL, TRUE); - $output .= filter_form('format', $node->format); - - $output .= form_textarea(t('Log message'), 'log', $node->log, 60, 5, t('An explanation of the additions or updates being made to help other authors understand your motivations.')); + $form['body'] = array( + type => 'textarea', title => t('Body'), default_value => $node->body, required => TRUE + ); + $form = array_merge($form, filter_form($node->format)); + + $form['log'] = array( + type => 'textarea', title => t('Log message'), default_value => $node->log, required => TRUE, rows => 5, + description => t('An explanation of the additions or updates being made to help other authors understand your motivations.') + ); if (user_access('administer nodes')) { - $output .= form_weight(t('Weight'), 'weight', $node->weight, 15, t('Pages at a given level are ordered first by weight and then by title.')); + $form['weight'] = array( + type => 'weight', title => t('Weight'), default_value => $node->weight, delta => 15, + description => t('Pages at a given level are ordered first by weight and then by title.') + ); } else { // If a regular user updates a book page, we create a new revision // authored by that user: - $output .= form_hidden('revision', 1); + $form['revision'] = array(type => 'hidden', value => 1); } - return $output; + return $form; } /** Index: modules/filter.module =================================================================== RCS file: /cvs/drupal/drupal/modules/filter.module,v retrieving revision 1.71 diff -u -r1.71 filter.module --- modules/filter.module 25 Aug 2005 21:14:16 -0000 1.71 +++ modules/filter.module 1 Sep 2005 22:29:09 -0000 @@ -726,32 +726,26 @@ * @return * HTML for the form element. */ -function filter_form($name = 'format', $value = FILTER_FORMAT_DEFAULT) { +function filter_form($value = FILTER_FORMAT_DEFAULT) { if ($value == FILTER_FORMAT_DEFAULT) { $value = variable_get('filter_default_format', 1); } $formats = filter_formats(); $extra = l(t('More information about formatting options'), 'filter/tips'); - + + $form['format'] = array(type => 'fieldset', title => t('Input format'), collapsible => TRUE, collapsed => TRUE); if (count($formats) > 1) { // Multiple formats available: display radio buttons with tips. - $output = ''; foreach ($formats as $format) { - $tips = _filter_tips($format->format, false); - - // TODO: get support for block-level radios so the
is not output? - $output .= '
'; - $output .= ''; - $output .= theme('filter_tips', $tips); - $output .= '
'; + $form['format'][$format->name] = array(type=> 'filter_format', title => $format->name, default_value => $value, return_value => $format->fid, description => theme('filter_tips', _filter_tips($format->format, false))); } - $group = theme('form_element', NULL, $output, $extra, NULL, _form_get_error($name)); - return form_group_collapsible(t('Input format'), $group, TRUE); + return $form; } else { // Only one format available: use a hidden form item and only show tips. $format = array_shift($formats); + $form['format'][$format->name] = array(type => 'hidden', value => $format->format); $output = form_hidden($name, $format->format); $tips = _filter_tips(variable_get('filter_default_format', 1), false); $output .= form_item(t('Formatting guidelines'), theme('filter_tips', $tips, false, $extra), $extra); @@ -759,6 +753,20 @@ } } +function filter_elements() { + $type['filter_format'] = array(); + return $type; +} + +function theme_filter_format($element) { + $output .= '
'; + $output .= ''; + $output .= $element[description]; + $output .= '
'; + return $output; +} + + /** * Returns true if the user is allowed to access this format. */ Index: modules/node.module =================================================================== RCS file: /cvs/drupal/drupal/modules/node.module,v retrieving revision 1.526 diff -u -r1.526 node.module --- modules/node.module 30 Aug 2005 15:22:29 -0000 1.526 +++ modules/node.module 1 Sep 2005 22:29:56 -0000 @@ -6,6 +6,8 @@ * The core that allows content to be submitted to the site. */ +include_once 'includes/form.inc'; + define('NODE_NEW_LIMIT', time() - 30 * 24 * 60 * 60); /** @@ -400,7 +402,7 @@ /** * Save a node object into the database. */ -function node_save($node) { +function node_save(&$node) { global $user; $node->is_new = false; @@ -501,9 +503,6 @@ // Clear the cache so an anonymous poster can see the node being added or updated. cache_clear_all(); - - // Return the node ID: - return $node; } /** @@ -1298,121 +1297,92 @@ return $node; } + /** * Generate the node editing form. */ -function node_form($edit) { - // Validate the node if we don't already know the errors. +function node_form($node) { if (!$edit->validated) { $edit = node_validate($edit); } + // Set the id of the top-level form tag + $form[attributes]['id'] = 'node-form'; + // Prepend extra node form elements. - $form = implode('', node_invoke_nodeapi($edit, 'form pre')); + $form = array_merge($form, node_invoke_nodeapi($node, 'form pre')); + + /** + * Basic node information. + * These elements set the value property, making them immutable. + */ + $form['uid'] = array(type => 'hidden', value => $node->uid); + $form['created'] = array(type => 'hidden', value => $node->created); + $form['changed'] = array(type => 'hidden', value => $node->changed); + $form['type'] = array(type => 'hidden', value => $node->type); // Get the node-specific bits. // We can't use node_invoke() because $param must be passed by reference. - $function = node_get_base($edit) .'_form'; + $function = _node_names('base', $node) .'_form'; $param = array(); if (function_exists($function)) { - $form .= $function($edit, $param); + $node_form = $function($node, $param); + $form = array_merge($form, $function($node, $param)); } // Append extra node form elements. - $form .= implode('', node_invoke_nodeapi($edit, 'form post')); - - $output .= '
'; + $form = array_merge($form, node_invoke_nodeapi($node, 'form post')); - // Add hidden 'op' variable, which specifies the default operation (Preview). - $output .= '\n"; - - // Add the admin-specific parts. - if (user_access('administer nodes')) { - $output .= '
'; + /** + * Node author information + */ + $form['author'] = array(type => 'fieldset', title => t('Authoring information'), collapsible => TRUE, collapsed => TRUE, weight => -2); + $form['author']['name'] = array(type => 'textfield', title => t('Authored by'), maxlength => 60, autocomplete_path => 'user/autocomplete', default_value => $node->name, weight => -1); + $form['author']['date'] = array(type => 'textfield', title =>t('Authored on'), maxlength => 25, required => TRUE, default_value => $node->date); + + + $node_options = variable_get('node_options_'. $node->type, array('status', 'promote')); + + /** + * Node options + */ + $form['options'] = array(type => 'fieldset', title => t('Publishing options'), collapsible => TRUE, collapsed => TRUE, weight => -2); + $form['options']['status'] = array(type => 'checkbox', title => t('Published'), default_value => in_array('status', $node_options)); + $form['options']['moderate'] = array(type => 'checkbox', title => t('In moderation queue'), default_value => in_array('moderate', $node_options)); + $form['options']['promote'] = array(type => 'checkbox', title => t('Promoted to front page'), default_value => in_array('promote', $node_options)); + $form['options']['sticky'] = array(type => 'checkbox', title =>t('Sticky at top of lists'), default_value => in_array('sticky', $node_options)); + $form['options']['revision'] = array(type => 'checkbox', title =>t('Create new revision'), default_value => in_array('revision', $node_options)); - $author = form_autocomplete(t('Authored by'), 'name', $edit->name, 30, 60, 'user/autocomplete'); - $author .= form_textfield(t('Authored on'), 'date', $edit->date, 30, 25, NULL, NULL, TRUE); - - $output .= '
'; - $output .= form_group_collapsible(t('Authoring information'), $author, TRUE); - $output .= "
\n"; - - $node_options = variable_get('node_options_'. $edit->type, array('status', 'promote')); - $options .= form_checkbox(t('Published'), 'status', 1, isset($edit->status) ? $edit->status : in_array('status', $node_options)); - $options .= form_checkbox(t('In moderation queue'), 'moderate', 1, isset($edit->moderate) ? $edit->moderate : in_array('moderate', $node_options)); - $options .= form_checkbox(t('Promoted to front page'), 'promote', 1, isset($edit->promote) ? $edit->promote : in_array('promote', $node_options)); - $options .= form_checkbox(t('Sticky at top of lists'), 'sticky', 1, isset($edit->sticky) ? $edit->sticky : in_array('sticky', $node_options)); - $options .= form_checkbox(t('Create new revision'), 'revision', 1, isset($edit->revision) ? $edit->revision : in_array('revision', $node_options)); - - $output .= '
'; - $output .= form_group_collapsible(t('Publishing options'), $options, TRUE); - $output .= "
\n"; - - $extras .= implode('
', node_invoke_nodeapi($edit, 'form admin')); - $output .= $extras ? '
'. $extras .'
' : '
'; - } // Add the default fields. - $output .= '
'; - $output .= form_textfield(t('Title'), 'title', $edit->title, 60, 128, NULL, NULL, TRUE); - - // Add the node-type-specific fields. - $output .= $form; - - // Add the hidden fields. - if ($edit->nid) { - $output .= form_hidden('nid', $edit->nid); - } - - if (isset($edit->uid)) { - // The use of isset() is mandatory in the context of user IDs, because - // user ID 0 denotes the anonymous user. - $output .= form_hidden('uid', $edit->uid); - } - - if ($edit->created) { - $output .= form_hidden('created', $edit->created); - } - - if ($edit->changed) { - $output .= form_hidden('changed', $edit->changed); - } - - $output .= form_hidden('type', $edit->type); + $form['title'] = array(type => 'textfield', title => t('Title'), size => 60, maxlength => 128, required => TRUE, default_value => $node->title, weight => -1); // Add the buttons. - $output .= form_submit(t('Preview')); - - if ($edit->type && (($_POST['op'] == t('Preview') && !form_get_errors()) || !variable_get('node_preview', 0))) { - $output .= form_submit(t('Submit')); - } + $form['preview'] = array(type => 'submit', value => t('Preview'), weight => 19); - if ($edit->nid && node_access('delete', $edit)) { - $output .= form_submit(t('Delete')); + if ($node->type && (($_POST['op'] == t('Preview') && !form_get_errors()) || !variable_get('node_preview', 0))) { + $form['submit'] = array(type => 'submit', value => t('Submit'), weight => 20); } - $output .= '
'; - $extra = node_invoke_nodeapi($edit, 'form param'); - foreach ($extra as $key => $value) { - if (is_array($value)) { - if (isset($param[$key])) { - $param[$key] = array_merge($param[$key], $value); - } - else { - $param[$key] = $value; - } - } - else { - $param[$key] = $value; - } - } + return drupal_get_form($node->type . '_node_form', $form, 'node_form'); +} - $attributes = array('id' => 'node-form'); - if (is_array($param['options'])) { - $attributes = array_merge($param['options'], $attributes); - } - return form($output, ($param['method'] ? $param['method'] : 'post'), $param['action'], $attributes); +function theme_node_form($form) { + $output .= '
'; + $output .= '
'; + $output .= '
'; + $output .= form_render($form['author']); + $output .= '
'; + $output .= '
'; + $output .= form_render($form['options']); + $output .= '
'; + $output .= '
'; + $output .= '
'; + $output .= form_render($form); + $output .= '
'; + $output .= '
'; + return $output; } /** @@ -1435,7 +1405,7 @@ $node[$field] = $_GET['edit'][$field]; } } - $output = node_form($node); + $output = node_form(array2object($node)); drupal_set_title(t('Submit %name', array('%name' => node_get_name($node)))); } else { @@ -1573,7 +1543,7 @@ // Check whether the current user has the proper access rights to // perform this operation: if (node_access('update', $node)) { - node_save(&$node); + node_save($node); watchdog('content', t('%type: updated %title.', array('%type' => theme('placeholder', t($node->type)), '%title' => theme('placeholder', $node->title))), WATCHDOG_NOTICE, l(t('view'), 'node/'. $node->nid)); $msg = t('The %post was updated.', array ('%post' => node_get_name($node))); } @@ -1582,7 +1552,7 @@ // Check whether the current user has the proper access rights to // perform this operation: if (node_access('create', $node)) { - node_save(&$node); + node_save($node); watchdog('content', t('%type: added %title.', array('%type' => theme('placeholder', t($node->type)), '%title' => theme('placeholder', $node->title))), WATCHDOG_NOTICE, l(t('view'), "node/$node->nid")); $msg = t('Your %post was created.', array ('%post' => node_get_name($node))); } Index: modules/page.module =================================================================== RCS file: /cvs/drupal/drupal/modules/page.module,v retrieving revision 1.136 diff -u -r1.136 page.module --- modules/page.module 30 Aug 2005 15:22:29 -0000 1.136 +++ modules/page.module 1 Sep 2005 22:29:58 -0000 @@ -68,15 +68,21 @@ */ function page_form(&$node) { if (function_exists('taxonomy_node_form')) { - $output .= implode('', taxonomy_node_form('page', $node)); + $form['taxonomy'] = taxonomy_node_form('blog', $node); } - $output .= form_textarea(t('Body'), 'body', $node->body, 60, 20, '', NULL, TRUE); - $output .= filter_form('format', $node->format); + $form['body'] = array( + type => 'textarea', title => t('Body'), default_value => $node->body, required => TRUE + ); + $form = array_merge($form, filter_form($node->format)); - $output .= form_textarea(t('Log message'), 'log', $node->log, 60, 5, t('An explanation of the additions or updates being made to help other authors understand your motivations.')); - return $output; + $form['log'] = array( + type => 'textarea', title => t('Log message'), default_value => $node->log, required => TRUE, rows => 5, + description => t('An explanation of the additions or updates being made to help other authors understand your motivations.') + ); + + return $form; } Index: modules/story.module =================================================================== RCS file: /cvs/drupal/drupal/modules/story.module,v retrieving revision 1.170 diff -u -r1.170 story.module --- modules/story.module 29 Aug 2005 19:58:49 -0000 1.170 +++ modules/story.module 1 Sep 2005 22:29:58 -0000 @@ -67,16 +67,22 @@ * Implementation of hook_form(). */ function story_form(&$node) { - $output = ''; - if (function_exists('taxonomy_node_form')) { - $output .= implode('', taxonomy_node_form('story', $node)); + $form['taxonomy'] = taxonomy_node_form('blog', $node); } - $output .= form_textarea(t('Body'), 'body', $node->body, 60, 20, '', NULL, TRUE); - $output .= filter_form('format', $node->format); + $form['body'] = array( + type => 'textarea', title => t('Body'), default_value => $node->body, required => TRUE + ); + $form = array_merge($form, filter_form($node->format)); + + + $form['log'] = array( + type => 'textarea', title => t('Log message'), default_value => $node->log, required => TRUE, rows => 5, + description => t('An explanation of the additions or updates being made to help other authors understand your motivations.') + ); - return $output; + return $form; } Index: modules/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system.module,v retrieving revision 1.229 diff -u -r1.229 system.module --- modules/system.module 28 Aug 2005 18:17:47 -0000 1.229 +++ modules/system.module 1 Sep 2005 22:30:39 -0000 @@ -49,6 +49,33 @@ } /** + * Implementation of hook_elements(). + */ +function system_elements() { + // Top level form + $type['form'] = array(method => 'POST', action => request_uri()); + + // Inputs + $type['checkbox'] = array(input => TRUE, return_value => 1); + $type['submit'] = array(input => TRUE, name => 'op', button_type => 'submit'); + $type['button'] = array(input => TRUE, name => 'op', button_type => 'submit'); + $type['textfield'] = array(input => TRUE, size => 60, maxlength => 70, autocomplete_path => FALSE); + $type['password'] = array(input => TRUE, size => 60, maxlength => 70); + $type['textarea'] = array(input => TRUE, cols => 60, rows => 20); + $type['radios'] = array(input => TRUE, multiple => TRUE); + $type['checkboxes'] = array(input => TRUE); + $type['select'] = array(input => TRUE); + $type['weight'] = array(input => TRUE); + + // Form structure + $type['item'] = array(); + $type['hidden'] = array(input => TRUE); + $type['markup'] = array(prefix => '', suffix => ''); + $type['fieldset'] = array(collapsible => FALSE, collapsed => FALSE); + return $type; +} + +/** * Implementation of hook_menu(). */ function system_menu($may_cache) { @@ -179,62 +206,134 @@ function system_view_general() { // General settings: - $group = form_textfield(t('Name'), 'site_name', variable_get('site_name', 'drupal'), 60, 70, t('The name of this web site.')); - $group .= form_textfield(t('E-mail address'), 'site_mail', variable_get('site_mail', ini_get('sendmail_from')), 60, 128, t('A valid e-mail address for this website, used by the auto-mailer during registration, new password requests, notifications, etc.')); - $group .= form_textfield(t('Slogan'), 'site_slogan', variable_get('site_slogan', ''), 60, 128, t('The slogan of this website. Some themes display a slogan when available.')); - $group .= form_textarea(t('Mission'), 'site_mission', variable_get('site_mission', ''), 60, 5, t('Your site\'s mission statement or focus.')); - $group .= form_textarea(t('Footer message'), 'site_footer', variable_get('site_footer', ''), 60, 5, t('This text will be displayed at the bottom of each page. Useful for adding a copyright notice to your pages.')); - $group .= form_textfield(t('Anonymous user'), 'anonymous', variable_get('anonymous', 'Anonymous'), 60, 70, t('The name used to indicate anonymous users.')); - $group .= form_textfield(t('Default front page'), 'site_frontpage', variable_get('site_frontpage', 'node'), 60, 70, t('The home page displays content from this relative URL. If you are not using clean URLs, specify the part after "?q=". If unsure, specify "node".')); + $form['general'] = array( + type => 'fieldset', title => t('General settings'), + collapsible => TRUE, collapsed => TRUE + ); + $form['general']['site_name'] = array( + type => 'textfield', title => t('Name'), default_value => variable_get('site_name', 'drupal'), + description => t('The name of this web site.') + ); + $form['general']['site_mail'] = array( + type => 'textfield', title => t('E-mail address'), default_value => variable_get('site_mail', ini_get('sendmail_from')), maxlength => 128, + description => t('A valid e-mail address for this website, used by the auto-mailer during registration, new password requests, notifications, etc.') + ); + $form['general']['site_slogan'] = array( + type => 'textfield', title => t('Slogan'), default_value => variable_get('site_slogan', ''), + maxlength => 128, description => t('The slogan of this website. Some themes display a slogan when available.') + ); + + $form['general']['site_mission'] = array( + type => 'textarea', title => t('Mission'), default_value => variable_get('site_mission', ''), + rows => 5, description => t('Your site\'s mission statement or focus.') + ); + $form['general']['site_footer'] = array( + type => 'textarea', title => t('Footer message'), default_value => variable_get('site_footer', ''), rows => 5, + description => t('This text will be displayed at the bottom of each page. Useful for adding a copyright notice to your pages.') + ); + $form['general']['anonymous'] = array( + type => 'textfield', title => t('Anonymous user'), default_value => variable_get('anonymous', 'Anonymous'), + description => t('The name used to indicate anonymous users.') + ); + $form['general']['site_frontpage'] = array( + type => 'textfield', title => t('Default front page'), default_value => variable_get('site_frontpage', 'node'), + description => t('The home page displays content from this relative URL. If you are not using clean URLs, specify the part after "?q=". If unsure, specify "node".') + ); // We check for clean URL support using an image on the client side. - $group .= form_radios(t('Clean URLs'), 'clean_url', variable_get('clean_url', 0), array(t('Disabled'), t('Enabled')), t('This option makes Drupal emit clean URLs (i.e. without ?q= in the URL). You\'ll need ModRewrite support for this to work. See the .htaccess file in Drupal\'s top-level directory for more information.')); + $form['general']['clean_url'] = array( + type => 'radios', title => t('Clean URLs'), default_value => variable_get('clean_url', 0), options => array(t('Disabled'), t('Enabled')), + description => t('This option makes Drupal emit clean URLs (i.e. without ?q= in the URL). You\'ll need ModRewrite support for this to work. See the .htaccess file in Drupal\'s top-level directory for more information.') + ); + variable_set('clean_url_ok', 0); global $base_url; // We will use a random URL so there is no way a proxy or a browser could cache the "no such image" answer. - $group .= ''; + $form['general']['clean_url_test'] = array(type => 'markup', value => ''); - $output = form_group_collapsible(t('General settings'), $group, TRUE); // Error handling: + + $form['errors'] = array( type => 'fieldset', title =>t('Error handling'), collapsible => TRUE, collapsed => TRUE ); + $form['errors']['site_403'] = array( + type => 'textfield', title => t('Default 403 (access denied) page'), default_value => variable_get('site_403', ''), + description => t('This page is displayed when the requested document is denied to the current user. If you are not using clean URLs, specify the part after "?q=". If unsure, specify nothing.') + ); + + $form['errors']['site_404'] = array( + type => 'textfield', title => t('Default 404 (not found) page'), default_value => variable_get('site_404', ''), + description => t('This page is displayed when no other content matches the requested document. If you are not using clean URLs, specify the part after "?q=". If unsure, specify nothing.') + ); + + $form['errors']['error_level'] = array( + type => 'select', title => t('Error reporting'), default_value => variable_get('error_level', 1), + options => array(t('Write errors to the log'), t('Write errors to the log and to the screen')), + description => t('Where Drupal, PHP and SQL errors are logged. On a production server it is recommended that errors are only written to the error log. On a test server it can be helpful to write logs to the screen.') + ); + $period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200), 'format_interval'); $period['1000000000'] = t('Never'); - $group = form_textfield(t('Default 403 (access denied) page'), 'site_403', variable_get('site_403', ''), 60, 70, t('This page is displayed when the requested document is denied to the current user. If you are not using clean URLs, specify the part after "?q=". If unsure, specify nothing.')); - $group .= form_textfield(t('Default 404 (not found) page'), 'site_404', variable_get('site_404', ''), 60, 70, t('This page is displayed when no other content matches the requested document. If you are not using clean URLs, specify the part after "?q=". If unsure, specify nothing.')); - $group .= form_select(t('Error reporting'), 'error_level', variable_get('error_level', 1), array(t('Write errors to the log'), t('Write errors to the log and to the screen')), t('Where Drupal, PHP and SQL errors are logged. On a production server it is recommended that errors are only written to the error log. On a test server it can be helpful to write logs to the screen.')); - $group .= form_select(t('Discard log entries older than'), 'watchdog_clear', variable_get('watchdog_clear', 604800), $period, t('The time log entries should be kept. Older entries will be automatically discarded. Requires crontab.')); + $form['errors']['watchdog_clear'] = array( + type => 'select', title => t('Discard log entries older than'), default_value => variable_get('watchdog_clear', 604800), options => $period, + description => t('The time log entries should be kept. Older entries will be automatically discarded. Requires crontab.') + ); - $output .= form_group_collapsible(t('Error handling'), $group, TRUE); // Caching: - $group = form_radios(t('Page cache'), 'cache', variable_get('cache', CACHE_DISABLED), array(CACHE_DISABLED => t('Disabled'), CACHE_ENABLED => t('Enabled')), t("Drupal has a caching mechanism which stores dynamically generated web pages in a database. By caching a web page, Drupal does not have to create the page each time someone wants to view it, instead it takes only one SQL query to display it, reducing response time and the server's load. Only pages requested by \"anonymous\" users are cached. In order to reduce server load and save bandwidth, Drupal stores and sends compressed cached pages.")); + $form['cache'] = array(type => 'fieldset', title => t('Cache settings'), collapsible => TRUE, collapsed => TRUE); + + $form['cache']['cache'] = array( + type => 'radios', title => t('Page cache'), default_value => variable_get('cache', CACHE_DISABLED), + options => array(CACHE_DISABLED => t('Disabled'), CACHE_ENABLED => t('Enabled')), + description => t("Drupal has a caching mechanism which stores dynamically generated web pages in a database. By caching a web page, Drupal does not have to create the page each time someone wants to view it, instead it takes only one SQL query to display it, reducing response time and the server's load. Only pages requested by \"anonymous\" users are cached. In order to reduce server load and save bandwidth, Drupal stores and sends compressed cached pages.") + ); + $period = drupal_map_assoc(array(0, 60, 180, 300, 600, 900, 1800, 2700, 3600, 10800, 21600, 32400, 43200, 86400), 'format_interval'); $period[0] = t('none'); - $group .= form_select(t('Minimum cache lifetime'), 'cache_lifetime', variable_get('cache_lifetime', 0), $period, t('Enabling the cache will offer a sufficient performance boost for most low-traffic and medium-traffic sites. On high-traffic sites it can become necessary to enforce a minimum cache lifetime. The minimum cache lifetime is the minimum amount of time that will go by before the cache is emptied and recreated. A larger minimum cache lifetime offers better performance, but users will not see new content for a longer period of time.')); + $form['cache']['cache_lifetime'] = array( + type => 'select', title => t('Minimum cache lifetime'), default_value => variable_get('cache_lifetime', 0), options => $period, + description => t('Enabling the cache will offer a sufficient performance boost for most low-traffic and medium-traffic sites. On high-traffic sites it can become necessary to enforce a minimum cache lifetime. The minimum cache lifetime is the minimum amount of time that will go by before the cache is emptied and recreated. A larger minimum cache lifetime offers better performance, but users will not see new content for a longer period of time.') + ); - $output .= form_group_collapsible(t('Cache settings'), $group, TRUE); // File system: + $form['files'] = array(type => 'fieldset', title => t('File system settings'), collapsible => TRUE, collapsed => TRUE); + $directory_path = variable_get('file_directory_path', 'files'); file_check_directory($directory_path, FILE_CREATE_DIRECTORY, 'file_directory_path'); + $form['files']['file_directory_path'] = array( + type => 'textfield', title => t('File system path'), default_value => $directory_path, maxlength => 255, valid => 'directory', + description => t('A file system path where the files will be stored. This directory has to exist and be writable by Drupal. If the download method is set to public this directory has to be relative to Drupal installation directory, and be accessible over the web. When download method is set to private this directory should not be accessible over the web. Changing this location after the site has been in use will cause problems so only change this setting on an existing site if you know what you are doing.') + ); + $directory_temp = variable_get('file_directory_temp', FILE_DIRECTORY_TEMP); file_check_directory($directory_temp, FILE_CREATE_DIRECTORY, 'file_directory_temp'); - - $group = form_textfield(t('File system path'), 'file_directory_path', $directory_path, 60, 255, t('A file system path where the files will be stored. This directory has to exist and be writable by Drupal. If the download method is set to public this directory has to be relative to Drupal installation directory, and be accessible over the web. When download method is set to private this directory should not be accessible over the web. Changing this location after the site has been in use will cause problems so only change this setting on an existing site if you know what you are doing.')); - $group .= form_textfield(t('Temporary directory'), 'file_directory_temp', $directory_temp, 60, 255, t('Location where uploaded files will be kept during previews. Relative paths will be resolved relative to the file system path.')); - $group .= form_radios(t('Download method'), 'file_downloads', variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC), array(FILE_DOWNLOADS_PUBLIC => t('Public - files are available using http directly.'), FILE_DOWNLOADS_PRIVATE => t('Private - files are transferred by Drupal.')), t('If you want any sort of access control on the downloading of files, this needs to be set to private. You can change this at any time, however all download URLs will change and there may be unexpected problems so it is not recommended.')); - $output .= form_group_collapsible(t('File system settings'), $group, TRUE); + + $form['files']['file_directory_tmp'] = array( + type => 'textfield', title => t('Temporary directory'), default_value => $directory_temp, maxlength => 255, valid => 'directory', + description => t('Location where uploaded files will be kept during previews. Relative paths will be resolved relative to the file system path.') + ); + + $form['files']['file_downloads'] = array( + type => 'radios', title => t('Download method'), default_value => variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC), + options => array(FILE_DOWNLOADS_PUBLIC => t('Public - files are available using http directly.'), FILE_DOWNLOADS_PRIVATE => t('Private - files are transferred by Drupal.')), + description => t('If you want any sort of access control on the downloading of files, this needs to be set to private. You can change this at any time, however all download URLs will change and there may be unexpected problems so it is not recommended.') + ); // Image handling: - $group = ''; + $group = array(); $toolkits_available = image_get_available_toolkits(); if (count($toolkits_available) > 1) { - $group .= form_radios(t('Select an image processing toolkit'), 'image_toolkit', variable_get('image_toolkit', image_get_toolkit()), $toolkits_available); - } - $group .= image_toolkit_invoke('settings'); - if ($group) { - $output .= form_group_collapsible(t('Image handling'), '

'. $group .'

', TRUE); + $group['image_toolkit'] = array( + type => 'radios', title => t('Select an image processing toolkit'), + default_value => variable_get('image_toolkit', image_get_toolkit()), options => $toolkits_available + ); + } + $group['toolkit'] = image_toolkit_invoke('settings'); + if (is_array($group)) { + $form['image'] = array(type => 'fieldset', title => t('Image handling'), collapsible => TRUE, collapsed => true); + $form['image'] = array_merge($form['image'], $group); } // Date settings: @@ -263,19 +362,44 @@ $datelongchoices[$f] = format_date(time(), 'custom', $f); } - $group = form_select(t('Default time zone'), 'date_default_timezone', variable_get('date_default_timezone', 0), $zones, t('Select the default site time zone.')); - $group .= form_radios(t('Configurable time zones'), 'configurable_timezones', variable_get('configurable_timezones', 1), array(t('Disabled'), t('Enabled')), t('Enable or disable user-configurable time zones. When enabled, users can set their own time zone and dates will be updated accordingly.')); - $group .= form_select(t('Short date format'), 'date_format_short', variable_get('date_format_short', $dateshort[0]), $dateshortchoices, t('The short format of date display.')); - $group .= form_select(t('Medium date format'), 'date_format_medium', variable_get('date_format_medium', $datemedium[0]), $datemediumchoices, t('The medium sized date display.')); - $group .= form_select(t('Long date format'), 'date_format_long', variable_get('date_format_long', $datelong[0]), $datelongchoices, t('Longer date format used for detailed display.')); - $group .= form_select(t('First day of week'), 'date_first_day', variable_get('date_first_day', 0), array(0 => t('Sunday'), 1 => t('Monday'), 2 => t('Tuesday'), 3 => t('Wednesday'), 4 => t('Thursday'), 5 => t('Friday'), 6 => t('Saturday')), t('The first day of the week for calendar views.')); + $form['dates'] = array(type => 'fieldset', title => t('Date settings'), collapsible => TRUE, collapsed => TRUE); + $form['dates']['date_default_timezone'] = array( + type => 'select', title => t('Default time zone'), default_value => variable_get('date_default_timezone', 0), + options => $zones, description => t('Select the default site time zone.') + ); + + $form['dates']['configurable_timezones'] = array( + type => 'radios', title => t('Configurable time zones'), default_value => variable_get('configurable_timezones', 1), options => array(t('Disabled'), t('Enabled')), + description => t('Enable or disable user-configurable time zones. When enabled, users can set their own time zone and dates will be updated accordingly.') + ); + + $form['dates']['date_format_short'] = array( + type => 'select', title => t('Short date format'), default_value => variable_get('date_format_short', $dateshort[0]), + options => $dateshortchoices, description => t('The short format of date display.') + ); + + $form['dates']['date_format_medium'] = array( + type => 'select', title => t('Medium date format'), default_value => variable_get('date_format_medium', $datemedium[0]), + options => $datemediumchoices, description => t('The medium sized date display.') + ); + + $form['dates']['date_format_long'] = array( + type => 'select', title => t('Long date format'), default_value => variable_get('date_format_long', $datelong[0]), + options => $datelongchoices, description => t('Longer date format used for detailed display.') + ); + + $form['dates']['date_first_day'] = array( + type => 'select', title => t('First day of week'), default_value => variable_get('date_first_day', 0), + options => array(0 => t('Sunday'), 1 => t('Monday'), 2 => t('Tuesday'), 3 => t('Wednesday'), 4 => t('Thursday'), 5 => t('Friday'), 6 => t('Saturday')), + description => t('The first day of the week for calendar views.') + ); - $output .= form_group_collapsible(t('Date settings'), $group, TRUE); // String handling: report status and errors. - $output .= form_group_collapsible(t('String handling'), unicode_settings(), TRUE); + $form['strings'] = array(type => 'fieldset', title => t('String handling'), collapsible => TRUE, collapsed => TRUE); + $form['strings']['settings'] = array_merge($from['strings'], unicode_settings()); - return $output; + return $form; } /** @@ -607,42 +731,58 @@ } } -function system_settings_form($form) { - $form .= form_submit(t('Save configuration')); - $form .= form_submit(t('Reset to defaults')); +// Add the submit / reset buttons and run drupal_get_form() +function system_settings_form($form_id, $form) { + $form['buttons']['submit'] = array(type => 'submit', value => t('Save configuration') ); + $form['buttons']['reset'] = array(type => 'submit', value => t('Reset to defaults') ); - return form($form); + return drupal_get_form($form_id, $form, $_POST['edit'], 'system_settings_form'); } -function system_settings_save() { +/** + * Execute the system_settings_form. Use the system_settings_save() recursive function. + */ +function system_settings_form_execute($form_id, $form) { $op = $_POST['op']; $edit = $_POST['edit']; if ($op == t('Reset to defaults')) { - if (is_array($edit)) { - foreach ($edit as $name => $value) { - variable_del($name); - } - } + system_settings_save(TRUE); drupal_set_message(t('The configuration options have been reset to their default values.')); } else if ($op == t('Save configuration')) { - if (is_array($edit)) { - if ($edit['clean_url'] && !variable_get('clean_url_ok', 0)) { - drupal_set_message(t('It appears your host is not configured correctly for Clean URLs. Please check for ModRewrite support with your administrator.'), 'error'); - $edit['clean_url'] = 0; - } - foreach ($edit as $name => $value) { - variable_set($name, $value); - } - } + system_settings_save(); drupal_set_message(t('The configuration options have been saved.')); } - else { - return; - } + menu_rebuild(); - drupal_goto($_GET['q']); +} + +/** + * Do the clean url validation, changing the form property if it doesn't work. + */ +function system_settings_validate($form_id, &$form) { + #TODO .. fix here. + if ($edit['clean_url'] && !variable_get('clean_url_ok', 0)) { + drupal_set_message(t('It appears your host is not configured correctly for Clean URLs. Please check for ModRewrite support with your administrator.'), 'error'); + $edit['clean_url'] = 0; + } + +} + +/** + * Save all the variables submitted to the system table. + */ +function system_settings_save($reset = FALSE) { + global $form_variable; + foreach ($form_variable as $key => $value) { + if ($reset) { + variable_del($key); + } + else { + variable_set($key, $value); + } + } } /** @@ -669,16 +809,16 @@ * Menu callback; displays a module's settings page. */ function system_site_settings($module = NULL) { - system_settings_save(); if ($module) { $form = module_invoke($module, 'settings'); } else { $form = system_view_general(); + $module = 'system'; } - return system_settings_form($form); + return system_settings_form($module . '_settings_form', $form); } /** @@ -724,7 +864,6 @@ } } - system_settings_save(); $form = ''; Index: modules/taxonomy.module =================================================================== RCS file: /cvs/drupal/drupal/modules/taxonomy.module,v retrieving revision 1.222 diff -u -r1.222 taxonomy.module --- modules/taxonomy.module 28 Aug 2005 16:30:50 -0000 1.222 +++ modules/taxonomy.module 1 Sep 2005 22:31:07 -0000 @@ -510,14 +510,18 @@ } } $typed_string = implode(', ', $typed_terms) . (array_key_exists('tags', $terms) ? $terms['tags'][$vocabulary->vid] : NULL); - $result[] = form_autocomplete($vocabulary->name, "$name][tags][". $vocabulary->vid, $typed_string, 60, 100, 'taxonomy/autocomplete/'. $vocabulary->vid, t('A comma-separated list of terms describing this content (Example: funny, bungie jumping, "Company, Inc.").'), NULL, ($vocabulary->required ? TRUE : FALSE)); + + + $form[$name]['tags'][$vocabulary->vid] = array( type => textfield, default_value => $typed_string, size => 60, maxlength => 100, + autocomplete_path => 'taxonomy/autocomplete/'. $vocabulary->vid, required => ($vocabulary->required ? TRUE : FALSE), title => $vocabulary->name, + description => t('A comma-separated list of terms describing this content (Example: funny, bungie jumping, "Company, Inc.").') ); } else { $ntterms = array_key_exists('taxonomy', $node) ? $terms : array_keys($terms); - $result[] = taxonomy_form($vocabulary->vid, $ntterms, $help, $name); + $form[$name][$vocabulary->vid] = taxonomy_form($vocabulary->vid, $ntterms, $help, $name); } } - return $result ? $result : array(); + return $form ? $form : array(); } /** @@ -888,8 +892,8 @@ $value = $tree[0]->tid; } } - - return form_select($title, $name . ($multiple ? '' : ']['), $value, $options, $description, $multiple ? 'size="'. min(12, count($options)) .'"' : 0, $multiple); + $form[$name] = array(type => 'select', default_value => $value, options => $options, description => $description, multiple => $multiple, size => $multiple ? 'size="'. min(12, count($options)) .'"' : 0); + return $form; } function _taxonomy_depth($depth, $graphic = '--') { Index: modules/upload.module =================================================================== RCS file: /cvs/drupal/drupal/modules/upload.module,v retrieving revision 1.50 diff -u -r1.50 upload.module --- modules/upload.module 31 Aug 2005 18:37:30 -0000 1.50 +++ modules/upload.module 1 Sep 2005 22:31:28 -0000 @@ -163,7 +163,6 @@ $node->list[$key] = $file->list; } } - if (($file = file_check_upload('upload')) && user_access('upload files')) { global $user; Index: modules/user.module =================================================================== RCS file: /cvs/drupal/drupal/modules/user.module,v retrieving revision 1.502 diff -u -r1.502 user.module --- modules/user.module 25 Aug 2005 21:14:17 -0000 1.502 +++ modules/user.module 1 Sep 2005 22:32:22 -0000 @@ -6,6 +6,8 @@ * Enables the user registration and login system. */ +include_once './includes/form.inc'; + /** * Invokes hook_user() in every module. * @@ -515,20 +517,14 @@ case 0: // For usability's sake, avoid showing two login forms on one page. if (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1)))) { - $edit = $_POST['edit']; - - $output = "
\n"; - // NOTE: special care needs to be taken because on pages with forms, // such as node and comment submission pages, the $edit variable // might already be set. - $output .= form_textfield(t('Username'), 'name', $edit['name'], 15, 64); - $output .= form_password(t('Password'), 'pass', $pass, 15, 64); - $output .= form_submit(t('Log in')); - $output .= "
\n"; - - $output = form($output, 'post', url('user/login', drupal_get_destination())); + $form['name'] = array(type => 'textfield', title => t('Username'), maxlength => 64, size => 15, required => TRUE); + $form['pass'] = array(type => 'password', title => t('Password'), maxlength => 64, size => 15, required => TRUE); + $form['submit'] = array(type => 'submit', value => t('Log in')); + $output .= drupal_get_form('user_login_block', $form, 'user_login'); if (variable_get('user_register', 1)) { $items[] = l(t('Create new account'), 'user/register', array('title' => t('Create a new user account.'))); @@ -600,6 +596,15 @@ } } + + +function theme_user_login_block($form) { + $output = "
\n"; + $output .= form_render($form); + $output .= "
\n"; + return $output; +} + function theme_user_picture($account) { if (variable_get('user_pictures', 0)) { if ($account->picture && file_exists($account->picture)) { @@ -816,6 +821,8 @@ /*** User features *********************************************************/ + + function user_login($edit = array(), $msg = '') { global $user, $base_url; @@ -868,16 +875,27 @@ if ($msg) { $output .= "

$msg

"; } + $form['name'] = array(type => 'textfield', title => t('Username'), size => 30, maxlength => 64, required => TRUE); if (count(user_auth_help_links()) > 0) { - $output .= form_textfield(t('Username'), 'name', $edit['name'], 30, 64, t('Enter your %s username, or an ID from one of our affiliates: %a.', array('%s' => variable_get('site_name', 'local'), '%a' => implode(', ', user_auth_help_links())))); + $form['name'][description] = t('Enter your %s username, or an ID from one of our affiliates: %a.', array('%s' => variable_get('site_name', 'local'), '%a' => implode(', ', user_auth_help_links()))); } else { - $output .= form_textfield(t('Username'), 'name', $edit['name'], 30, 64, t('Enter your %s username.', array('%s' => variable_get('site_name', 'local')))); + $form['name'][description] = t('Enter your %s username.', array('%s' => variable_get('site_name', 'local'))); + } + $form['pass'] = array(type => 'password', title => t('Password'), size => 30, maxlength => 64, description => t('Enter the password that accompanies your username.'), required => TRUE); + $form['submit'] = array(type => 'submit', value => t('Log in'), weight => 2); + return drupal_get_form('user_login', $form); +} + +function user_login_validate($form) { + if (!user_authenticate($form['name'][value], $form['pass'][value])) { + form_set_error($form['name'][name], t('invalid username and password')); } - $output .= form_password(t('Password'), 'pass', $pass, 30, 64, t('Enter the password that accompanies your username.')); - $output .= form_submit(t('Log in')); +} - return form($output, 'post', url('user/login', drupal_get_destination())); +function user_login_execute($form) { + global $form_variables; + return user_login($form_variables); } function user_authenticate($name, $pass) { @@ -1302,10 +1320,6 @@ case 'register': return user_register($edit); break; - case t('Log in'): - case 'login': - return user_login($edit); - break; default: if (!arg(1)) { if ($user->uid) {