? .DS_Store ? phpinfo.php ? popups-193311-45_0.patch ? popups-193311-50.patch ? misc/popupapi.js ? modules/popuppage ? modules/system/popup-template.tpl.php ? sites/default/files ? sites/default/settings.php Index: index.php =================================================================== RCS file: /cvs/drupal/drupal/index.php,v retrieving revision 1.94 diff -u -p -r1.94 index.php --- index.php 26 Dec 2007 08:46:48 -0000 1.94 +++ index.php 20 Mar 2008 00:58:37 -0000 @@ -32,8 +32,7 @@ if (is_int($return)) { } } elseif (isset($return)) { - // Print any value (including an empty string) except NULL or undefined: - print theme('page', $return); + print render('page', $return); } drupal_page_footer(); Index: includes/bootstrap.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v retrieving revision 1.206 diff -u -p -r1.206 bootstrap.inc --- includes/bootstrap.inc 10 Jan 2008 22:47:17 -0000 1.206 +++ includes/bootstrap.inc 20 Mar 2008 00:58:37 -0000 @@ -271,7 +271,7 @@ function drupal_unset_globals() { * session name correctly. */ function conf_init() { - global $base_url, $base_path, $base_root; + global $base_url, $base_path, $base_root, $render_mode, $request_mode; // Export the following settings.php variables to the global namespace global $db_url, $db_prefix, $cookie_domain, $conf, $installed_profile, $update_free_access; @@ -337,6 +337,10 @@ function conf_init() { ini_set('session.cookie_domain', $cookie_domain); } session_name('SESS'. md5($session_name)); + + // TODO - add comments to describe what these globals control. + $render_mode = isset($_SERVER['HTTP_X_DRUPAL_RENDER_MODE']) ? $_SERVER['HTTP_X_DRUPAL_RENDER_MODE'] : 'xhtml/plain'; + $request_mode = isset($_SERVER['HTTP_X_REQUESTED_WITH']) ? $_SERVER['HTTP_X_REQUESTED_WITH'] : 'standard'; } /** Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.760 diff -u -p -r1.760 common.inc --- includes/common.inc 17 Mar 2008 17:01:05 -0000 1.760 +++ includes/common.inc 20 Mar 2008 00:58:40 -0000 @@ -293,14 +293,14 @@ function drupal_get_destination() { * supported. * @see drupal_get_destination() */ -function drupal_goto($path = '', $query = NULL, $fragment = NULL, $http_response_code = 302) { - +// TODO - update comments to reflect breaking drupal_goto into two functions. +function drupal_get_goto_url($path = '', $query = NULL, $fragment = NULL) { if (isset($_REQUEST['destination'])) { extract(parse_url(urldecode($_REQUEST['destination']))); } else if (isset($_REQUEST['edit']['destination'])) { extract(parse_url(urldecode($_REQUEST['edit']['destination']))); - } + } $url = url($path, array('query' => $query, 'fragment' => $fragment, 'absolute' => TRUE)); // Remove newlines from the URL to avoid header injection attacks. @@ -311,19 +311,25 @@ function drupal_goto($path = '', $query if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') { module_invoke_all('exit', $url); } + return $url; +} +function drupal_goto($path = '', $query = NULL, $fragment = NULL, $http_response_code = 302) { + $url = drupal_get_goto_url($path, $query, $fragment); + // Even though session_write_close() is registered as a shutdown function, we // need all session data written to the database before redirecting. session_write_close(); - + header('Location: '. $url, TRUE, $http_response_code); - + // The "Location" header sends a redirect status code to the HTTP daemon. In // some cases this can be wrong, so we make sure none of the code below the // drupal_goto() call gets executed upon redirection. exit(); } + /** * Generates a site off-line message. */ @@ -2629,6 +2635,44 @@ function drupal_alter($type, &$data) { } } +/** + * Abstract the Drupal rendering system. + * Allow renderers other than the theme system to produce content output. + * Example of use: render('page', $content); + * + * @param + * Array starting with the element being rendered (ex: 'page'), + * followed by the content arguments. + * + * @return + * Rendered content. + */ +function render() { + global $render_mode; + $args = func_get_args(); + +// TODO - cache the renderer dispatch table. +// static $renderers; +// if (!$renderers) { +// // look in the cache +// //$renderers = cache_get('renderers'); +// if (!$renderers) { +// $renderers = module_invoke_all('renderers'); // Build the renderer dispatch table +// cache_set('renderers', $renderers); +// } +// } + + $renderers = module_invoke_all('renderers'); // Build the renderer dispatch table + $renderer = $renderers[$render_mode]; + if ($renderer) { + return call_user_func_array($renderer, $args); + } + else { + drupal_set_message(t('Attempting to use an unsupported render mode %render_mode.', array('%render_mode' => $render_mode)), 'error'); + $args = func_get_args(); + return call_user_func_array('theme', $args); + } +} /** * Renders HTML given a structured array tree. Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.268 diff -u -p -r1.268 form.inc --- includes/form.inc 15 Mar 2008 11:02:47 -0000 1.268 +++ includes/form.inc 20 Mar 2008 00:58:42 -0000 @@ -433,7 +433,9 @@ function drupal_process_form($form_id, & // however, we'll skip this and let the calling function examine // the resulting $form_state bundle itself. if (!$form['#programmed'] && empty($form_state['rebuild']) && empty($form_state['storage'])) { - drupal_redirect_form($form, $form_state['redirect']); + global $request_mode; + // TODO - more comments here, and update the above comments. + module_invoke_all('after_process_form', $request_mode, $form, $form_state); } } } @@ -606,8 +608,13 @@ function drupal_render_form($form_id, &$ * @param $redirect * An optional value containing the destination path to redirect * to if none is specified by the form. + * @param $do_goto + * Boolean flag. + * If true, call to drupal_goto to do the redirect. + * If false, return the url of the redirect, but don't go there. This allows + * for alternal flows of control, such as AJAX or webservices. */ -function drupal_redirect_form($form, $redirect = NULL) { +function drupal_redirect_form($form, $redirect = NULL, $do_goto = TRUE) { $goto = NULL; if (isset($redirect)) { $goto = $redirect; @@ -615,17 +622,31 @@ function drupal_redirect_form($form, $re if ($goto !== FALSE && isset($form['#redirect'])) { $goto = $form['#redirect']; } - if (!isset($goto) || ($goto !== FALSE)) { - if (isset($goto)) { - if (is_array($goto)) { - call_user_func_array('drupal_goto', $goto); + if (!isset($goto) || ($goto !== FALSE)) { + // If $do_goto is set, call drupal_goto and do the redirect & exit. + if ($do_goto) { + if (isset($goto)) { + if (is_array($goto)) { + call_user_func_array('drupal_goto', $goto); + } + else { + drupal_goto($goto); + } } - else { - drupal_goto($goto); + drupal_goto($_GET['q']); + } + else { // If $do_goto is false, just calculate and return the next url. + if (isset($goto)) { + if (is_array($goto)) { + return call_user_func_array('drupal_get_goto_url', $goto); + } + else { + return drupal_get_goto_url($goto); + } } + return drupal_get_goto_url($_GET['q']); } - drupal_goto($_GET['q']); - } + } } /** Index: includes/menu.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/menu.inc,v retrieving revision 1.266 diff -u -p -r1.266 menu.inc --- includes/menu.inc 19 Mar 2008 07:38:29 -0000 1.266 +++ includes/menu.inc 20 Mar 2008 00:58:43 -0000 @@ -1167,6 +1167,7 @@ function menu_get_active_help() { // Add "more help" link on admin pages if the module provides a // standalone help page. if ($arg[0] == "admin" && module_exists('help') && module_invoke($name, 'help', 'admin/help#'. $arg[2], $empty_arg) && $help) { + drupal_add_popups(); $output .= theme("more_help_link", url('admin/help/'. $arg[2])); } } Index: includes/theme.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/theme.inc,v retrieving revision 1.417 diff -u -p -r1.417 theme.inc --- includes/theme.inc 20 Feb 2008 13:39:29 -0000 1.417 +++ includes/theme.inc 20 Mar 2008 00:58:44 -0000 @@ -1449,7 +1449,7 @@ function theme_item_list($items = array( * Returns code that emits the 'more help'-link. */ function theme_more_help_link($url) { - return '
'. l(t('More information about formatting options'), 'filter/tips') .'
'; + drupal_add_popups(); + $extra = ''. l(t('More information about formatting options'), 'filter/tips', array('attributes'=>array('class'=>'popup'))) .'
'; $tiplist = theme('filter_tips', $tips, FALSE, $extra); if (!$tiplist) { $tiplist = ''. t('No guidelines available.') .'
'; Index: modules/filter/filter.module =================================================================== RCS file: /cvs/drupal/drupal/modules/filter/filter.module,v retrieving revision 1.207 diff -u -p -r1.207 filter.module --- modules/filter/filter.module 13 Mar 2008 21:26:08 -0000 1.207 +++ modules/filter/filter.module 20 Mar 2008 00:58:46 -0000 @@ -477,6 +477,7 @@ function filter_form($value = FILTER_FOR $value = filter_resolve_format($value); $formats = filter_formats(); + drupal_add_popups(); $extra = theme('filter_tips_more_info'); if (count($formats) > 1) { @@ -581,7 +582,7 @@ function _filter_tips($format, $long = F * @ingroup themeable */ function theme_filter_tips_more_info() { - return ''. l(t('More information about formatting options'), 'filter/tips') .'
'; + return ''. l(t('More information about formatting options'), 'filter/tips', array('attributes'=>array('class'=>'popup'))) .'
'; } /** Index: modules/help/help.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/help/help.admin.inc,v retrieving revision 1.5 diff -u -p -r1.5 help.admin.inc --- modules/help/help.admin.inc 25 Nov 2007 11:11:17 -0000 1.5 +++ modules/help/help.admin.inc 20 Mar 2008 00:58:46 -0000 @@ -23,7 +23,7 @@ function help_page($name) { $output = ''; if (module_hook($name, 'help')) { $module = drupal_parse_info_file(drupal_get_path('module', $name) .'/'. $name .'.info'); - drupal_set_title($module['name']); + drupal_set_title(t('Help: '). $module['name']); $temp = module_invoke($name, 'help', "admin/help#$name", drupal_help_arg()); if (empty($temp)) { Index: modules/menu/menu.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/menu/menu.admin.inc,v retrieving revision 1.29 diff -u -p -r1.29 menu.admin.inc --- modules/menu/menu.admin.inc 23 Feb 2008 08:13:09 -0000 1.29 +++ modules/menu/menu.admin.inc 20 Mar 2008 00:58:46 -0000 @@ -61,6 +61,7 @@ function menu_overview_form(&$form_state */ function _menu_overview_tree_form($tree) { static $form = array('#tree' => TRUE); + drupal_add_popups(); foreach ($tree as $data) { $title = ''; $item = $data['link']; @@ -97,11 +98,11 @@ function _menu_overview_tree_form($tree) $operations['edit'] = l(t('edit'), 'admin/build/menu/item/'. $item['mlid'] .'/edit'); // Only items created by the menu module can be deleted. if ($item['module'] == 'menu' || $item['updated'] == 1) { - $operations['delete'] = l(t('delete'), 'admin/build/menu/item/'. $item['mlid'] .'/delete'); + $operations['delete'] = l(t('delete'), 'admin/build/menu/item/'. $item['mlid'] .'/delete', array('attributes'=>array('class'=>'popup-form'))); } // Set the reset column. elseif ($item['module'] == 'system' && $item['customized']) { - $operations['reset'] = l(t('reset'), 'admin/build/menu/item/'. $item['mlid'] .'/reset'); + $operations['reset'] = l(t('reset'), 'admin/build/menu/item/'. $item['mlid'] .'/reset', array('attributes'=>array('class'=>'popup-form'))); } $form[$mlid]['operations'] = array(); Index: modules/node/content_types.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/node/content_types.inc,v retrieving revision 1.50 diff -u -p -r1.50 content_types.inc --- modules/node/content_types.inc 27 Jan 2008 18:03:05 -0000 1.50 +++ modules/node/content_types.inc 20 Mar 2008 00:58:46 -0000 @@ -10,6 +10,7 @@ * Displays the content type admin overview page. */ function node_overview_types() { + drupal_add_popups(); $types = node_get_types(); $names = node_get_types('names'); $header = array(t('Name'), t('Type'), t('Description'), array('data' => t('Operations'), 'colspan' => '2')); @@ -29,7 +30,7 @@ function node_overview_types() { // Set the delete column. if ($type->custom) { - $row[] = array('data' => l(t('delete'), 'admin/content/node-type/'. $type_url_str .'/delete')); + $row[] = array('data' => l(t('delete'), 'admin/content/node-type/'. $type_url_str .'/delete', array('attributes'=>array('class'=>'popup-form')))); } else { $row[] = array('data' => ''); Index: modules/path/path.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/path/path.admin.inc,v retrieving revision 1.7 diff -u -p -r1.7 path.admin.inc --- modules/path/path.admin.inc 8 Jan 2008 10:35:42 -0000 1.7 +++ modules/path/path.admin.inc 20 Mar 2008 00:58:46 -0000 @@ -41,7 +41,12 @@ function path_admin_overview($keys = NUL $rows = array(); $destination = drupal_get_destination(); while ($data = db_fetch_object($result)) { - $row = array(check_plain($data->dst), check_plain($data->src), l(t('edit'), "admin/build/path/edit/$data->pid", array('query' => $destination)), l(t('delete'), "admin/build/path/delete/$data->pid", array('query' => $destination))); + $row = array( + check_plain($data->dst), + check_plain($data->src), + l(t('edit'), "admin/build/path/edit/$data->pid", array('query' => $destination)), + l(t('delete'), "admin/build/path/delete/$data->pid", array('query' => $destination, 'attributes'=>array('class'=>'popup-form'))) + ); if ($multilanguage) { $row[4] = $row[3]; $row[3] = $row[2]; Index: modules/system/system.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v retrieving revision 1.65 diff -u -p -r1.65 system.admin.inc --- modules/system/system.admin.inc 13 Mar 2008 21:26:09 -0000 1.65 +++ modules/system/system.admin.inc 20 Mar 2008 00:58:48 -0000 @@ -116,6 +116,31 @@ function system_admin_by_module() { } /** + * Todo + * + * @return unknown + */ +function system_popup_settings() { + drupal_set_title("Popups Settings"); + $form = array(); + + $form['popuppage_title_selector'] = array( + '#type' => 'textfield', + '#title' => t('Title Selector'), + '#default_value' => variable_get('popuppage_title_selector', 'div.left-corner > h2:eq(0)'), + '#description' => t("jQuery selector to define the page's title on your Admin theme."), + ); + $form['popuppage_content_selector'] = array( + '#type' => 'textfield', + '#title' => t('Content Selector'), + '#default_value' => variable_get('popuppage_content_selector', 'div.left-corner > div.clear-block:last'), + '#description' => t('jQuery selector to define the page\'s content area on your Admin theme.'), + ); + + return system_settings_form($form); +} + +/** * Menu callback; displays a module's settings page. */ function system_settings_overview() { Index: modules/system/system.css =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.css,v retrieving revision 1.48 diff -u -p -r1.48 system.css --- modules/system/system.css 9 Jan 2008 09:56:39 -0000 1.48 +++ modules/system/system.css 20 Mar 2008 00:58:48 -0000 @@ -542,3 +542,80 @@ span.password-confirm { span.password-confirm span { font-weight: normal; } + +/* +** Popups Dialog box styles +*/ + +#popups-overlay { + position: absolute; +/* width: 100%; + height: 100%; */ + background: black; + z-index: 9; + top: 0; +} +#popups-loading { + z-index: 10; + opacity: 0.75; + position: relative; +} +#popups-loading div{ + position: absolute; +} +#popups { + border: 2px solid #EDF5FA; + background: white; + position: absolute; + opacity: 1.0; + z-index: 10; + color: black; + padding: 0.5em; + width: 600px; + overflow: auto; +} +#popups-title { + /*background: #222; + color: white; + */ + border-bottom: 1px solid #b4d7f0; + background-color: #d4e7f3; + color: #455067; + font-weight: bold; + padding: 0.25em; + margin-bottom: 0.25em; +} +#popups-title div.title { + float:left; +} +#popups-title #popups-close { + float:right; + line-height: 0pt; + margin-top: 2px; /* Trying for vertical centering */ +} +#popups-title #popups-close a { + color: red; +} +#popups-title div.clear { + clear: both; +} +#popups input { + margin: 0.1em; +} +#popups input[type="text"]:focus, #popups input[type="password"]:focus, #popups textarea:focus { + background-color: #FFA; + outline: thin solid grey; +} +#popups div.messages { + background: transparent; + border: none; + padding: 0; + margin: 0; +} + +a.popups-processed:after { + content: "[\2020]"; + vertical-align: super; + font-size: smaller; +} + Index: modules/system/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.module,v retrieving revision 1.593 diff -u -p -r1.593 system.module --- modules/system/system.module 11 Mar 2008 08:13:14 -0000 1.593 +++ modules/system/system.module 20 Mar 2008 00:58:49 -0000 @@ -149,6 +149,11 @@ function system_theme() { 'arguments' => array('image_path' => NULL), ), 'system_compact_link' => array(), + 'popup_template' => array( + 'template' => 'popup-template', + ), + 'popup_save_dialog' => array(), + )); } @@ -515,6 +520,20 @@ function system_menu() { 'type' => MENU_CALLBACK, 'file' => 'system.admin.inc', ); + + // Popups: + $items['admin/settings/popuppage'] = array( + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_popup_settings'), + 'title' => 'AJAX Popups', + 'description' => 'Configure the AJAX Popup behavior.', + 'file' => 'system.admin.inc', + ); + $items['popuppage/save_dialog'] = array( + 'page callback' => 'theme', + 'page arguments' => array('popup_save_dialog'), + 'access callback' => TRUE, + ); return $items; } @@ -1887,6 +1906,77 @@ function system_check_http_request() { } /** + * Implements hook_renderers. + * Provide default system renderers. + */ +function system_renderers() { + return array( + 'xhtml/plain' => 'system_render_default', + 'json/popup' => 'system_render_json_popup' + ); +} + +/** + * Defualt Drupal renderer. + * Use the theme system to render to xhtml, for consumption by browsers. + * + * @return + * Themed content. + */ +function system_render_default() { + $args = func_get_args(); + return call_user_func_array('theme', $args); +} + +/** + * Render the page as JSON, for consumption by AJAX calls. + * Optimized for AJAX popups. + * + * @return + * JSON object with metadata and themed page content. + */ +function system_render_json_popup() { + $args = func_get_args(); + $hook = array_shift($args); + switch ($hook) { + case 'page': // render('page', $content); + return drupal_json(array( + 'status' => 'ok', + 'title' => drupal_get_title(), + 'messages' => theme('status_messages'), + 'path' => $_GET['q'], + 'content' => $args[0], + )); + default: + return drupal_json(array( + 'status' => 'error', + 'messages' => "No way to render '$hook' in mode 'json/popup'", + )); + } +} + +/** + * Implements hook_after_process_form + */ +function system_after_process_form($request_mode, $form, $form_state) { + switch ($request_mode) { + case 'XMLHttpRequest': + // Request comes from jQuery AJAX call. + // Return status, next page url and form state as JSON. + $url = drupal_redirect_form($form, $form_state['redirect'], FALSE); + print drupal_json(array( + 'status' => 'redirect', + 'path' => $url, + 'form_state' => $form_state, + )); + exit; + case 'standard': + // Default Drupal behavior, redirect to the next page. + drupal_redirect_form($form, $form_state['redirect']); + } +} + +/** * Format the Powered by Drupal text. * * @ingroup themeable Index: modules/user/user.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.admin.inc,v retrieving revision 1.19 diff -u -p -r1.19 user.admin.inc --- modules/user/user.admin.inc 20 Feb 2008 13:46:43 -0000 1.19 +++ modules/user/user.admin.inc 20 Mar 2008 00:58:50 -0000 @@ -901,9 +901,16 @@ function user_admin_access() { $header = array(array('data' => t('Access type'), 'field' => 'status'), array('data' => t('Rule type'), 'field' => 'type'), array('data' => t('Mask'), 'field' => 'mask'), array('data' => t('Operations'), 'colspan' => 2)); $result = db_query("SELECT aid, type, status, mask FROM {access}". tablesort_sql($header)); $access_types = array('user' => t('username'), 'mail' => t('e-mail'), 'host' => t('host')); + drupal_add_popups(); $rows = array(); while ($rule = db_fetch_object($result)) { - $rows[] = array($rule->status ? t('allow') : t('deny'), $access_types[$rule->type], $rule->mask, l(t('edit'), 'admin/user/rules/edit/'. $rule->aid), l(t('delete'), 'admin/user/rules/delete/'. $rule->aid)); + $rows[] = array( + $rule->status ? t('allow') : t('deny'), + $access_types[$rule->type], + $rule->mask, + l(t('edit'), 'admin/user/rules/edit/'. $rule->aid), + l(t('delete'), 'admin/user/rules/delete/'. $rule->aid, array('attributes'=>array('class'=>'popup-form'))) + ); } if (empty($rows)) { $rows[] = array(array('data' => ''. t('There are currently no access rules.') .'', 'colspan' => 5));