Index: includes/menu.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/menu.inc,v retrieving revision 1.163 diff -u -p -r1.163 menu.inc --- includes/menu.inc 24 Apr 2007 08:26:58 -0000 1.163 +++ includes/menu.inc 30 Apr 2007 05:37:51 -0000 @@ -343,6 +343,10 @@ function menu_get_item($path = NULL, $it */ function menu_execute_active_handler() { if ($item = menu_get_item()) { + //dsm($item); + if ($item->includes) { + include_once($item->includes); + } return $item->access ? call_user_func_array($item->page_callback, $item->page_arguments) : MENU_ACCESS_DENIED; } return MENU_NOT_FOUND; @@ -777,10 +781,16 @@ function menu_rebuild() { $item['page callback'] = $parent['page callback']; if (!isset($item['page arguments']) && isset($parent['page arguments'])) { $item['page arguments'] = $parent['page arguments']; + if (empty($item['includes'])) { + $item['includes'] = $parent['includes']; + } } } } } + if (!isset($item['includes'])) { + $item['includes'] = ''; + } if (!isset($item['access callback'])) { $item['access callback'] = isset($item['access arguments']) ? 'user_access' : 0; } @@ -843,15 +853,16 @@ function menu_rebuild() { if (!empty($item['disabled'])) { $item['_visible'] = FALSE; } + db_query("INSERT INTO {menu} ( mid, pid, path, load_functions, to_arg_functions, access_callback, access_arguments, page_callback, page_arguments, fit, number_parts, visible, parents, depth, has_children, tab, title, parent, type, mleft, mright, block_callback, description, position, - link_path, attributes, query, fragment, absolute, html) + link_path, attributes, query, fragment, absolute, html, includes) VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', %d, %d, %d, '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', - '%s', '%s', '%s', '%s', %d, %d)", + '%s', '%s', '%s', '%s', %d, %d, '%s')", $item['_mid'], $item['_pid'], $path, $item['load_functions'], $item['to_arg_functions'], $item['access callback'], serialize($item['access arguments']), $item['page callback'], @@ -862,7 +873,7 @@ function menu_rebuild() { $item['_mright'], $item['block callback'], $item['description'], $item['position'], $link_path, $item['attributes'], $item['query'], $item['fragment'], - $item['absolute'], $item['html']); + $item['absolute'], $item['html'], $item['includes']); } } Index: modules/block/block.module =================================================================== RCS file: /cvs/drupal/drupal/modules/block/block.module,v retrieving revision 1.257 diff -u -p -r1.257 block.module --- modules/block/block.module 17 Apr 2007 07:19:38 -0000 1.257 +++ modules/block/block.module 30 Apr 2007 05:37:52 -0000 @@ -76,6 +76,7 @@ function block_menu() { 'page callback' => 'drupal_get_form', 'page arguments' => array('block_admin_display'), 'access arguments' => array('administer blocks'), + 'includes' => drupal_get_path('module', 'block') . '/block.pages.inc', ); $items['admin/build/block/list'] = array( 'title' => t('List'), @@ -96,6 +97,7 @@ function block_menu() { 'title' => t('Add block'), 'page arguments' => array('block_add_block_form'), 'type' => MENU_LOCAL_TASK, + 'includes' => drupal_get_path('module', 'block') . '/block.pages.inc', ); $default = variable_get('theme_default', 'garland'); foreach (list_themes() as $key => $theme) { @@ -146,6 +148,42 @@ function block_block($op = 'list', $delt } } + +/** + * Implementation of hook_user(). + * + * Allow users to decide which custom blocks to display when they visit + * the site. + */ +function block_user($type, $edit, &$user, $category = NULL) { + global $user; + switch ($type) { + case 'form': + if ($category == 'account') { + $result = db_query("SELECT DISTINCT b.* FROM {blocks} b LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta WHERE b.status = 1 AND b.custom != 0 AND (r.rid IN (%s) OR r.rid IS NULL) ORDER BY b.weight, b.module", implode(',', array_keys($user->roles))); + $form['block'] = array('#type' => 'fieldset', '#title' => t('Block configuration'), '#weight' => 3, '#collapsible' => TRUE, '#tree' => TRUE); + while ($block = db_fetch_object($result)) { + $data = module_invoke($block->module, 'block', 'list'); + if ($data[$block->delta]['info']) { + $return = TRUE; + $form['block'][$block->module][$block->delta] = array('#type' => 'checkbox', '#title' => check_plain($data[$block->delta]['info']), '#default_value' => isset($user->block[$block->module][$block->delta]) ? $user->block[$block->module][$block->delta] : ($block->custom == 1)); + } + } + + if (!empty($return)) { + return $form; + } + } + + break; + case 'validate': + if (empty($edit['block'])) { + $edit['block'] = array(); + } + return $edit; + } +} + /** * Update the 'blocks' DB table with the blocks currently exported by modules. * @@ -214,450 +252,6 @@ function _block_rehash() { } /** - * Generate main block administration form. - */ -function block_admin_display($theme = NULL) { - global $theme_key, $custom_theme; - - // Add CSS - drupal_add_css(drupal_get_path('module', 'block') .'/block.css', 'module', 'all', FALSE); - - // If non-default theme configuration has been selected, set the custom theme. - if ($theme) { - $custom_theme = $theme; - } - else { - $custom_theme = variable_get('theme_default', 'garland'); - } - init_theme(); - - // Fetch and sort blocks - $blocks = _block_rehash(); - usort($blocks, '_block_compare'); - - $throttle = module_exists('throttle'); - $block_regions = array(BLOCK_REGION_NONE => '<'. t('none') .'>') + system_region_list($theme_key); - - // Build form tree - $form['#action'] = arg(3) ? url('admin/build/block/list/'. $theme_key) : url('admin/build/block'); - $form['#tree'] = TRUE; - foreach ($blocks as $i => $block) { - $form[$i]['module'] = array('#type' => 'value', '#value' => $block['module']); - $form[$i]['delta'] = array('#type' => 'value', '#value' => $block['delta']); - $form[$i]['info'] = array('#value' => check_plain($block['info'])); - $form[$i]['theme'] = array('#type' => 'hidden', '#value' => $theme_key); - $form[$i]['weight'] = array('#type' => 'weight', '#default_value' => $block['weight']); - $form[$i]['region'] = array('#type' => 'select', - '#default_value' => $block['status'] ? (isset($block['region']) ? $block['region'] : system_default_region($theme_key)) : BLOCK_REGION_NONE, - '#options' => $block_regions, - ); - - if ($throttle) { - $form[$i]['throttle'] = array('#type' => 'checkbox', '#default_value' => isset($block['throttle']) ? $block['throttle'] : FALSE); - } - $form[$i]['configure'] = array('#value' => l(t('configure'), 'admin/build/block/configure/'. $block['module'] .'/'. $block['delta'])); - if ($block['module'] == 'block') { - $form[$i]['delete'] = array('#value' => l(t('delete'), 'admin/build/block/delete/'. $block['delta'])); - } - } - $form['submit'] = array('#type' => 'submit', '#value' => t('Save blocks')); - - return $form; -} - -/** - * Helper function for sorting blocks on admin/build/block. - * - * Active blocks are sorted by region, then by weight. - * Disabled blocks are sorted by name. - */ -function _block_compare($a, $b) { - $status = $b['status'] - $a['status']; - // Separate enabled from disabled. - if ($status) { - return $status; - } - // Enabled blocks - if ($a['status']) { - $place = strcmp($a['region'], $b['region']); - return $place ? $place : ($a['weight'] - $b['weight']); - } - // Disabled blocks - else { - return strcmp($a['info'], $b['info']); - } -} - -/** - * Process main block administration form submission. - */ -function block_admin_display_submit($form_id, $form_values) { - foreach ($form_values as $block) { - $block['status'] = $block['region'] != BLOCK_REGION_NONE; - $block['region'] = $block['status'] ? $block['region'] : ''; - db_query("UPDATE {blocks} SET status = %d, weight = %d, region = '%s', throttle = %d WHERE module = '%s' AND delta = '%s' AND theme = '%s'", $block['status'], $block['weight'], $block['region'], $block['throttle'], $block['module'], $block['delta'], $block['theme']); - } - drupal_set_message(t('The block settings have been updated.')); - cache_clear_all(); -} - -/** - * Theme main block administration form submission. - * - * Note: the blocks are already sorted in the right order, - * grouped by status, region and weight. - */ -function theme_block_admin_display($form) { - global $theme_key; - - $throttle = module_exists('throttle'); - $block_regions = system_region_list($theme_key); - - // Highlight regions on page to provide visual reference. - foreach ($block_regions as $key => $value) { - drupal_set_content($key, '
'. $value .'
'); - } - - // Build rows - $rows = array(); - $last_region = ''; - $last_status = 1; - foreach (element_children($form) as $i) { - $block = &$form[$i]; - // Only take form elements that are blocks. - if (isset($block['info'])) { - // Fetch values - $region = $block['region']['#default_value']; - $status = $region != BLOCK_REGION_NONE; - - // Output region header - if ($status && $region != $last_region) { - $region_title = t('@region', array('@region' => drupal_ucfirst($block_regions[$region]))); - $rows[] = array(array('data' => $region_title, 'class' => 'region', 'colspan' => ($throttle ? 7 : 6))); - $last_region = $region; - } - // Output disabled header - elseif ($status != $last_status) { - $rows[] = array(array('data' => t('Disabled'), 'class' => 'region', 'colspan' => ($throttle ? 7 : 6))); - $last_status = $status; - } - - // Generate block row - $row = array( - array('data' => drupal_render($block['info']), 'class' => 'block'), - drupal_render($block['region']) . drupal_render($block['theme']), - drupal_render($block['weight']), - ); - if ($throttle) { - $row[] = drupal_render($block['throttle']); - } - $row[] = drupal_render($block['configure']); - $row[] = !empty($block['delete']) ? drupal_render($block['delete']) : ''; - $rows[] = $row; - } - } - - // Finish table - $header = array(t('Block'), t('Region'), t('Weight')); - if ($throttle) { - $header[] = t('Throttle'); - } - $header[] = array('data' => t('Operations'), 'colspan' => 2); - - $output = theme('table', $header, $rows, array('id' => 'blocks')); - - $output .= drupal_render($form); - - return $output; -} - -function block_box_get($bid) { - return db_fetch_array(db_query("SELECT bx.*, title FROM {boxes} bx INNER JOIN {blocks} bl ON bx.bid = bl.delta WHERE module = 'block' AND bid = %d", $bid)); -} - -/** - * Menu callback; displays the block configuration form. - */ -function block_admin_configure($module = NULL, $delta = 0) { - - $form['module'] = array('#type' => 'value', '#value' => $module); - $form['delta'] = array('#type' => 'value', '#value' => $delta); - - $edit = db_fetch_array(db_query("SELECT pages, visibility, custom, title FROM {blocks} WHERE module = '%s' AND delta = '%s'", $module, $delta)); - - $form['block_settings'] = array( - '#type' => 'fieldset', - '#title' => t('Block specific settings'), - '#collapsible' => TRUE, - ); - $form['block_settings']['title'] = array( - '#type' => 'textfield', - '#title' => t('Block title'), - '#maxlength' => 64, - '#description' => $module == 'block' ? t('The title of the block as shown to the user.') : t('Override the default title for the block. Use <none> to display no title, or leave blank to use the default block title.'), - '#default_value' => $edit['title'], - '#weight' => -18, - ); - - - // Module-specific block configurations. - if ($settings = module_invoke($module, 'block', 'configure', $delta)) { - foreach ($settings as $k => $v) { - $form['block_settings'][$k] = $v; - } - } - - // Get the block subject for the page title. - $info = module_invoke($module, 'block', 'list'); - if (isset($info[$delta])) { - drupal_set_title(t("'%name' block", array('%name' => $info[$delta]['info']))); - } - - // Standard block configurations. - $form['user_vis_settings'] = array( - '#type' => 'fieldset', - '#title' => t('User specific visibility settings'), - '#collapsible' => TRUE, - ); - $form['user_vis_settings']['custom'] = array( - '#type' => 'radios', - '#title' => t('Custom visibility settings'), - '#options' => array( - t('Users cannot control whether or not they see this block.'), - t('Show this block by default, but let individual users hide it.'), - t('Hide this block by default but let individual users show it.') - ), - '#description' => t('Allow individual users to customize the visibility of this block in their account settings.'), - '#default_value' => $edit['custom'], - ); - - // Role-based visibility settings - $default_role_options = array(); - $result = db_query("SELECT rid FROM {blocks_roles} WHERE module = '%s' AND delta = '%s'", $module, $delta); - while ($role = db_fetch_object($result)) { - $default_role_options[] = $role->rid; - } - $result = db_query('SELECT rid, name FROM {role} ORDER BY name'); - $role_options = array(); - while ($role = db_fetch_object($result)) { - $role_options[$role->rid] = $role->name; - } - $form['role_vis_settings'] = array( - '#type' => 'fieldset', - '#title' => t('Role specific visibility settings'), - '#collapsible' => TRUE, - ); - $form['role_vis_settings']['roles'] = array( - '#type' => 'checkboxes', - '#title' => t('Show block for specific roles'), - '#default_value' => $default_role_options, - '#options' => $role_options, - '#description' => t('Show this block only for the selected role(s). If you select no roles, the block will be visible to all users.'), - ); - - $form['page_vis_settings'] = array( - '#type' => 'fieldset', - '#title' => t('Page specific visibility settings'), - '#collapsible' => TRUE, - ); - $access = user_access('use PHP for block visibility'); - - if ($edit['visibility'] == 2 && !$access) { - $form['page_vis_settings'] = array(); - $form['page_vis_settings']['visibility'] = array('#type' => 'value', '#value' => 2); - $form['page_vis_settings']['pages'] = array('#type' => 'value', '#value' => $edit['pages']); - } - else { - $options = array(t('Show on every page except the listed pages.'), t('Show on only the listed pages.')); - $description = t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '')); - - if ($access) { - $options[] = t('Show if the following PHP code returns TRUE (PHP-mode, experts only).'); - $description .= ' '. t('If the PHP-mode is chosen, enter PHP code between %php. Note that executing incorrect PHP-code can break your Drupal site.', array('%php' => '')); - } - $form['page_vis_settings']['visibility'] = array( - '#type' => 'radios', - '#title' => t('Show block on specific pages'), - '#options' => $options, - '#default_value' => $edit['visibility'], - ); - $form['page_vis_settings']['pages'] = array( - '#type' => 'textarea', - '#title' => t('Pages'), - '#default_value' => $edit['pages'], - '#description' => $description, - ); - } - - $form['submit'] = array( - '#type' => 'submit', - '#value' => t('Save block'), - ); - - return $form; -} - -function block_admin_configure_validate($form_id, $form_values) { - if ($form_values['module'] == 'block') { - if (empty($form_values['info']) || db_num_rows(db_query("SELECT bid FROM {boxes} WHERE bid != %d AND info = '%s'", $form_values['delta'], $form_values['info']))) { - form_set_error('info', t('Please ensure that each block description is unique.')); - } - } -} - -function block_admin_configure_submit($form_id, $form_values) { - if (!form_get_errors()) { - db_query("UPDATE {blocks} SET visibility = %d, pages = '%s', custom = %d, title = '%s' WHERE module = '%s' AND delta = '%s'", $form_values['visibility'], trim($form_values['pages']), $form_values['custom'], $form_values['title'], $form_values['module'], $form_values['delta']); - db_query("DELETE FROM {blocks_roles} WHERE module = '%s' AND delta = '%s'", $form_values['module'], $form_values['delta']); - foreach (array_filter($form_values['roles']) as $rid) { - db_query("INSERT INTO {blocks_roles} (rid, module, delta) VALUES (%d, '%s', '%s')", $rid, $form_values['module'], $form_values['delta']); - } - module_invoke($form_values['module'], 'block', 'save', $form_values['delta'], $form_values); - drupal_set_message(t('The block configuration has been saved.')); - cache_clear_all(); - return 'admin/build/block'; - } -} - -/** - * Menu callback: display the custom block addition form. - */ -function block_add_block_form() { - return block_admin_configure('block', NULL); -} - -function block_add_block_form_validate($form_id, $form_values) { - if (empty($form_values['info']) || db_num_rows(db_query("SELECT info FROM {boxes} WHERE info = '%s'", $form_values['info']))) { - form_set_error('info', t('Please ensure that each block description is unique.')); - } -} - -/** - * Save the new custom block. - */ -function block_add_block_form_submit($form_id, $form_values) { - $delta = db_next_id('{boxes}_bid'); - - foreach (list_themes() as $key => $theme) { - if ($theme->status) { - db_query("INSERT INTO {blocks} (visibility, pages, custom, title, module, theme, status, weight, delta) VALUES(%d, '%s', %d, '%s', '%s', '%s', %d, %d, %d)", $form_values['visibility'], trim($form_values['pages']), $form_values['custom'], $form_values['title'], $form_values['module'], $theme->name, 0, 0, $delta); - } - } - - foreach (array_filter($form_values['roles']) as $rid) { - db_query("INSERT INTO {blocks_roles} (rid, module, delta) VALUES (%d, '%s', '%s')", $rid, $form_values['module'], $delta); - } - - db_query("INSERT INTO {boxes} (bid, body, info, format) VALUES (%d, '%s', '%s', %d)", $delta, $form_values['body'], $form_values['info'], $form_values['format']); - - drupal_set_message(t('The block has been created.')); - cache_clear_all(); - - return 'admin/build/block'; -} - -/** - * Menu callback; confirm deletion of custom blocks. - */ -function block_box_delete($bid = 0) { - $box = block_box_get($bid); - $form['info'] = array('#type' => 'hidden', '#value' => $box['info'] ? $box['info'] : $box['title']); - $form['bid'] = array('#type' => 'hidden', '#value' => $bid); - - return confirm_form($form, t('Are you sure you want to delete the block %name?', array('%name' => $box['info'])), 'admin/build/block', '', t('Delete'), t('Cancel')); -} - -/** - * Deletion of custom blocks. - */ -function block_box_delete_submit($form_id, $form_values) { - db_query('DELETE FROM {boxes} WHERE bid = %d', $form_values['bid']); - db_query("DELETE FROM {blocks} WHERE module = 'block' AND delta = %d", $form_values['bid']); - drupal_set_message(t('The block %name has been removed.', array('%name' => $form_values['info']))); - cache_clear_all(); - return 'admin/build/block'; -}; - -/** - * Define the custom block form. - */ -function block_box_form($edit = array()) { - $edit += array( - 'info' => '', - 'body' => '', - ); - $form['info'] = array( - '#type' => 'textfield', - '#title' => t('Block description'), - '#default_value' => $edit['info'], - '#maxlength' => 64, - '#description' => t('A brief description of your block. Used on the block overview page.', array('@overview' => url('admin/build/block'))), - '#required' => TRUE, - '#weight' => -19, - ); - $form['body_field']['#weight'] = -17; - $form['body_field']['body'] = array( - '#type' => 'textarea', - '#title' => t('Block body'), - '#default_value' => $edit['body'], - '#rows' => 15, - '#description' => t('The content of the block as shown to the user.'), - '#weight' => -17, - ); - if (!isset($edit['format'])) { - $edit['format'] = FILTER_FORMAT_DEFAULT; - } - $form['body_field']['format'] = filter_form($edit['format'], -16); - - return $form; -} - -function block_box_save($edit, $delta) { - if (!filter_access($edit['format'])) { - $edit['format'] = FILTER_FORMAT_DEFAULT; - } - - db_query("UPDATE {boxes} SET body = '%s', info = '%s', format = %d WHERE bid = %d", $edit['body'], $edit['info'], $edit['format'], $delta); - - return TRUE; -} - -/** - * Implementation of hook_user(). - * - * Allow users to decide which custom blocks to display when they visit - * the site. - */ -function block_user($type, $edit, &$user, $category = NULL) { - global $user; - switch ($type) { - case 'form': - if ($category == 'account') { - $result = db_query("SELECT DISTINCT b.* FROM {blocks} b LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta WHERE b.status = 1 AND b.custom != 0 AND (r.rid IN (%s) OR r.rid IS NULL) ORDER BY b.weight, b.module", implode(',', array_keys($user->roles))); - $form['block'] = array('#type' => 'fieldset', '#title' => t('Block configuration'), '#weight' => 3, '#collapsible' => TRUE, '#tree' => TRUE); - while ($block = db_fetch_object($result)) { - $data = module_invoke($block->module, 'block', 'list'); - if ($data[$block->delta]['info']) { - $return = TRUE; - $form['block'][$block->module][$block->delta] = array('#type' => 'checkbox', '#title' => check_plain($data[$block->delta]['info']), '#default_value' => isset($user->block[$block->module][$block->delta]) ? $user->block[$block->module][$block->delta] : ($block->custom == 1)); - } - } - - if (!empty($return)) { - return $form; - } - } - - break; - case 'validate': - if (empty($edit['block'])) { - $edit['block'] = array(); - } - return $edit; - } -} - -/** * Return all blocks in the specified region for the current user. * * @param $region Index: modules/block/block.pages.inc =================================================================== RCS file: modules/block/block.pages.inc diff -N modules/block/block.pages.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/block/block.pages.inc 30 Apr 2007 05:37:52 -0000 @@ -0,0 +1,417 @@ + '<'. t('none') .'>') + system_region_list($theme_key); + + // Build form tree + $form['#action'] = arg(3) ? url('admin/build/block/list/'. $theme_key) : url('admin/build/block'); + $form['#tree'] = TRUE; + foreach ($blocks as $i => $block) { + $form[$i]['module'] = array('#type' => 'value', '#value' => $block['module']); + $form[$i]['delta'] = array('#type' => 'value', '#value' => $block['delta']); + $form[$i]['info'] = array('#value' => check_plain($block['info'])); + $form[$i]['theme'] = array('#type' => 'hidden', '#value' => $theme_key); + $form[$i]['weight'] = array('#type' => 'weight', '#default_value' => $block['weight']); + $form[$i]['region'] = array('#type' => 'select', + '#default_value' => $block['status'] ? (isset($block['region']) ? $block['region'] : system_default_region($theme_key)) : BLOCK_REGION_NONE, + '#options' => $block_regions, + ); + + if ($throttle) { + $form[$i]['throttle'] = array('#type' => 'checkbox', '#default_value' => isset($block['throttle']) ? $block['throttle'] : FALSE); + } + $form[$i]['configure'] = array('#value' => l(t('configure'), 'admin/build/block/configure/'. $block['module'] .'/'. $block['delta'])); + if ($block['module'] == 'block') { + $form[$i]['delete'] = array('#value' => l(t('delete'), 'admin/build/block/delete/'. $block['delta'])); + } + } + $form['submit'] = array('#type' => 'submit', '#value' => t('Save blocks')); + + return $form; +} + +/** + * Helper function for sorting blocks on admin/build/block. + * + * Active blocks are sorted by region, then by weight. + * Disabled blocks are sorted by name. + */ +function _block_compare($a, $b) { + $status = $b['status'] - $a['status']; + // Separate enabled from disabled. + if ($status) { + return $status; + } + // Enabled blocks + if ($a['status']) { + $place = strcmp($a['region'], $b['region']); + return $place ? $place : ($a['weight'] - $b['weight']); + } + // Disabled blocks + else { + return strcmp($a['info'], $b['info']); + } +} + +/** + * Process main block administration form submission. + */ +function block_admin_display_submit($form_id, $form_values) { + foreach ($form_values as $block) { + $block['status'] = $block['region'] != BLOCK_REGION_NONE; + $block['region'] = $block['status'] ? $block['region'] : ''; + db_query("UPDATE {blocks} SET status = %d, weight = %d, region = '%s', throttle = %d WHERE module = '%s' AND delta = '%s' AND theme = '%s'", $block['status'], $block['weight'], $block['region'], $block['throttle'], $block['module'], $block['delta'], $block['theme']); + } + drupal_set_message(t('The block settings have been updated.')); + cache_clear_all(); +} + +/** + * Theme main block administration form submission. + * + * Note: the blocks are already sorted in the right order, + * grouped by status, region and weight. + */ +function theme_block_admin_display($form) { + global $theme_key; + + $throttle = module_exists('throttle'); + $block_regions = system_region_list($theme_key); + + // Highlight regions on page to provide visual reference. + foreach ($block_regions as $key => $value) { + drupal_set_content($key, '
'. $value .'
'); + } + + // Build rows + $rows = array(); + $last_region = ''; + $last_status = 1; + foreach (element_children($form) as $i) { + $block = &$form[$i]; + // Only take form elements that are blocks. + if (isset($block['info'])) { + // Fetch values + $region = $block['region']['#default_value']; + $status = $region != BLOCK_REGION_NONE; + + // Output region header + if ($status && $region != $last_region) { + $region_title = t('@region', array('@region' => drupal_ucfirst($block_regions[$region]))); + $rows[] = array(array('data' => $region_title, 'class' => 'region', 'colspan' => ($throttle ? 7 : 6))); + $last_region = $region; + } + // Output disabled header + elseif ($status != $last_status) { + $rows[] = array(array('data' => t('Disabled'), 'class' => 'region', 'colspan' => ($throttle ? 7 : 6))); + $last_status = $status; + } + + // Generate block row + $row = array( + array('data' => drupal_render($block['info']), 'class' => 'block'), + drupal_render($block['region']) . drupal_render($block['theme']), + drupal_render($block['weight']), + ); + if ($throttle) { + $row[] = drupal_render($block['throttle']); + } + $row[] = drupal_render($block['configure']); + $row[] = !empty($block['delete']) ? drupal_render($block['delete']) : ''; + $rows[] = $row; + } + } + + // Finish table + $header = array(t('Block'), t('Region'), t('Weight')); + if ($throttle) { + $header[] = t('Throttle'); + } + $header[] = array('data' => t('Operations'), 'colspan' => 2); + + $output = theme('table', $header, $rows, array('id' => 'blocks')); + + $output .= drupal_render($form); + + return $output; +} + +function block_box_get($bid) { + return db_fetch_array(db_query("SELECT bx.*, title FROM {boxes} bx INNER JOIN {blocks} bl ON bx.bid = bl.delta WHERE module = 'block' AND bid = %d", $bid)); +} + +/** + * Menu callback; displays the block configuration form. + */ +function block_admin_configure($module = NULL, $delta = 0) { + + $form['module'] = array('#type' => 'value', '#value' => $module); + $form['delta'] = array('#type' => 'value', '#value' => $delta); + + $edit = db_fetch_array(db_query("SELECT pages, visibility, custom, title FROM {blocks} WHERE module = '%s' AND delta = '%s'", $module, $delta)); + + $form['block_settings'] = array( + '#type' => 'fieldset', + '#title' => t('Block specific settings'), + '#collapsible' => TRUE, + ); + $form['block_settings']['title'] = array( + '#type' => 'textfield', + '#title' => t('Block title'), + '#maxlength' => 64, + '#description' => $module == 'block' ? t('The title of the block as shown to the user.') : t('Override the default title for the block. Use <none> to display no title, or leave blank to use the default block title.'), + '#default_value' => $edit['title'], + '#weight' => -18, + ); + + + // Module-specific block configurations. + if ($settings = module_invoke($module, 'block', 'configure', $delta)) { + foreach ($settings as $k => $v) { + $form['block_settings'][$k] = $v; + } + } + + // Get the block subject for the page title. + $info = module_invoke($module, 'block', 'list'); + if (isset($info[$delta])) { + drupal_set_title(t("'%name' block", array('%name' => $info[$delta]['info']))); + } + + // Standard block configurations. + $form['user_vis_settings'] = array( + '#type' => 'fieldset', + '#title' => t('User specific visibility settings'), + '#collapsible' => TRUE, + ); + $form['user_vis_settings']['custom'] = array( + '#type' => 'radios', + '#title' => t('Custom visibility settings'), + '#options' => array( + t('Users cannot control whether or not they see this block.'), + t('Show this block by default, but let individual users hide it.'), + t('Hide this block by default but let individual users show it.') + ), + '#description' => t('Allow individual users to customize the visibility of this block in their account settings.'), + '#default_value' => $edit['custom'], + ); + + // Role-based visibility settings + $default_role_options = array(); + $result = db_query("SELECT rid FROM {blocks_roles} WHERE module = '%s' AND delta = '%s'", $module, $delta); + while ($role = db_fetch_object($result)) { + $default_role_options[] = $role->rid; + } + $result = db_query('SELECT rid, name FROM {role} ORDER BY name'); + $role_options = array(); + while ($role = db_fetch_object($result)) { + $role_options[$role->rid] = $role->name; + } + $form['role_vis_settings'] = array( + '#type' => 'fieldset', + '#title' => t('Role specific visibility settings'), + '#collapsible' => TRUE, + ); + $form['role_vis_settings']['roles'] = array( + '#type' => 'checkboxes', + '#title' => t('Show block for specific roles'), + '#default_value' => $default_role_options, + '#options' => $role_options, + '#description' => t('Show this block only for the selected role(s). If you select no roles, the block will be visible to all users.'), + ); + + $form['page_vis_settings'] = array( + '#type' => 'fieldset', + '#title' => t('Page specific visibility settings'), + '#collapsible' => TRUE, + ); + $access = user_access('use PHP for block visibility'); + + if ($edit['visibility'] == 2 && !$access) { + $form['page_vis_settings'] = array(); + $form['page_vis_settings']['visibility'] = array('#type' => 'value', '#value' => 2); + $form['page_vis_settings']['pages'] = array('#type' => 'value', '#value' => $edit['pages']); + } + else { + $options = array(t('Show on every page except the listed pages.'), t('Show on only the listed pages.')); + $description = t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '')); + + if ($access) { + $options[] = t('Show if the following PHP code returns TRUE (PHP-mode, experts only).'); + $description .= ' '. t('If the PHP-mode is chosen, enter PHP code between %php. Note that executing incorrect PHP-code can break your Drupal site.', array('%php' => '')); + } + $form['page_vis_settings']['visibility'] = array( + '#type' => 'radios', + '#title' => t('Show block on specific pages'), + '#options' => $options, + '#default_value' => $edit['visibility'], + ); + $form['page_vis_settings']['pages'] = array( + '#type' => 'textarea', + '#title' => t('Pages'), + '#default_value' => $edit['pages'], + '#description' => $description, + ); + } + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Save block'), + ); + + return $form; +} + +function block_admin_configure_validate($form_id, $form_values) { + if ($form_values['module'] == 'block') { + if (empty($form_values['info']) || db_num_rows(db_query("SELECT bid FROM {boxes} WHERE bid != %d AND info = '%s'", $form_values['delta'], $form_values['info']))) { + form_set_error('info', t('Please ensure that each block description is unique.')); + } + } +} + +function block_admin_configure_submit($form_id, $form_values) { + if (!form_get_errors()) { + db_query("UPDATE {blocks} SET visibility = %d, pages = '%s', custom = %d, title = '%s' WHERE module = '%s' AND delta = '%s'", $form_values['visibility'], trim($form_values['pages']), $form_values['custom'], $form_values['title'], $form_values['module'], $form_values['delta']); + db_query("DELETE FROM {blocks_roles} WHERE module = '%s' AND delta = '%s'", $form_values['module'], $form_values['delta']); + foreach (array_filter($form_values['roles']) as $rid) { + db_query("INSERT INTO {blocks_roles} (rid, module, delta) VALUES (%d, '%s', '%s')", $rid, $form_values['module'], $form_values['delta']); + } + module_invoke($form_values['module'], 'block', 'save', $form_values['delta'], $form_values); + drupal_set_message(t('The block configuration has been saved.')); + cache_clear_all(); + return 'admin/build/block'; + } +} + +/** + * Menu callback: display the custom block addition form. + */ +function block_add_block_form() { + return block_admin_configure('block', NULL); +} + +function block_add_block_form_validate($form_id, $form_values) { + if (empty($form_values['info']) || db_num_rows(db_query("SELECT info FROM {boxes} WHERE info = '%s'", $form_values['info']))) { + form_set_error('info', t('Please ensure that each block description is unique.')); + } +} + +/** + * Save the new custom block. + */ +function block_add_block_form_submit($form_id, $form_values) { + $delta = db_next_id('{boxes}_bid'); + + foreach (list_themes() as $key => $theme) { + if ($theme->status) { + db_query("INSERT INTO {blocks} (visibility, pages, custom, title, module, theme, status, weight, delta) VALUES(%d, '%s', %d, '%s', '%s', '%s', %d, %d, %d)", $form_values['visibility'], trim($form_values['pages']), $form_values['custom'], $form_values['title'], $form_values['module'], $theme->name, 0, 0, $delta); + } + } + + foreach (array_filter($form_values['roles']) as $rid) { + db_query("INSERT INTO {blocks_roles} (rid, module, delta) VALUES (%d, '%s', '%s')", $rid, $form_values['module'], $delta); + } + + db_query("INSERT INTO {boxes} (bid, body, info, format) VALUES (%d, '%s', '%s', %d)", $delta, $form_values['body'], $form_values['info'], $form_values['format']); + + drupal_set_message(t('The block has been created.')); + cache_clear_all(); + + return 'admin/build/block'; +} + +/** + * Menu callback; confirm deletion of custom blocks. + */ +function block_box_delete($bid = 0) { + $box = block_box_get($bid); + $form['info'] = array('#type' => 'hidden', '#value' => $box['info'] ? $box['info'] : $box['title']); + $form['bid'] = array('#type' => 'hidden', '#value' => $bid); + + return confirm_form($form, t('Are you sure you want to delete the block %name?', array('%name' => $box['info'])), 'admin/build/block', '', t('Delete'), t('Cancel')); +} + +/** + * Deletion of custom blocks. + */ +function block_box_delete_submit($form_id, $form_values) { + db_query('DELETE FROM {boxes} WHERE bid = %d', $form_values['bid']); + db_query("DELETE FROM {blocks} WHERE module = 'block' AND delta = %d", $form_values['bid']); + drupal_set_message(t('The block %name has been removed.', array('%name' => $form_values['info']))); + cache_clear_all(); + return 'admin/build/block'; +}; + +/** + * Define the custom block form. + */ +function block_box_form($edit = array()) { + $edit += array( + 'info' => '', + 'body' => '', + ); + $form['info'] = array( + '#type' => 'textfield', + '#title' => t('Block description'), + '#default_value' => $edit['info'], + '#maxlength' => 64, + '#description' => t('A brief description of your block. Used on the block overview page.', array('@overview' => url('admin/build/block'))), + '#required' => TRUE, + '#weight' => -19, + ); + $form['body_field']['#weight'] = -17; + $form['body_field']['body'] = array( + '#type' => 'textarea', + '#title' => t('Block body'), + '#default_value' => $edit['body'], + '#rows' => 15, + '#description' => t('The content of the block as shown to the user.'), + '#weight' => -17, + ); + if (!isset($edit['format'])) { + $edit['format'] = FILTER_FORMAT_DEFAULT; + } + $form['body_field']['format'] = filter_form($edit['format'], -16); + + return $form; +} + +function block_box_save($edit, $delta) { + if (!filter_access($edit['format'])) { + $edit['format'] = FILTER_FORMAT_DEFAULT; + } + + db_query("UPDATE {boxes} SET body = '%s', info = '%s', format = %d WHERE bid = %d", $edit['body'], $edit['info'], $edit['format'], $delta); + + return TRUE; +} Index: modules/comment/comment.module =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v retrieving revision 1.540 diff -u -p -r1.540 comment.module --- modules/comment/comment.module 27 Apr 2007 07:42:54 -0000 1.540 +++ modules/comment/comment.module 30 Apr 2007 05:37:52 -0000 @@ -201,6 +201,7 @@ function comment_menu() { 'description' => t('List and edit site comments and the comment moderation queue.'), 'page callback' => 'comment_admin', 'access arguments' => array('administer comments'), + 'includes' => drupal_get_path('module', 'comment') . '/comment.pages.inc', ); // Tabs: @@ -220,6 +221,7 @@ function comment_menu() { 'title' => t('Approval queue'), 'page arguments' => array('approval'), 'type' => MENU_LOCAL_TASK, + 'includes' => drupal_get_path('module', 'comment') . '/comment.pages.inc', ); $items['admin/content/comment/settings'] = array( @@ -228,6 +230,7 @@ function comment_menu() { 'page arguments' => array('comment_admin_settings'), 'weight' => 10, 'type' => MENU_LOCAL_TASK, + 'includes' => drupal_get_path('module', 'comment') . '/comment.pages.inc', ); $items['comment/delete'] = array( @@ -235,6 +238,7 @@ function comment_menu() { 'page callback' => 'comment_delete', 'access arguments' => array('administer comments'), 'type' => MENU_CALLBACK, + 'includes' => drupal_get_path('module', 'comment') . '/comment.pages.inc', ); $items['comment/edit'] = array( @@ -242,6 +246,7 @@ function comment_menu() { 'page callback' => 'comment_edit', 'access arguments' => array('post comments'), 'type' => MENU_CALLBACK, + 'includes' => drupal_get_path('module', 'comment') . '/comment.pages.inc', ); $items['comment/reply/%node'] = array( 'title' => t('Reply to comment'), @@ -250,6 +255,7 @@ function comment_menu() { 'access callback' => 'node_access', 'access arguments' => array('view', 2), 'type' => MENU_CALLBACK, + 'includes' => drupal_get_path('module', 'comment') . '/comment.pages.inc', ); $items['node/%node/%'] = array( 'title' => t('View'), @@ -258,6 +264,7 @@ function comment_menu() { 'access callback' => '_comment_view_access', 'access arguments' => array(1, 2), 'type' => MENU_CALLBACK, + 'includes' => drupal_get_path('module', 'comment') . '/comment.pages.inc', ); return $items; @@ -287,6 +294,7 @@ function comment_block($op = 'list', $de } } + /** * Find a number of recent comments. This is done in two steps. * 1. Find the n (specified by $number) nodes that have the most recent @@ -511,1509 +519,6 @@ function comment_user($type, $edit, &$us } /** - * Menu callback; presents the comment settings page. - */ -function comment_admin_settings() { - $form['viewing_options'] = array( - '#type' => 'fieldset', - '#title' => t('Viewing options'), - '#collapsible' => TRUE, - ); - - $form['viewing_options']['comment_default_mode'] = array( - '#type' => 'radios', - '#title' => t('Default display mode'), - '#default_value' => variable_get('comment_default_mode', COMMENT_MODE_THREADED_EXPANDED), - '#options' => _comment_get_modes(), - '#description' => t('The default view for comments. Expanded views display the body of the comment. Threaded views keep replies together.'), - ); - - $form['viewing_options']['comment_default_order'] = array( - '#type' => 'radios', - '#title' => t('Default display order'), - '#default_value' => variable_get('comment_default_order', COMMENT_ORDER_NEWEST_FIRST), - '#options' => _comment_get_orders(), - '#description' => t('The default sorting for new users and anonymous users while viewing comments. These users may change their view using the comment control panel. For registered users, this change is remembered as a persistent user preference.'), - ); - - $form['viewing_options']['comment_default_per_page'] = array( - '#type' => 'select', - '#title' => t('Default comments per page'), - '#default_value' => variable_get('comment_default_per_page', 50), - '#options' => _comment_per_page(), - '#description' => t('Default number of comments for each page: more comments are distributed in several pages.'), - ); - - $form['viewing_options']['comment_controls'] = array( - '#type' => 'radios', - '#title' => t('Comment controls'), - '#default_value' => variable_get('comment_controls', COMMENT_CONTROLS_HIDDEN), - '#options' => array( - t('Display above the comments'), - t('Display below the comments'), - t('Display above and below the comments'), - t('Do not display')), - '#description' => t('Position of the comment controls box. The comment controls let the user change the default display mode and display order of comments.'), - ); - - $form['posting_settings'] = array( - '#type' => 'fieldset', - '#title' => t('Posting settings'), - '#collapsible' => TRUE, - ); - - $form['posting_settings']['comment_anonymous'] = array( - '#type' => 'radios', - '#title' => t('Anonymous commenting'), - '#default_value' => variable_get('comment_anonymous', COMMENT_ANONYMOUS_MAYNOT_CONTACT), - '#options' => array( - COMMENT_ANONYMOUS_MAYNOT_CONTACT => t('Anonymous posters may not enter their contact information'), - COMMENT_ANONYMOUS_MAY_CONTACT => t('Anonymous posters may leave their contact information'), - COMMENT_ANONYMOUS_MUST_CONTACT => t('Anonymous posters must leave their contact information')), - '#description' => t('This option is enabled when anonymous users have permission to post comments on the permissions page.', array('@url' => url('admin/user/access', array('fragment' => 'module-comment')))), - ); - if (!user_access('post comments', user_load(array('uid' => 0)))) { - $form['posting_settings']['comment_anonymous']['#disabled'] = TRUE; - } - - $form['posting_settings']['comment_subject_field'] = array( - '#type' => 'radios', - '#title' => t('Comment subject field'), - '#default_value' => variable_get('comment_subject_field', 1), - '#options' => array(t('Disabled'), t('Enabled')), - '#description' => t('Can users provide a unique subject for their comments?'), - ); - - $form['posting_settings']['comment_preview'] = array( - '#type' => 'radios', - '#title' => t('Preview comment'), - '#default_value' => variable_get('comment_preview', COMMENT_PREVIEW_REQUIRED), - '#options' => array(t('Optional'), t('Required')), - ); - - $form['posting_settings']['comment_form_location'] = array( - '#type' => 'radios', - '#title' => t('Location of comment submission form'), - '#default_value' => variable_get('comment_form_location', COMMENT_FORM_SEPARATE_PAGE), - '#options' => array(t('Display on separate page'), t('Display below post or comments')), - ); - - return system_settings_form($form); -} - -/** - * This is *not* a hook_access() implementation. This function is called - * to determine whether the current user has access to a particular comment. - * - * Authenticated users can edit their comments as long they have not been - * replied to. This prevents people from changing or revising their - * statements based on the replies to their posts. - */ -function comment_access($op, $comment) { - global $user; - - if ($op == 'edit') { - return ($user->uid && $user->uid == $comment->uid && comment_num_replies($comment->cid) == 0) || user_access('administer comments'); - } -} - -function comment_node_url() { - return arg(0) .'/'. arg(1); -} - -function comment_edit($cid) { - global $user; - - $comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d', $cid)); - $comment = drupal_unpack($comment); - $comment->name = $comment->uid ? $comment->registered_name : $comment->name; - if (comment_access('edit', $comment)) { - return comment_form_box((array)$comment); - } - else { - drupal_access_denied(); - } -} - -/** - * This function is responsible for generating a comment reply form. - * There are several cases that have to be handled, including: - * - replies to comments - * - replies to nodes - * - attempts to reply to nodes that can no longer accept comments - * - respecting access permissions ('access comments', 'post comments', etc.) - * - * The node or comment that is being replied to must appear above the comment - * form to provide the user context while authoring the comment. - * - * @param $node - * Every comment belongs to a node. This is that node. - * @param $pid - * Some comments are replies to other comments. In those cases, $pid is the parent - * comment's cid. - * - * @return $output - * The rendered parent node or comment plus the new comment form. - */ -function comment_reply($node, $pid = NULL) { - // Set the breadcrumb trail. - menu_set_location(array(array('path' => "node/$node->nid", 'title' => $node->title), array('path' => "comment/reply/$node->nid"))); - - $op = isset($_POST['op']) ? $_POST['op'] : ''; - - $output = ''; - - if (user_access('access comments')) { - // The user is previewing a comment prior to submitting it. - if ($op == t('Preview comment')) { - if (user_access('post comments')) { - $output .= comment_form_box(array('pid' => $pid, 'nid' => $node->nid), NULL); - } - else { - drupal_set_message(t('You are not authorized to post comments.'), 'error'); - drupal_goto("node/$node->nid"); - } - } - else { - // $pid indicates that this is a reply to a comment. - if ($pid) { - // load the comment whose cid = $pid - if ($comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.signature, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = %d', $pid, COMMENT_PUBLISHED))) { - // If that comment exists, make sure that the current comment and the parent comment both - // belong to the same parent node. - if ($comment->nid != $node->nid) { - // Attempting to reply to a comment not belonging to the current nid. - drupal_set_message(t('The comment you are replying to does not exist.'), 'error'); - drupal_goto("node/$node->nid"); - } - // Display the parent comment - $comment = drupal_unpack($comment); - $comment->name = $comment->uid ? $comment->registered_name : $comment->name; - $output .= theme('comment_view', $comment); - } - else { - drupal_set_message(t('The comment you are replying to does not exist.'), 'error'); - drupal_goto("node/$node->nid"); - } - } - // This is the case where the comment is in response to a node. Display the node. - else if (user_access('access content')) { - $output .= node_view($node); - } - - // Should we show the reply box? - if (node_comment_mode($node->nid) != COMMENT_NODE_READ_WRITE) { - drupal_set_message(t("This discussion is closed: you can't post new comments."), 'error'); - drupal_goto("node/$node->nid"); - } - else if (user_access('post comments')) { - $output .= comment_form_box(array('pid' => $pid, 'nid' => $node->nid), t('Reply')); - } - else { - drupal_set_message(t('You are not authorized to post comments.'), 'error'); - drupal_goto("node/$node->nid"); - } - } - } - else { - drupal_set_message(t('You are not authorized to view comments.'), 'error'); - drupal_goto("node/$node->nid"); - } - - return $output; -} - -/** - * Accepts a submission of new or changed comment content. - * - * @param $edit - * A comment array. - * - * @return - * If the comment is successfully saved the comment ID is returned. If the comment - * is not saved, FALSE is returned. - */ -function comment_save($edit) { - global $user; - if (user_access('post comments') && (user_access('administer comments') || node_comment_mode($edit['nid']) == COMMENT_NODE_READ_WRITE)) { - if (!form_get_errors()) { - if ($edit['cid']) { - // Update the comment in the database. - db_query("UPDATE {comments} SET status = %d, timestamp = %d, subject = '%s', comment = '%s', format = %d, uid = %d, name = '%s', mail = '%s', homepage = '%s' WHERE cid = %d", $edit['status'], $edit['timestamp'], $edit['subject'], $edit['comment'], $edit['format'], $edit['uid'], $edit['name'], $edit['mail'], $edit['homepage'], $edit['cid']); - - _comment_update_node_statistics($edit['nid']); - - // Allow modules to respond to the updating of a comment. - comment_invoke_comment($edit, 'update'); - - // Add an entry to the watchdog log. - watchdog('content', 'Comment: updated %subject.', array('%subject' => $edit['subject']), WATCHDOG_NOTICE, l(t('view'), 'node/'. $edit['nid'], array('fragment' => 'comment-'. $edit['cid']))); - } - else { - // Check for duplicate comments. Note that we have to use the - // validated/filtered data to perform such check. - $duplicate = db_result(db_query("SELECT COUNT(cid) FROM {comments} WHERE pid = %d AND nid = %d AND subject = '%s' AND comment = '%s'", $edit['pid'], $edit['nid'], $edit['subject'], $edit['comment']), 0); - if ($duplicate != 0) { - watchdog('content', 'Comment: duplicate %subject.', array('%subject' => $edit['subject']), WATCHDOG_WARNING); - } - - // Add the comment to database. - $status = user_access('post comments without approval') ? COMMENT_PUBLISHED : COMMENT_NOT_PUBLISHED; - $roles = variable_get('comment_roles', array()); - $score = 0; - - foreach (array_intersect(array_keys($roles), array_keys($user->roles)) as $rid) { - $score = max($roles[$rid], $score); - } - - $users = serialize(array(0 => $score)); - - // Here we are building the thread field. See the documentation for - // comment_render(). - if ($edit['pid'] == 0) { - // This is a comment with no parent comment (depth 0): we start - // by retrieving the maximum thread level. - $max = db_result(db_query('SELECT MAX(thread) FROM {comments} WHERE nid = %d', $edit['nid'])); - - // Strip the "/" from the end of the thread. - $max = rtrim($max, '/'); - - // Finally, build the thread field for this new comment. - $thread = int2vancode(vancode2int($max) + 1) .'/'; - } - else { - // This is comment with a parent comment: we increase - // the part of the thread value at the proper depth. - - // Get the parent comment: - $parent = _comment_load($edit['pid']); - - // Strip the "/" from the end of the parent thread. - $parent->thread = (string) rtrim((string) $parent->thread, '/'); - - // Get the max value in _this_ thread. - $max = db_result(db_query("SELECT MAX(thread) FROM {comments} WHERE thread LIKE '%s.%%' AND nid = %d", $parent->thread, $edit['nid'])); - - if ($max == '') { - // First child of this parent. - $thread = $parent->thread .'.'. int2vancode(0) .'/'; - } - else { - // Strip the "/" at the end of the thread. - $max = rtrim($max, '/'); - - // We need to get the value at the correct depth. - $parts = explode('.', $max); - $parent_depth = count(explode('.', $parent->thread)); - $last = $parts[$parent_depth]; - - // Finally, build the thread field for this new comment. - $thread = $parent->thread .'.'. int2vancode(vancode2int($last) + 1) .'/'; - } - } - - $edit['cid'] = db_next_id('{comments}_cid'); - $edit['timestamp'] = time(); - - if ($edit['uid'] === $user->uid) { // '===' because we want to modify anonymous users too - $edit['name'] = $user->name; - } - - $edit += array('mail' => '', 'homepage' => ''); - db_query("INSERT INTO {comments} (cid, nid, pid, uid, subject, comment, format, hostname, timestamp, status, score, users, thread, name, mail, homepage) VALUES (%d, %d, %d, %d, '%s', '%s', %d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s')", $edit['cid'], $edit['nid'], $edit['pid'], $edit['uid'], $edit['subject'], $edit['comment'], $edit['format'], $_SERVER['REMOTE_ADDR'], $edit['timestamp'], $status, $score, $users, $thread, $edit['name'], $edit['mail'], $edit['homepage']); - - _comment_update_node_statistics($edit['nid']); - - // Tell the other modules a new comment has been submitted. - comment_invoke_comment($edit, 'insert'); - - // Add an entry to the watchdog log. - watchdog('content', 'Comment: added %subject.', array('%subject' => $edit['subject']), WATCHDOG_NOTICE, l(t('view'), 'node/'. $edit['nid'], array('fragment' => 'comment-'. $edit['cid']))); - } - - // Clear the cache so an anonymous user can see his comment being added. - cache_clear_all(); - - // Explain the approval queue if necessary, and then - // redirect the user to the node he's commenting on. - if ($status == COMMENT_NOT_PUBLISHED) { - drupal_set_message(t('Your comment has been queued for moderation by site administrators and will be published after approval.')); - } - return $edit['cid']; - } - else { - return FALSE; - } - } - else { - watchdog('content', 'Comment: unauthorized comment submitted or comment submitted to a closed node %subject.', array('%subject' => $edit['subject']), WATCHDOG_WARNING); - drupal_set_message(t('Comment: unauthorized comment submitted or comment submitted to a closed node %subject.', array('%subject' => $edit['subject'])), 'error'); - return FALSE; - } -} - -function comment_links($comment, $return = 1) { - global $user; - - $links = array(); - - // If we are viewing just this comment, we link back to the node. - if ($return) { - $links['comment_parent'] = array( - 'title' => t('parent'), - 'href' => comment_node_url(), - 'fragment' => "comment-$comment->cid" - ); - } - - if (node_comment_mode($comment->nid) == COMMENT_NODE_READ_WRITE) { - if (user_access('administer comments') && user_access('post comments')) { - $links['comment_delete'] = array( - 'title' => t('delete'), - 'href' => "comment/delete/$comment->cid" - ); - $links['comment_edit'] = array( - 'title' => t('edit'), - 'href' => "comment/edit/$comment->cid" - ); - $links['comment_reply'] = array( - 'title' => t('reply'), - 'href' => "comment/reply/$comment->nid/$comment->cid" - ); - } - else if (user_access('post comments')) { - if (comment_access('edit', $comment)) { - $links['comment_edit'] = array( - 'title' => t('edit'), - 'href' => "comment/edit/$comment->cid" - ); - } - $links['comment_reply'] = array( - 'title' => t('reply'), - 'href' => "comment/reply/$comment->nid/$comment->cid" - ); - } - else { - $links['comment_forbidden']['title'] = theme('comment_post_forbidden', $comment->nid); - } - } - - return $links; -} - -/** - * Renders comment(s). - * - * @param $node - * The node which comment(s) needs rendering. - * @param $cid - * Optional, if given, only one comment is rendered. - * - * To display threaded comments in the correct order we keep a 'thread' field - * and order by that value. This field keeps this data in - * a way which is easy to update and convenient to use. - * - * A "thread" value starts at "1". If we add a child (A) to this comment, - * we assign it a "thread" = "1.1". A child of (A) will have "1.1.1". Next - * brother of (A) will get "1.2". Next brother of the parent of (A) will get - * "2" and so on. - * - * First of all note that the thread field stores the depth of the comment: - * depth 0 will be "X", depth 1 "X.X", depth 2 "X.X.X", etc. - * - * Now to get the ordering right, consider this example: - * - * 1 - * 1.1 - * 1.1.1 - * 1.2 - * 2 - * - * If we "ORDER BY thread ASC" we get the above result, and this is the - * natural order sorted by time. However, if we "ORDER BY thread DESC" - * we get: - * - * 2 - * 1.2 - * 1.1.1 - * 1.1 - * 1 - * - * Clearly, this is not a natural way to see a thread, and users will get - * confused. The natural order to show a thread by time desc would be: - * - * 2 - * 1 - * 1.2 - * 1.1 - * 1.1.1 - * - * which is what we already did before the standard pager patch. To achieve - * this we simply add a "/" at the end of each "thread" value. This way out - * thread fields will look like depicted below: - * - * 1/ - * 1.1/ - * 1.1.1/ - * 1.2/ - * 2/ - * - * we add "/" since this char is, in ASCII, higher than every number, so if - * now we "ORDER BY thread DESC" we get the correct order. However this would - * spoil the reverse ordering, "ORDER BY thread ASC" -- here, we do not need - * to consider the trailing "/" so we use a substring only. - */ -function comment_render($node, $cid = 0) { - global $user; - - $output = ''; - - if (user_access('access comments')) { - // Pre-process variables. - $nid = $node->nid; - if (empty($nid)) { - $nid = 0; - } - - $mode = _comment_get_display_setting('mode'); - $order = _comment_get_display_setting('sort'); - $comments_per_page = _comment_get_display_setting('comments_per_page'); - - if ($cid) { - // Single comment view. - $query = 'SELECT c.cid, c.pid, c.nid, c.subject, c.comment, c.format, c.timestamp, c.name, c.mail, c.homepage, u.uid, u.name AS registered_name, u.signature, u.picture, u.data, c.score, c.users, c.status FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d'; - $query_args = array($cid); - if (!user_access('administer comments')) { - $query .= ' AND c.status = %d'; - $query_args[] = COMMENT_PUBLISHED; - } - - $result = db_query($query, $query_args); - - if ($comment = db_fetch_object($result)) { - $comment->name = $comment->uid ? $comment->registered_name : $comment->name; - $links = module_invoke_all('link', 'comment', $comment, 1); - drupal_alter('link', $links, $node); - - $output .= theme('comment_view', $comment, $links); - } - } - else { - // Multiple comment view - $query_count = 'SELECT COUNT(*) FROM {comments} WHERE nid = %d'; - $query = 'SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment, c.format, c.timestamp, c.name, c.mail, c.homepage, u.uid, u.name AS registered_name, u.signature, u.picture, u.data, c.score, c.users, c.thread, c.status FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.nid = %d'; - - $query_args = array($nid); - if (!user_access('administer comments')) { - $query .= ' AND c.status = %d'; - $query_count .= ' AND status = %d'; - $query_args[] = COMMENT_PUBLISHED; - } - - if ($order == COMMENT_ORDER_NEWEST_FIRST) { - if ($mode == COMMENT_MODE_FLAT_COLLAPSED || $mode == COMMENT_MODE_FLAT_EXPANDED) { - $query .= ' ORDER BY c.timestamp DESC'; - } - else { - $query .= ' ORDER BY c.thread DESC'; - } - } - else if ($order == COMMENT_ORDER_OLDEST_FIRST) { - if ($mode == COMMENT_MODE_FLAT_COLLAPSED || $mode == COMMENT_MODE_FLAT_EXPANDED) { - $query .= ' ORDER BY c.timestamp'; - } - else { - - /* - ** See comment above. Analysis learns that this doesn't cost - ** too much. It scales much much better than having the whole - ** comment structure. - */ - - $query .= ' ORDER BY SUBSTRING(c.thread, 1, (LENGTH(c.thread) - 1))'; - } - } - - // Start a form, for use with comment control. - $result = pager_query($query, $comments_per_page, 0, $query_count, $query_args); - if (db_num_rows($result) && (variable_get('comment_controls', COMMENT_CONTROLS_HIDDEN) == COMMENT_CONTROLS_ABOVE || variable_get('comment_controls', COMMENT_CONTROLS_HIDDEN) == COMMENT_CONTROLS_ABOVE_BELOW)) { - $output .= drupal_get_form('comment_controls', $mode, $order, $comments_per_page); - } - - $divs = 0; - $last_depth = 0; - drupal_add_css(drupal_get_path('module', 'comment') .'/comment.css'); - while ($comment = db_fetch_object($result)) { - $comment = drupal_unpack($comment); - $comment->name = $comment->uid ? $comment->registered_name : $comment->name; - $comment->depth = count(explode('.', $comment->thread)) - 1; - - if ($mode == COMMENT_MODE_THREADED_COLLAPSED || $mode == COMMENT_MODE_THREADED_EXPANDED) { - if ($comment->depth > $last_depth) { - $divs++; - $output .= '
'; - $last_depth++; - } - else { - while ($comment->depth < $last_depth) { - $divs--; - $output .= '
'; - $last_depth--; - } - } - } - - if ($mode == COMMENT_MODE_FLAT_COLLAPSED) { - $output .= theme('comment_flat_collapsed', $comment); - } - else if ($mode == COMMENT_MODE_FLAT_EXPANDED) { - $output .= theme('comment_flat_expanded', $comment); - } - else if ($mode == COMMENT_MODE_THREADED_COLLAPSED) { - $output .= theme('comment_thread_collapsed', $comment); - } - else if ($mode == COMMENT_MODE_THREADED_EXPANDED) { - $output .= theme('comment_thread_expanded', $comment); - } - } - for ($i = 0; $i < $divs; $i++) { - $output .= ''; - } - $output .= theme('pager', NULL, $comments_per_page, 0); - - if (db_num_rows($result) && (variable_get('comment_controls', COMMENT_CONTROLS_HIDDEN) == COMMENT_CONTROLS_BELOW || variable_get('comment_controls', COMMENT_CONTROLS_HIDDEN) == COMMENT_CONTROLS_ABOVE_BELOW)) { - $output .= drupal_get_form('comment_controls', $mode, $order, $comments_per_page); - } - } - - // If enabled, show new comment form. - if (user_access('post comments') && node_comment_mode($nid) == COMMENT_NODE_READ_WRITE && (variable_get('comment_form_location', COMMENT_FORM_SEPARATE_PAGE) == COMMENT_FORM_BELOW)) { - $output .= comment_form_box(array('nid' => $nid), t('Post new comment')); - } - - $output = theme('comment_wrapper', $output); - } - - return $output; -} - -/** - * Menu callback; delete a comment. - */ -function comment_delete($cid = NULL) { - $comment = db_fetch_object(db_query('SELECT c.*, u.name AS registered_name, u.uid FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE c.cid = %d', $cid)); - $comment->name = $comment->uid ? $comment->registered_name : $comment->name; - - $output = ''; - - // We'll only delete if the user has confirmed the - // deletion using the form in our else clause below. - if (is_object($comment) && is_numeric($comment->cid) && $_POST['confirm']) { - drupal_set_message(t('The comment and all its replies have been deleted.')); - - // Delete comment and its replies. - _comment_delete_thread($comment); - - _comment_update_node_statistics($comment->nid); - - // Clear the cache so an anonymous user sees that his comment was deleted. - cache_clear_all(); - - drupal_goto("node/$comment->nid"); - } - else if (is_object($comment) && is_numeric($comment->cid)) { - $output = drupal_get_form('comment_confirm_delete', $comment->subject, $comment->nid); - } - else { - drupal_set_message(t('The comment no longer exists.')); - } - - return $output; -} - -function comment_confirm_delete($subject, $nid) { - return confirm_form( - array(), - t('Are you sure you want to delete the comment %title?', array('%title' => $subject)), - 'node/'. $nid, - t('Any replies to this comment will be lost. This action cannot be undone.'), - t('Delete'), - t('Cancel')); -} - -/** - * Comment operations. We offer different update operations depending on - * which comment administration page we're on. - */ -function comment_operations($action = NULL) { - if ($action == 'publish') { - $operations = array( - 'publish' => array(t('Publish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_PUBLISHED .' WHERE cid = %d'), - 'delete' => array(t('Delete the selected comments'), '') - ); - } - else if ($action == 'unpublish') { - $operations = array( - 'unpublish' => array(t('Unpublish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_NOT_PUBLISHED .' WHERE cid = %d'), - 'delete' => array(t('Delete the selected comments'), '') - ); - } - else { - $operations = array( - 'publish' => array(t('Publish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_PUBLISHED .' WHERE cid = %d'), - 'unpublish' => array(t('Unpublish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_NOT_PUBLISHED .' WHERE cid = %d'), - 'delete' => array(t('Delete the selected comments'), '') - ); - } - return $operations; -} - -/** - * Menu callback; present an administrative comment listing. - */ -function comment_admin($type = 'new') { - $edit = $_POST; - - if (isset($edit['operation']) && ($edit['operation'] == 'delete') && $edit['comments']) { - return drupal_get_form('comment_multiple_delete_confirm'); - } - else { - return drupal_get_form('comment_admin_overview', $type, arg(4)); - } -} - -function comment_admin_overview($type = 'new', $arg) { - // build an 'Update options' form - $form['options'] = array( - '#type' => 'fieldset', '#title' => t('Update options'), - '#prefix' => '
', '#suffix' => '
' - ); - $options = array(); - foreach (comment_operations($arg == 'approval' ? 'publish' : 'unpublish') as $key => $value) { - $options[$key] = $value[0]; - } - $form['options']['operation'] = array('#type' => 'select', '#options' => $options, '#default_value' => 'publish'); - $form['options']['submit'] = array('#type' => 'submit', '#value' => t('Update')); - - // load the comments that we want to display - $status = ($type == 'approval') ? COMMENT_NOT_PUBLISHED : COMMENT_PUBLISHED; - $form['header'] = array('#type' => 'value', '#value' => array( - theme('table_select_header_cell'), - array('data' => t('Subject'), 'field' => 'subject'), - array('data' => t('Author'), 'field' => 'name'), - array('data' => t('Time'), 'field' => 'timestamp', 'sort' => 'desc'), - array('data' => t('Operations')) - )); - $result = pager_query('SELECT c.subject, c.nid, c.cid, c.comment, c.timestamp, c.status, c.name, c.homepage, u.name AS registered_name, u.uid FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE c.status = %d'. tablesort_sql($form['header']['#value']), 50, 0, NULL, $status); - - // build a table listing the appropriate comments - $destination = drupal_get_destination(); - while ($comment = db_fetch_object($result)) { - $comments[$comment->cid] = ''; - $comment->name = $comment->uid ? $comment->registered_name : $comment->name; - $form['subject'][$comment->cid] = array('#value' => l($comment->subject, 'node/'. $comment->nid, array('title' => truncate_utf8($comment->comment, 128), 'fragment' => 'comment-'. $comment->cid))); - $form['username'][$comment->cid] = array('#value' => theme('username', $comment)); - $form['timestamp'][$comment->cid] = array('#value' => format_date($comment->timestamp, 'small')); - $form['operations'][$comment->cid] = array('#value' => l(t('edit'), 'comment/edit/'. $comment->cid, array('query' => $destination))); - } - $form['comments'] = array('#type' => 'checkboxes', '#options' => isset($comments) ? $comments: array()); - $form['pager'] = array('#value' => theme('pager', NULL, 50, 0)); - return $form; -} - -/** - * We can't execute any 'Update options' if no comments were selected. - */ -function comment_admin_overview_validate($form_id, $form_values) { - $form_values['comments'] = array_diff($form_values['comments'], array(0)); - if (count($form_values['comments']) == 0) { - form_set_error('', t('Please select one or more comments to perform the update on.')); - drupal_goto('admin/content/comment'); - } -} - -/** - * Execute the chosen 'Update option' on the selected comments, such as - * publishing, unpublishing or deleting. - */ -function comment_admin_overview_submit($form_id, $form_values) { - $operations = comment_operations(); - if ($operations[$form_values['operation']][1]) { - // extract the appropriate database query operation - $query = $operations[$form_values['operation']][1]; - foreach ($form_values['comments'] as $cid => $value) { - if ($value) { - // perform the update action, then refresh node statistics - db_query($query, $cid); - $comment = _comment_load($cid); - _comment_update_node_statistics($comment->nid); - // Allow modules to respond to the updating of a comment. - comment_invoke_comment($comment, $form_values['operation']); - // Add an entry to the watchdog log. - watchdog('content', 'Comment: updated %subject.', array('%subject' => $comment->subject), WATCHDOG_NOTICE, l(t('view'), 'node/'. $comment->nid, array('fragment' => 'comment-'. $comment->cid))); - } - } - cache_clear_all(); - drupal_set_message(t('The update has been performed.')); - drupal_goto('admin/content/comment'); - } -} - -function theme_comment_admin_overview($form) { - $output = drupal_render($form['options']); - if (isset($form['subject']) && is_array($form['subject'])) { - foreach (element_children($form['subject']) as $key) { - $row = array(); - $row[] = drupal_render($form['comments'][$key]); - $row[] = drupal_render($form['subject'][$key]); - $row[] = drupal_render($form['username'][$key]); - $row[] = drupal_render($form['timestamp'][$key]); - $row[] = drupal_render($form['operations'][$key]); - $rows[] = $row; - } - } - else { - $rows[] = array(array('data' => t('No comments available.'), 'colspan' => '6')); - } - - $output .= theme('table', $form['header']['#value'], $rows); - if ($form['pager']['#value']) { - $output .= drupal_render($form['pager']); - } - - $output .= drupal_render($form); - - return $output; -} - -/** - * List the selected comments and verify that the admin really wants to delete - * them. - */ -function comment_multiple_delete_confirm() { - $edit = $_POST; - - $form['comments'] = array('#prefix' => '', '#tree' => TRUE); - // array_filter() returns only elements with actual values - $comment_counter = 0; - foreach (array_filter($edit['comments']) as $cid => $value) { - $comment = _comment_load($cid); - if (is_object($comment) && is_numeric($comment->cid)) { - $subject = db_result(db_query('SELECT subject FROM {comments} WHERE cid = %d', $cid)); - $form['comments'][$cid] = array('#type' => 'hidden', '#value' => $cid, '#prefix' => '
  • ', '#suffix' => check_plain($subject) .'
  • '); - $comment_counter++; - } - } - $form['operation'] = array('#type' => 'hidden', '#value' => 'delete'); - - if (!$comment_counter) { - drupal_set_message(t('There do not appear to be any comments to delete or your selected comment was deleted by another administrator.')); - drupal_goto('admin/content/comment'); - } - else { - return confirm_form($form, - t('Are you sure you want to delete these comments and all their children?'), - 'admin/content/comment', t('This action cannot be undone.'), - t('Delete comments'), t('Cancel')); - } -} - -/** - * Perform the actual comment deletion. - */ -function comment_multiple_delete_confirm_submit($form_id, $form_values) { - if ($form_values['confirm']) { - foreach ($form_values['comments'] as $cid => $value) { - $comment = _comment_load($cid); - _comment_delete_thread($comment); - _comment_update_node_statistics($comment->nid); - } - cache_clear_all(); - drupal_set_message(t('The comments have been deleted.')); - } - drupal_goto('admin/content/comment'); -} - -/** -*** misc functions: helpers, privates, history -**/ - -/** - * Load the entire comment by cid. - */ -function _comment_load($cid) { - return db_fetch_object(db_query('SELECT * FROM {comments} WHERE cid = %d', $cid)); -} - -function comment_num_all($nid) { - static $cache; - - if (!isset($cache[$nid])) { - $cache[$nid] = db_result(db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = %d', $nid)); - } - return $cache[$nid]; -} - -function comment_num_replies($pid) { - static $cache; - - if (!isset($cache[$pid])) { - $cache[$pid] = db_result(db_query('SELECT COUNT(cid) FROM {comments} WHERE pid = %d AND status = %d', $pid, COMMENT_PUBLISHED)); - } - - return $cache[$pid]; -} - -/** - * get number of new comments for current user and specified node - * - * @param $nid node-id to count comments for - * @param $timestamp time to count from (defaults to time of last user access - * to node) - */ -function comment_num_new($nid, $timestamp = 0) { - global $user; - - if ($user->uid) { - // Retrieve the timestamp at which the current user last viewed the - // specified node. - if (!$timestamp) { - $timestamp = node_last_viewed($nid); - } - $timestamp = ($timestamp > NODE_NEW_LIMIT ? $timestamp : NODE_NEW_LIMIT); - - // Use the timestamp to retrieve the number of new comments. - $result = db_result(db_query('SELECT COUNT(c.cid) FROM {node} n INNER JOIN {comments} c ON n.nid = c.nid WHERE n.nid = %d AND timestamp > %d AND c.status = %d', $nid, $timestamp, COMMENT_PUBLISHED)); - - return $result; - } - else { - return 0; - } - -} - -function comment_validate($edit) { - global $user; - - // Invoke other validation handlers - comment_invoke_comment($edit, 'validate'); - - if (isset($edit['date'])) { - // As of PHP 5.1.0, strtotime returns FALSE upon failure instead of -1. - if (strtotime($edit['date']) <= 0) { - form_set_error('date', t('You have to specify a valid date.')); - } - } - if (isset($edit['author']) && !$account = user_load(array('name' => $edit['author']))) { - form_set_error('author', t('You have to specify a valid author.')); - } - - // Check validity of name, mail and homepage (if given) - if (!$user->uid || isset($edit['is_anonymous'])) { - if (variable_get('comment_anonymous', COMMENT_ANONYMOUS_MAYNOT_CONTACT) > COMMENT_ANONYMOUS_MAYNOT_CONTACT) { - if ($edit['name']) { - $taken = db_result(db_query("SELECT COUNT(uid) FROM {users} WHERE LOWER(name) = '%s'", $edit['name']), 0); - - if ($taken != 0) { - form_set_error('name', t('The name you used belongs to a registered user.')); - } - - } - else if (variable_get('comment_anonymous', COMMENT_ANONYMOUS_MAYNOT_CONTACT) == COMMENT_ANONYMOUS_MUST_CONTACT) { - form_set_error('name', t('You have to leave your name.')); - } - - if ($edit['mail']) { - if (!valid_email_address($edit['mail'])) { - form_set_error('mail', t('The e-mail address you specified is not valid.')); - } - } - else if (variable_get('comment_anonymous', COMMENT_ANONYMOUS_MAYNOT_CONTACT) == COMMENT_ANONYMOUS_MUST_CONTACT) { - form_set_error('mail', t('You have to leave an e-mail address.')); - } - - if ($edit['homepage']) { - if (!valid_url($edit['homepage'], TRUE)) { - form_set_error('homepage', t('The URL of your homepage is not valid. Remember that it must be fully qualified, i.e. of the form http://example.com/directory.')); - } - } - } - } - - return $edit; -} - -/* -** Generate the basic commenting form, for appending to a node or display on a separate page. -** This is rendered by theme_comment_form. -*/ - -function comment_form($edit, $title = NULL) { - global $user; - - $op = isset($_POST['op']) ? $_POST['op'] : ''; - - if ($user->uid) { - if (!empty($edit['cid']) && user_access('administer comments')) { - if (!empty($edit['author'])) { - $author = $edit['author']; - } - elseif (!empty($edit['name'])) { - $author = $edit['name']; - } - else { - $author = $edit['registered_name']; - } - - if (!empty($edit['status'])) { - $status = $edit['status']; - } - else { - $status = 0; - } - - if (!empty($edit['date'])) { - $date = $edit['date']; - } - else { - $date = format_date($edit['timestamp'], 'custom', 'Y-m-d H:i O'); - } - - $form['admin'] = array( - '#type' => 'fieldset', - '#title' => t('Administration'), - '#collapsible' => TRUE, - '#collapsed' => TRUE, - '#weight' => -2, - ); - - if ($edit['registered_name'] != '') { - // The comment is by a registered user - $form['admin']['author'] = array( - '#type' => 'textfield', - '#title' => t('Authored by'), - '#size' => 30, - '#maxlength' => 60, - '#autocomplete_path' => 'user/autocomplete', - '#default_value' => $author, - '#weight' => -1, - ); - } - else { - // The comment is by an anonymous user - $form['is_anonymous'] = array( - '#type' => 'value', - '#value' => TRUE, - ); - $form['admin']['name'] = array( - '#type' => 'textfield', - '#title' => t('Authored by'), - '#size' => 30, - '#maxlength' => 60, - '#default_value' => $author, - '#weight' => -1, - ); - $form['admin']['mail'] = array( - '#type' => 'textfield', - '#title' => t('E-mail'), - '#maxlength' => 64, - '#size' => 30, - '#default_value' => $edit['mail'], - '#description' => t('The content of this field is kept private and will not be shown publicly.'), - ); - - $form['admin']['homepage'] = array( - '#type' => 'textfield', - '#title' => t('Homepage'), - '#maxlength' => 255, - '#size' => 30, - '#default_value' => $edit['homepage'], - ); - } - - $form['admin']['date'] = array('#type' => 'textfield', '#parents' => array('date'), '#title' => t('Authored on'), '#size' => 20, '#maxlength' => 25, '#default_value' => $date, '#weight' => -1); - - $form['admin']['status'] = array('#type' => 'radios', '#parents' => array('status'), '#title' => t('Status'), '#default_value' => $status, '#options' => array(t('Published'), t('Not published')), '#weight' => -1); - - } - else { - $form['_author'] = array('#type' => 'item', '#title' => t('Your name'), '#value' => theme('username', $user) - ); - $form['author'] = array('#type' => 'value', '#value' => $user->name); - } - } - else if (variable_get('comment_anonymous', COMMENT_ANONYMOUS_MAYNOT_CONTACT) == COMMENT_ANONYMOUS_MAY_CONTACT) { - $form['name'] = array('#type' => 'textfield', '#title' => t('Your name'), '#maxlength' => 60, '#size' => 30, '#default_value' => $edit['name'] ? $edit['name'] : variable_get('anonymous', t('Anonymous')) - ); - - $form['mail'] = array('#type' => 'textfield', '#title' => t('E-mail'), '#maxlength' => 64, '#size' => 30, '#default_value' => $edit['mail'], '#description' => t('The content of this field is kept private and will not be shown publicly.') - ); - - $form['homepage'] = array('#type' => 'textfield', '#title' => t('Homepage'), '#maxlength' => 255, '#size' => 30, '#default_value' => $edit['homepage']); - } - else if (variable_get('comment_anonymous', COMMENT_ANONYMOUS_MAYNOT_CONTACT) == COMMENT_ANONYMOUS_MUST_CONTACT) { - $form['name'] = array('#type' => 'textfield', '#title' => t('Your name'), '#maxlength' => 60, '#size' => 30, '#default_value' => $edit['name'] ? $edit['name'] : variable_get('anonymous', t('Anonymous')), '#required' => TRUE); - - $form['mail'] = array('#type' => 'textfield', '#title' => t('E-mail'), '#maxlength' => 64, '#size' => 30, '#default_value' => $edit['mail'], '#description' => t('The content of this field is kept private and will not be shown publicly.'), '#required' => TRUE); - - $form['homepage'] = array('#type' => 'textfield', '#title' => t('Homepage'), '#maxlength' => 255, '#size' => 30, '#default_value' => $edit['homepage']); - } - - if (variable_get('comment_subject_field', 1) == 1) { - $form['subject'] = array('#type' => 'textfield', '#title' => t('Subject'), '#maxlength' => 64, '#default_value' => !empty($edit['subject']) ? $edit['subject'] : ''); - } - - if (!empty($edit['comment'])) { - $default = $edit['comment']; - } - else { - $default = ''; - } - - $form['comment_filter']['comment'] = array( - '#type' => 'textarea', - '#title' => t('Comment'), - '#rows' => 15, - '#default_value' => $default, - '#required' => TRUE, - ); - if (!isset($edit['format'])) { - $edit['format'] = FILTER_FORMAT_DEFAULT; - } - $form['comment_filter']['format'] = filter_form($edit['format']); - - $form['cid'] = array('#type' => 'value', '#value' => !empty($edit['cid']) ? $edit['cid'] : NULL); - $form['pid'] = array('#type' => 'value', '#value' => $edit['pid']); - $form['nid'] = array('#type' => 'value', '#value' => $edit['nid']); - $form['uid'] = array('#type' => 'value', '#value' => !empty($edit['uid']) ? $edit['uid'] : NULL); - - $form['preview'] = array('#type' => 'button', '#value' => t('Preview comment'), '#weight' => 19); - $form['#token'] = 'comment'. $edit['nid'] . $edit['pid']; - - // Only show post button if preview is optional or if we are in preview mode. - // We show the post button in preview mode even if there are form errors so that - // optional form elements (e.g., captcha) can be updated in preview mode. - if (!form_get_errors() && ((variable_get('comment_preview', COMMENT_PREVIEW_REQUIRED) == COMMENT_PREVIEW_OPTIONAL) || ($op == t('Preview comment')) || ($op == t('Post comment')))) { - $form['submit'] = array('#type' => 'submit', '#value' => t('Post comment'), '#weight' => 20); - } - - if ($op == t('Preview comment')) { - $form['#after_build'] = array('comment_form_add_preview'); - } - - if (!empty($_REQUEST['destination'])) { - $form['#attributes']['destination'] = $_REQUEST['destination']; - } - - if (empty($edit['cid']) && empty($edit['pid'])) { - $form['#action'] = url('comment/reply/'. $edit['nid']); - } - - // Graft in extra form additions - $form = array_merge($form, comment_invoke_comment($form, 'form')); - return $form; -} - -function comment_form_box($edit, $title = NULL) { - return theme('box', $title, drupal_get_form('comment_form', $edit, $title)); -} - -function comment_form_add_preview($form, $edit) { - global $user; - - drupal_set_title(t('Preview comment')); - - $output = ''; - - // Invoke full validation for the form, to protect against cross site - // request forgeries (CSRF) and setting arbitrary values for fields such as - // the input format. Preview the comment only when form validation does not - // set any errors. - drupal_validate_form($form['form_id']['#value'], $form); - if (!form_get_errors()) { - $comment = (object)_comment_form_submit($edit); - - // Attach the user and time information. - if ($edit['author']) { - $account = user_load(array('name' => $edit['author'])); - } - elseif ($user->uid && !isset($edit['is_anonymous'])) { - $account = $user; - } - if ($account) { - $comment->uid = $account->uid; - $comment->name = check_plain($account->name); - } - else { - $comment->name = variable_get('anonymous', t('Anonymous')); - } - $comment->timestamp = !empty($edit['timestamp']) ? $edit['timestamp'] : time(); - $output .= theme('comment_view', $comment); - } - $form['comment_preview'] = array( - '#value' => $output, - '#weight' => -100, - '#prefix' => '
    ', - '#suffix' => '
    ', - ); - - $output = ''; - - if ($edit['pid']) { - $comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.signature, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = %d', $edit['pid'], COMMENT_PUBLISHED)); - $comment = drupal_unpack($comment); - $comment->name = $comment->uid ? $comment->registered_name : $comment->name; - $output .= theme('comment_view', $comment); - } - else { - $form['#suffix'] = node_view(node_load($edit['nid'])); - $edit['pid'] = 0; - } - - $form['comment_preview_below'] = array('#value' => $output, '#weight' => 100); - - return $form; -} - -function comment_form_validate($form_id, $form_values) { - comment_validate($form_values); -} - -function _comment_form_submit($form_values) { - if (!isset($form_values['date'])) { - $form_values['date'] = 'now'; - } - $form_values['timestamp'] = strtotime($form_values['date']); - if (isset($form_values['author'])) { - $account = user_load(array('name' => $form_values['author'])); - $form_values['uid'] = $account->uid; - $form_values['name'] = $form_values['author']; - } - // Validate the comment's subject. If not specified, extract - // one from the comment's body. - if (trim($form_values['subject']) == '') { - // The body may be in any format, so we: - // 1) Filter it into HTML - // 2) Strip out all HTML tags - // 3) Convert entities back to plain-text. - // Note: format is checked by check_markup(). - $form_values['subject'] = trim(truncate_utf8(decode_entities(strip_tags(check_markup($form_values['comment'], $form_values['format']))), 29, TRUE)); - // Edge cases where the comment body is populated only by HTML tags will - // require a default subject. - if ($form_values['subject'] == '') { - $form_values['subject'] = t('(No subject)'); - } - } - - return $form_values; -} - -function comment_form_submit($form_id, $form_values) { - $form_values = _comment_form_submit($form_values); - if ($cid = comment_save($form_values)) { - return array('node/'. $form_values['nid'], NULL, "comment-$cid"); - } -} - -/* -** Renderer or visualization functions this can be optionally -** overridden by themes. -*/ - -function theme_comment_preview($comment, $links = array(), $visible = 1) { - $output = '
    '; - $output .= theme('comment_view', $comment, $links, $visible); - $output .= '
    '; - return $output; -}; - -function theme_comment_view($comment, $links = array(), $visible = 1) { - static $first_new = TRUE; - - $output = ''; - $comment->new = node_mark($comment->nid, $comment->timestamp); - if ($first_new && $comment->new != MARK_READ) { - // Assign the anchor only for the first new comment. This avoids duplicate - // id attributes on a page. - $first_new = FALSE; - $output .= "\n"; - } - - $output .= "cid\">\n"; - - // Switch to folded/unfolded view of the comment - if ($visible) { - $comment->comment = check_markup($comment->comment, $comment->format, FALSE); - - // Comment API hook - comment_invoke_comment($comment, 'view'); - - $output .= theme('comment', $comment, $links); - } - else { - $output .= theme('comment_folded', $comment); - } - - return $output; -} - -function comment_controls($mode = COMMENT_MODE_THREADED_EXPANDED, $order = COMMENT_ORDER_NEWEST_FIRST, $comments_per_page = 50) { - $form['mode'] = array('#type' => 'select', - '#default_value' => $mode, - '#options' => _comment_get_modes(), - '#weight' => 1, - ); - $form['order'] = array( - '#type' => 'select', - '#default_value' => $order, - '#options' => _comment_get_orders(), - '#weight' => 2, - ); - foreach (_comment_per_page() as $i) { - $options[$i] = t('!a comments per page', array('!a' => $i)); - } - $form['comments_per_page'] = array('#type' => 'select', - '#default_value' => $comments_per_page, - '#options' => $options, - '#weight' => 3, - ); - - $form['submit'] = array('#type' => 'submit', - '#value' => t('Save settings'), - '#weight' => 20, - ); - - return $form; -} - -function theme_comment_controls($form) { - $output .= '
    '; - $output .= drupal_render($form); - $output .= '
    '; - $output .= '
    '. t('Select your preferred way to display the comments and click "Save settings" to activate your changes.') .'
    '; - return theme('box', t('Comment viewing options'), $output); -} - -function comment_controls_submit($form_id, $form_values) { - global $user; - - $mode = $form_values['mode']; - $order = $form_values['order']; - $comments_per_page = $form_values['comments_per_page']; - - if ($user->uid) { - $user = user_save($user, array('mode' => $mode, 'sort' => $order, 'comments_per_page' => $comments_per_page)); - } - else { - $_SESSION['comment_mode'] = $mode; - $_SESSION['comment_sort'] = $order; - $_SESSION['comment_comments_per_page'] = $comments_per_page; - } -} - -/** - * Prepare values for comment.tpl.php - */ -function template_preprocess_comment(&$variables) { - $comment = $variables['comment']; - $variables['author'] = theme('username', $comment); - $variables['comment'] = $comment; - $variables['content'] = $comment->comment; - $variables['date'] = format_date($comment->timestamp); - $variables['links'] = isset($variables['links']) ? theme('links', $variables['links']) : ''; - $variables['new'] = $comment->new ? t('new') : ''; - $variables['picture'] = theme_get_setting('toggle_comment_user_picture') ? theme('user_picture', $comment) : ''; - $variables['signature'] = $comment->signature; - $variables['submitted'] = t('Submitted by !a on @b.', - array('!a' => theme('username', $comment), - '@b' => format_date($comment->timestamp))); - $variables['title'] = l($comment->subject, $_GET['q'], array('fragment' => "comment-$comment->cid")); -} - -function theme_comment_folded($comment) { - $output = "
    \n"; - $output .= ' '. l($comment->subject, comment_node_url() .'/'. $comment->cid, array('fragment' => "comment-$comment->cid")) .' '. theme('mark', $comment->new) .' '; - $output .= ''. t('by') .' '. theme('username', $comment) ."\n"; - $output .= "
    \n"; - return $output; -} - -function theme_comment_flat_collapsed($comment) { - return theme('comment_view', $comment, '', 0); -} - -function theme_comment_flat_expanded($comment) { - return theme('comment_view', $comment, module_invoke_all('link', 'comment', $comment, 0)); -} - -function theme_comment_thread_collapsed($comment) { - $output .= theme('comment_view', $comment, '', 0); - return $output; -} - -function theme_comment_thread_expanded($comment) { - $output = ''; - $output .= theme('comment_view', $comment, module_invoke_all('link', 'comment', $comment, 0)); - return $output; -} - -function theme_comment_post_forbidden($nid) { - global $user; - if ($user->uid) { - return t("you can't post comments"); - } - else { - // we cannot use drupal_get_destination() because these links sometimes appear on /node and taxo listing pages - if (variable_get('comment_form_location', COMMENT_FORM_SEPARATE_PAGE) == COMMENT_FORM_SEPARATE_PAGE) { - $destination = "destination=". drupal_urlencode("comment/reply/$nid#comment-form"); - } - else { - $destination = "destination=". drupal_urlencode("node/$nid#comment-form"); - } - - if (variable_get('user_register', 1)) { - return t('Login or register to post comments', array('@login' => url('user/login', array('query' => $destination)), '@register' => url('user/register', array('query' => $destination)))); - } - else { - return t('Login to post comments', array('@login' => url('user/login', array('query' => $destination)))); - } - } -} - -/** - * Allow themable wrapping of all comments. - */ -function theme_comment_wrapper($content) { - return '
    '. $content .'
    '; -} - -function _comment_delete_thread($comment) { - if (!is_object($comment) || !is_numeric($comment->cid)) { - watchdog('content', 'Can not delete non-existent comment.', WATCHDOG_WARNING); - return; - } - - // Delete the comment: - db_query('DELETE FROM {comments} WHERE cid = %d', $comment->cid); - watchdog('content', 'Comment: deleted %subject.', array('%subject' => $comment->subject)); - - comment_invoke_comment($comment, 'delete'); - - // Delete the comment's replies - $result = db_query('SELECT c.*, u.name AS registered_name, u.uid FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE pid = %d', $comment->cid); - while ($comment = db_fetch_object($result)) { - $comment->name = $comment->uid ? $comment->registered_name : $comment->name; - _comment_delete_thread($comment); - } -} - -/** - * Return an array of viewing modes for comment listings. - * - * We can't use a global variable array because the locale system - * is not initialized yet when the comment module is loaded. - */ -function _comment_get_modes() { - return array( - COMMENT_MODE_FLAT_COLLAPSED => t('Flat list - collapsed'), - COMMENT_MODE_FLAT_EXPANDED => t('Flat list - expanded'), - COMMENT_MODE_THREADED_COLLAPSED => t('Threaded list - collapsed'), - COMMENT_MODE_THREADED_EXPANDED => t('Threaded list - expanded') - ); -} - -/** - * Return an array of viewing orders for comment listings. - * - * We can't use a global variable array because the locale system - * is not initialized yet when the comment module is loaded. - */ -function _comment_get_orders() { - return array( - COMMENT_ORDER_NEWEST_FIRST => t('Date - newest first'), - COMMENT_ORDER_OLDEST_FIRST => t('Date - oldest first') - ); -} - -/** - * Return an array of "comments per page" settings from which the user - * can choose. - */ -function _comment_per_page() { - return drupal_map_assoc(array(10, 30, 50, 70, 90, 150, 200, 250, 300)); -} - -/** - * Return a current comment display setting - * - * $setting can be one of these: 'mode', 'sort', 'comments_per_page' - */ -function _comment_get_display_setting($setting) { - global $user; - - if (isset($_GET[$setting])) { - $value = $_GET[$setting]; - } - else { - // get the setting's site default - switch ($setting) { - case 'mode': - $default = variable_get('comment_default_mode', COMMENT_MODE_THREADED_EXPANDED); - break; - case 'sort': - $default = variable_get('comment_default_order', COMMENT_ORDER_NEWEST_FIRST); - break; - case 'comments_per_page': - $default = variable_get('comment_default_per_page', '50'); - } - if (variable_get('comment_controls', COMMENT_CONTROLS_HIDDEN) == COMMENT_CONTROLS_HIDDEN) { - // if comment controls are disabled use site default - $value = $default; - } - else { - // otherwise use the user's setting if set - if ($user->$setting) { - $value = $user->$setting; - } - else if ($_SESSION['comment_'. $setting]) { - $value = $_SESSION['comment_'. $setting]; - } - else { - $value = $default; - } - } - } - return $value; -} - -/** - * Updates the comment statistics for a given node. This should be called any - * time a comment is added, deleted, or updated. - * - * The following fields are contained in the node_comment_statistics table. - * - last_comment_timestamp: the timestamp of the last comment for this node or the node create stamp if no comments exist for the node. - * - last_comment_name: the name of the anonymous poster for the last comment - * - last_comment_uid: the uid of the poster for the last comment for this node or the node authors uid if no comments exists for the node. - * - comment_count: the total number of approved/published comments on this node. - */ -function _comment_update_node_statistics($nid) { - $count = db_result(db_query('SELECT COUNT(cid) FROM {comments} WHERE nid = %d AND status = %d', $nid, COMMENT_PUBLISHED)); - - // comments exist - if ($count > 0) { - $last_reply = db_fetch_object(db_query_range('SELECT cid, name, timestamp, uid FROM {comments} WHERE nid = %d AND status = %d ORDER BY cid DESC', $nid, COMMENT_PUBLISHED, 0, 1)); - db_query("UPDATE {node_comment_statistics} SET comment_count = %d, last_comment_timestamp = %d, last_comment_name = '%s', last_comment_uid = %d WHERE nid = %d", $count, $last_reply->timestamp, $last_reply->uid ? '' : $last_reply->name, $last_reply->uid, $nid); - } - - // no comments - else { - $node = db_fetch_object(db_query("SELECT uid, created FROM {node} WHERE nid = %d", $nid)); - db_query("UPDATE {node_comment_statistics} SET comment_count = 0, last_comment_timestamp = %d, last_comment_name = '', last_comment_uid = %d WHERE nid = %d", $node->created, $node->uid, $nid); - } -} - -/** * Invoke a hook_comment() operation in all modules. * * @param &$comment Index: modules/node/node.module =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.module,v retrieving revision 1.805 diff -u -p -r1.805 node.module --- modules/node/node.module 25 Apr 2007 21:28:00 -0000 1.805 +++ modules/node/node.module 30 Apr 2007 05:37:52 -0000 @@ -1128,6 +1128,7 @@ function node_menu() { 'weight' => -10, 'page callback' => 'system_admin_menu_block_page', 'access arguments' => array('administer site configuration'), + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/content/node'] = array( Index: modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.99 diff -u -p -r1.99 system.install --- modules/system/system.install 25 Apr 2007 21:34:32 -0000 1.99 +++ modules/system/system.install 30 Apr 2007 05:37:53 -0000 @@ -359,6 +359,7 @@ function system_install() { fragment varchar(255) NOT NULL default '', absolute INT NOT NULL default 0, html INT NOT NULL default 0, + includes mediumtext NOT NULL default '', PRIMARY KEY (path), KEY fit (fit), KEY visible (visible), @@ -835,6 +836,7 @@ function system_install() { fragment varchar(255) NOT NULL default '', absolute INT NOT NULL default 0, html INT NOT NULL default 0, + includes text NOT NULL default '', PRIMARY KEY (path) )"); @@ -3847,6 +3849,28 @@ function system_update_6012() { } /** + * Add optional includes to menu paths + */ +function system_update_6013() { + $ret = array(); + + switch ($GLOBALS['db_type']) { + case 'pgsql': + db_add_column($ret, 'menu', 'includes', 'text', array('default' => "''", 'not null' => TRUE)); + break; + case 'mysql': + case 'mysqli': + $ret[] = update_sql("ALTER TABLE {menu} ADD includes mediumtext NOT NULL default ''"); + break; + + } + + return $ret; +} + + + +/** * @} End of "defgroup updates-5.x-to-6.x" * The next series of updates should start at 7000. */ Index: modules/system/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.module,v retrieving revision 1.471 diff -u -p -r1.471 system.module --- modules/system/system.module 24 Apr 2007 19:49:01 -0000 1.471 +++ modules/system/system.module 30 Apr 2007 05:37:53 -0000 @@ -134,22 +134,26 @@ function system_menu() { 'access arguments' => array('access administration pages'), 'page callback' => 'system_main_admin_page', 'weight' => 9, + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/compact'] = array( 'title' => t('Compact mode'), 'page callback' => 'system_admin_compact_page', 'type' => MENU_CALLBACK, + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/by-task'] = array( 'title' => t('By task'), 'page callback' => 'system_main_admin_page', 'type' => MENU_DEFAULT_LOCAL_TASK, + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/by-module'] = array( 'title' => t('By module'), 'page callback' => 'system_admin_by_module', 'type' => MENU_LOCAL_TASK, 'weight' => 2, + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); // menu items that are basically just menu blocks $items['admin/settings'] = array( @@ -167,6 +171,7 @@ function system_menu() { 'weight' => -10, 'page callback' => 'system_admin_menu_block_page', 'access arguments' => array('administer site configuration'), + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/settings/admin'] = array( 'title' => t('Administration theme'), @@ -175,6 +180,7 @@ function system_menu() { 'page callback' => 'drupal_get_form', 'page arguments' => array('system_admin_theme_settings'), 'block callback' => 'system_admin_theme_settings', + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); // Themes: $items['admin/build/themes'] = array( @@ -182,12 +188,14 @@ function system_menu() { 'description' => t('Change which theme your site uses or allows users to set.'), 'page callback' => 'drupal_get_form', 'page arguments' => array('system_themes_form'), + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/build/themes/select'] = array( 'title' => t('List'), 'description' => t('Select the default theme.'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -1, + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/build/themes/settings'] = array( 'title' => t('Configure'), @@ -217,6 +225,7 @@ function system_menu() { 'description' => t('Enable or disable add-on modules for your site.'), 'page callback' => 'drupal_get_form', 'page arguments' => array('system_modules'), + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/build/modules/list'] = array( 'title' => t('List'), @@ -242,59 +251,69 @@ function system_menu() { 'description' => t('Change basic site information, such as the site name, slogan, e-mail address, mission, front page and more.'), 'page callback' => 'drupal_get_form', 'page arguments' => array('system_site_information_settings'), + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/settings/error-reporting'] = array( 'title' => t('Error reporting'), 'description' => t('Control how Drupal deals with errors including 403/404 errors as well as PHP error reporting.'), 'page callback' => 'drupal_get_form', 'page arguments' => array('system_error_reporting_settings'), + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/settings/logging'] = array( 'title' => t('Logging and alerts'), 'description' => t('Settings for logging and alerts modules. Various modules can route Drupal\'s system events to different destination, such as syslog, database, email, ...etc.'), 'page callback' => 'system_logging_overview', + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/settings/performance'] = array( 'title' => t('Performance'), 'description' => t('Enable or disable page caching for anonymous users, and enable or disable CSS preprocessor.'), 'page callback' => 'drupal_get_form', 'page arguments' => array('system_performance_settings'), + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/settings/file-system'] = array( 'title' => t('File system'), 'description' => t('Tell Drupal where to store uploaded files and how they are accessed.'), 'page callback' => 'drupal_get_form', 'page arguments' => array('system_file_system_settings'), + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/settings/image-toolkit'] = array( 'title' => t('Image toolkit'), 'description' => t('Choose which image toolkit to use if you have installed optional toolkits.'), 'page callback' => 'drupal_get_form', 'page arguments' => array('system_image_toolkit_settings'), + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/content/rss-publishing'] = array( 'title' => t('RSS publishing'), 'description' => t('Configure the number of items per feed and whether feeds should be titles/teasers/full-text.'), 'page callback' => 'drupal_get_form', 'page arguments' => array('system_rss_feeds_settings'), + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/settings/date-time'] = array( 'title' => t('Date and time'), 'description' => t("Settings for how Drupal displays date and time, as well as the system's default timezone."), 'page callback' => 'drupal_get_form', 'page arguments' => array('system_date_time_settings'), + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/settings/site-maintenance'] = array( 'title' => t('Site maintenance'), 'description' => t('Take the site off-line for maintenance or bring it back online.'), 'page callback' => 'drupal_get_form', 'page arguments' => array('system_site_maintenance_settings'), + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/settings/clean-urls'] = array( 'title' => t('Clean URLs'), 'description' => t('Enable or disable clean URLs for your site.'), 'page callback' => 'drupal_get_form', 'page arguments' => array('system_clean_url_settings'), + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); // Logs: @@ -304,6 +323,7 @@ function system_menu() { 'page callback' => 'system_admin_menu_block_page', 'weight' => 5, 'position' => 'left', + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/logs/status'] = array( 'title' => t('Status report'), @@ -311,6 +331,7 @@ function system_menu() { 'page callback' => 'system_status', 'weight' => 10, 'access arguments' => array('administer site configuration'), + 'includes' => drupal_get_path('module', 'system') . '/system.pages.inc', ); $items['admin/logs/status/run-cron'] = array( 'title' => t('Run cron'), @@ -374,55 +395,99 @@ function system_user($type, $edit, &$use } /** - * Provide the administration overview page. + * Implementation of hook_node_type(). + * + * Updates theme settings after a node type change. */ -function system_main_admin_page($arg = NULL) { - // If we received an argument, they probably meant some other page. - // Let's 404 them since the menu system cannot be told we do not - // accept arguments. - if (isset($arg) && substr($arg, 0, 3) != 'by-') { - return drupal_not_found(); +function system_node_type($op, $info) { + if ($op == 'update' && !empty($info->old_type) && $info->type != $info->old_type) { + $old = 'toggle_node_info_'. $info->old_type; + $new = 'toggle_node_info_'. $info->type; + + $theme_settings = variable_get('theme_settings', array()); + if (isset($theme_settings[$old])) { + $theme_settings[$new] = $theme_settings[$old]; + unset($theme_settings[$old]); + variable_set('theme_settings', $theme_settings); + } } +} + +/** + * Get a list of available regions from a specified theme. + * + * @param $theme_key + * The name of a theme. + * @return + * An array of regions in the form $region['name'] = 'description'. + */ +function system_region_list($theme_key) { + static $list = array(); - // Check for status report errors. - if (system_status(TRUE)) { - drupal_set_message(t('One or more problems were detected with your Drupal installation. Check the status report for more information.', array('@status' => url('admin/logs/status'))), 'error'); + if (!array_key_exists($theme_key, $list)) { + $info = unserialize(db_result(db_query("SELECT info FROM {system} WHERE type = 'theme' AND name = '%s'", $theme_key))); + $list[$theme_key] = array_map('t', $info['regions']); } - $map = arg(NULL); - $result = db_query("SELECT * FROM {menu} WHERE path LIKE 'admin/%%' AND depth = 2 AND visible = 1 AND path != 'admin/help' ORDER BY mleft"); - while ($item = db_fetch_object($result)) { - _menu_translate($item, $map, MENU_RENDER_LINK); - if (!$item->access) { - continue; - } - $block = (array)$item; - $block['content'] = ''; - if ($item->block_callback && function_exists($item->block_callback)) { - $function = $item->block_callback; - $block['content'] .= $function(); + return $list[$theme_key]; +} + +/** + * Get the name of the default region for a given theme. + * + * @param $theme + * The name of a theme. + * @return + * A string that is the region name. + */ +function system_default_region($theme) { + $regions = array_keys(system_region_list($theme)); + return isset($regions[0]) ? $regions[0] : ''; +} + +/** + * Assign an initial, default set of blocks for a theme. + * + * This function is called the first time a new theme is enabled. The new theme + * gets a copy of the default theme's blocks, with the difference that if a + * particular region isn't available in the new theme, the block is assigned + * to the new theme's default region. + * + * @param $theme + * The name of a theme. + */ +function system_initialize_theme_blocks($theme) { + // Initialize theme's blocks if none already registered. + if (!(db_num_rows(db_query("SELECT module FROM {blocks} WHERE theme = '%s'", $theme)))) { + $default_theme = variable_get('theme_default', 'garland'); + $regions = system_region_list($theme); + $result = db_query("SELECT * FROM {blocks} WHERE theme = '%s'", $default_theme); + while ($block = db_fetch_array($result)) { + // If the region isn't supported by the theme, assign the block to the theme's default region. + if (!array_key_exists($block['region'], $regions)) { + $block['region'] = system_default_region($theme); + } + db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, visibility, pages, custom, throttle) VALUES ('%s', '%s', '%s', %d, %d, '%s', %d, '%s', %d, %d)", + $block['module'], $block['delta'], $theme, $block['status'], $block['weight'], $block['region'], $block['visibility'], $block['pages'], $block['custom'], $block['throttle']); } - $block['content'] .= theme('admin_block_content', system_admin_menu_block($item)); - $blocks[] = $block; } - return theme('admin_page', $blocks); } + /** - * Provide a single block on the administration overview page. + * Add default buttons to a form and set its prefix */ -function system_admin_menu_block($item) { - $map = arg(NULL); - $content = array(); - $result = db_query('SELECT * FROM {menu} WHERE depth = %d AND %d < mleft AND mright < %d AND visible = 1 ORDER BY mleft', $item->depth + 1, $item->mleft, $item->mright); - while ($item = db_fetch_object($result)) { - _menu_translate($item, $map, MENU_RENDER_LINK); - if (!$item->access) { - continue; - } - $content[] = (array)$item; +function system_settings_form($form) { + $form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration') ); + $form['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset to defaults') ); + + if (!empty($_POST) && form_get_errors()) { + drupal_set_message(t('The settings have not been saved because of the errors.'), 'error'); } - return $content; + $form['#submit']['system_settings_form_submit'] = array(); + $form['#validate']['system_settings_form_validate'] = array(); + $form['#theme'] = 'system_settings_form'; + return $form; } /** @@ -440,48 +505,116 @@ function system_admin_menu_block_page() return $output; } -function system_admin_compact_page($mode = 'off') { - global $user; - user_save($user, array('admin_compact_mode' => ($mode == 'on'))); - drupal_goto('admin'); +/** + * Provide a single block on the administration overview page. + */ +function system_admin_menu_block($item) { + $map = arg(NULL); + $content = array(); + $result = db_query('SELECT * FROM {menu} WHERE depth = %d AND %d < mleft AND mright < %d AND visible = 1 ORDER BY mleft', $item->depth + 1, $item->mleft, $item->mright); + while ($item = db_fetch_object($result)) { + _menu_translate($item, $map, MENU_RENDER_LINK); + if (!$item->access) { + continue; + } + $content[] = (array)$item; + } + return $content; } + /** - * This function allows selection of the theme to show in administration sections. + * This function formats the content of an administrative block. + * + * @param $block + * An array containing information about the block. It should + * include a 'title', a 'description' and a formatted 'content'. + * @themeable */ -function system_admin_theme_settings() { - $themes = system_theme_data(); - ksort($themes); - $options[0] = t('System default'); - foreach ($themes as $theme) { - $options[$theme->name] = $theme->info['name']; +function theme_admin_block_content($content) { + if (!$content) { + return ''; } - $form['admin_theme'] = array( - '#type' => 'select', - '#options' => $options, - '#title' => t('Administration theme'), - '#description' => t('Choose which theme the administration pages should display in. If you choose "System default" the administration pages will use the same theme as the rest of the site.'), - '#default_value' => variable_get('admin_theme', '0'), - ); - - // In order to give it our own submit, we have to give it the default submit - // too because the presence of a #submit will prevent the default #submit - // from being used. Also we want ours first. - $form['#submit']['system_admin_theme_submit'] = array(); - $form['#submit']['system_settings_form_submit'] = array(); - return system_settings_form($form); + if (system_admin_compact_mode()) { + $output = ''; + } + else { + $output = '
    '; + foreach ($content as $item) { + $output .= '
    '. l($item['title'], $item['path'], $item) .'
    '; + $output .= '
    '. $item['description'] .'
    '; + } + $output .= '
    '; + } + return $output; } +/** + * Output a confirmation form + * + * This function returns a complete form for confirming an action. A link is + * offered to go back to the item that is being changed in case the user changes + * his/her mind. + * + * You can check for the existence of $_POST[$name] (where $name + * is usually 'confirm') to check if the confirmation was successful or + * use the regular submit model. + * + * @param $form + * Additional elements to inject into the form, for example hidden elements. + * @param $question + * The question to ask the user (e.g. "Are you sure you want to delete the + * block foo?"). + * @param $path + * The page to go to if the user denies the action. + * Can be either a drupal path, or an array with the keys 'path', 'query', 'fragment'. + * @param $description + * Additional text to display (defaults to "This action cannot be undone."). + * @param $yes + * A caption for the button which confirms the action (e.g. "Delete", + * "Replace", ...). + * @param $no + * A caption for the link which denies the action (e.g. "Cancel"). + * @param $name + * The internal name used to refer to the confirmation item. + * @return + * The form. + */ +function confirm_form($form, $question, $path, $description = NULL, $yes = NULL, $no = NULL, $name = 'confirm') { + $description = isset($description) ? $description : t('This action cannot be undone.'); -function system_admin_theme_submit($form_id, $form_values) { - // If we're changing themes, make sure the theme has its blocks initialized. - if ($form_values['admin_theme'] != variable_get('admin_theme', '0')) { - $result = db_query("SELECT status FROM {blocks} WHERE theme = '%s'", $form_values['admin_theme']); - if (!db_num_rows($result)) { - system_initialize_theme_blocks($form_values['admin_theme']); - } + // Prepare cancel link + $query = $fragment = NULL; + if (is_array($path)) { + $query = isset($path['query']) ? $path['query'] : NULL; + $fragment = isset($path['fragment']) ? $path['fragment'] : NULL; + $path = isset($path['path']) ? $path['path'] : NULL; } + $cancel = l($no ? $no : t('Cancel'), $path, array('query' => $query, 'fragment' => $fragment)); + + drupal_set_title($question); + + // Confirm form fails duplication check, as the form values rarely change -- so skip it. + $form['#skip_duplicate_check'] = TRUE; + + $form['#attributes'] = array('class' => 'confirmation'); + $form['description'] = array('#value' => $description); + $form[$name] = array('#type' => 'hidden', '#value' => 1); + + $form['actions'] = array('#prefix' => '
    ', '#suffix' => '
    '); + $form['actions']['submit'] = array('#type' => 'submit', '#value' => $yes ? $yes : t('Confirm')); + $form['actions']['cancel'] = array('#value' => $cancel); + $form['#theme'] = 'confirm_form'; + return $form; } /* @@ -562,1902 +695,10 @@ function _system_zonelist() { return $zones; } -function system_site_information_settings() { - $form['site_name'] = array( - '#type' => 'textfield', - '#title' => t('Name'), - '#default_value' => variable_get('site_name', 'Drupal'), - '#description' => t('The name of this website.'), - '#required' => TRUE - ); - $form['site_mail'] = array( - '#type' => 'textfield', - '#title' => t('E-mail address'), - '#default_value' => variable_get('site_mail', ini_get('sendmail_from')), - '#description' => t('A valid e-mail address to be used as the "From" address by the auto-mailer during registration, new password requests, notifications, etc. To lessen the likelihood of e-mail being marked as spam, this e-mail address should use the same domain as the website.'), - '#required' => TRUE, - ); - $form['site_slogan'] = array( - '#type' => 'textfield', - '#title' => t('Slogan'), - '#default_value' => variable_get('site_slogan', ''), - '#description' => t('The slogan of this website. Some themes display a slogan when available.') - ); - - $form['site_mission'] = array( - '#type' => 'textarea', - '#title' => t('Mission'), - '#default_value' => variable_get('site_mission', ''), - '#description' => t('Your site\'s mission statement or focus.') - ); - $form['site_footer'] = array( - '#type' => 'textarea', - '#title' => t('Footer message'), - '#default_value' => variable_get('site_footer', ''), - '#description' => t('This text will be displayed at the bottom of each page. Useful for adding a copyright notice to your pages.') - ); - $form['anonymous'] = array( - '#type' => 'textfield', - '#title' => t('Anonymous user'), - '#default_value' => variable_get('anonymous', t('Anonymous')), - '#description' => t('The name used to indicate anonymous users.') - ); - $form['site_frontpage'] = array( - '#type' => 'textfield', - '#title' => t('Default front page'), - '#default_value' => variable_get('site_frontpage', 'node'), - '#size' => 40, - '#description' => t('The home page displays content from this relative URL. If unsure, specify "node".'), - '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=') - ); - - return system_settings_form($form); -} - -function system_clean_url_settings() { - $form['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).'), - ); - - if (!variable_get('clean_url', 0)) { - if (strpos(request_uri(), '?q=') !== FALSE) { - drupal_add_js(array('cleanURL' => array('success' => t('Your server has been successfully tested to support this feature.'), 'failure' => t('Your system configuration does not currently support this feature. The handbook page on Clean URLs has additional troubleshooting information.'), 'testing' => t('Testing clean URLs...'))), 'setting'); - drupal_add_js(drupal_get_path('module', 'system') .'/system.js', 'module'); - drupal_add_js(' -// Global Killswitch -if (Drupal.jsEnabled) { - $(document).ready(function() { - Drupal.cleanURLsSettingsCheck(); - }); -}', 'inline'); - - $form['clean_url']['#description'] .= ' '. t('Before enabling clean URLs, you must perform a test to determine if your server is properly configured. If you are able to see this page again after clicking the "Run the clean URL test" link, the test has succeeded and the radio buttons above will be available. If instead you are directed to a "Page not found" error, you will need to change the configuration of your server. The handbook page on Clean URLs has additional troubleshooting information.', array('@handbook' => 'http://drupal.org/node/15365')) .''; - - $form['clean_url']['#disabled'] = TRUE; - $form['clean_url']['#prefix'] = '
    '; - $form['clean_url']['#suffix'] = '

    '. t('Run the clean url test.', array('@clean_url' => base_path() .'admin/settings/clean-urls')) .'

    '; - } - else { - $form['clean_url']['#description'] .= ' '. t('Your server has been successfully tested to support this feature.'); - } - } - - return system_settings_form($form); -} - -function system_error_reporting_settings() { - - $form['site_403'] = array( - '#type' => 'textfield', - '#title' => t('Default 403 (access denied) page'), - '#default_value' => variable_get('site_403', ''), - '#size' => 40, - '#description' => t('This page is displayed when the requested document is denied to the current user. If unsure, specify nothing.'), - '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=') - ); - - $form['site_404'] = array( - '#type' => 'textfield', - '#title' => t('Default 404 (not found) page'), - '#default_value' => variable_get('site_404', ''), - '#size' => 40, - '#description' => t('This page is displayed when no other content matches the requested document. If unsure, specify nothing.'), - '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=') - ); - - $form['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.') - ); - - return system_settings_form($form); -} - -function system_performance_settings() { - - $description = '

    '. t("The normal cache mode is suitable for most sites and does not cause any side effects. The aggressive cache mode causes Drupal to skip the loading (init) and unloading (exit) of enabled modules when serving a cached page. This results in an additional performance boost but can cause unwanted side effects.") .'

    '; - - $problem_modules = array_unique(array_merge(module_implements('init'), module_implements('exit'))); - sort($problem_modules); - - if (count($problem_modules) > 0) { - $description .= '

    '. t('The following enabled modules are incompatible with aggressive mode caching and will not function properly: %modules', array('%modules' => implode(', ', $problem_modules))) .'.

    '; - } - else { - $description .= '

    '. t('Currently, all enabled modules are compatible with the aggressive caching policy. Please note, if you use aggressive caching and enable new modules, you will need to check this page again to ensure compatibility.') .'

    '; - } - $form['page_cache'] = array( - '#type' => 'fieldset', - '#title' => t('Page cache'), - '#description' => t('Enabling the cache will offer a significant performance boost. Drupal can store and send compressed cached pages requested by anonymous users. By caching a web page, Drupal does not have to construct the page each time someone wants to view it.'), - ); - - $form['page_cache']['cache'] = array( - '#type' => 'radios', - '#title' => t('Caching mode'), - '#default_value' => variable_get('cache', CACHE_DISABLED), - '#options' => array(CACHE_DISABLED => t('Disabled'), CACHE_NORMAL => t('Normal (recommended, no side effects)'), CACHE_AGGRESSIVE => t('Aggressive (experts only, possible side effects)')), - '#description' => $description - ); - - $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'); - $form['page_cache']['cache_lifetime'] = array( - '#type' => 'select', - '#title' => t('Minimum cache lifetime'), - '#default_value' => variable_get('cache_lifetime', 0), - '#options' => $period, - '#description' => t('On high-traffic sites it can become necessary to enforce a minimum cache lif