Index: modules/system/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.module,v retrieving revision 1.594 diff -u -r1.594 system.module --- modules/system/system.module 1 Apr 2008 20:05:15 -0000 1.594 +++ modules/system/system.module 1 Apr 2008 20:43:19 -0000 @@ -149,6 +149,11 @@ 'arguments' => array('image_path' => NULL), ), 'system_compact_link' => array(), + 'popup_template' => array( + 'template' => 'popup-template', + ), + 'popup_save_dialog' => array(), + )); } @@ -632,6 +637,20 @@ 'type' => MENU_CALLBACK, 'file' => 'system.admin.inc', ); + + // AJAX popups: + $items['admin/settings/popup'] = 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['popup/save_dialog'] = array( + 'page callback' => 'theme', + 'page arguments' => array('popup_save_dialog'), + 'access callback' => TRUE, + ); return $items; } Index: modules/system/system.css =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.css,v retrieving revision 1.48 diff -u -r1.48 system.css --- modules/system/system.css 9 Jan 2008 09:56:39 -0000 1.48 +++ modules/system/system.css 1 Apr 2008 20:43:18 -0000 @@ -542,3 +542,81 @@ span.password-confirm span { font-weight: normal; } + +/* +** AJAX popup dialog box styles +*/ + +#popup-overlay { + position: absolute; +/* width: 100%; + height: 100%; */ + background: black; + z-index: 9; + top: 0; +} +#popup-loading { + z-index: 10; + opacity: 0.75; + position: relative; +} +#popup-loading div{ + position: absolute; +} +#popup { + border: 2px solid #EDF5FA; + background: white; + position: absolute; + opacity: 1.0; + z-index: 10; + color: black; + padding: 0.5em; + width: 600px; + overflow: auto; +} +#popup-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; +} +#popup-title div.title { + float:left; +} +#popup-title #popup-close { + float:right; + line-height: 0pt; + margin-top: 2px; /* Trying for vertical centering */ +} +#popup-title #popup-close a { + color: red; +} +#popup-title div.clear { + clear: both; +} +#popup input { + margin: 0.1em; +} +#popup input[type="text"]:focus, #popup input[type="password"]:focus, #popup textarea:focus { + background-color: #FFA; + outline: thin solid grey; +} +#popup div.messages { + background: transparent; + border: none; + padding: 0; + margin: 0; +} + +a.popup-processed:after { +/* TODO - Find a good icon + content: "[\2020]"; + vertical-align: super; + font-size: smaller; +*/ +} Index: modules/system/system.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v retrieving revision 1.66 diff -u -r1.66 system.admin.inc --- modules/system/system.admin.inc 23 Mar 2008 14:46:49 -0000 1.66 +++ modules/system/system.admin.inc 1 Apr 2008 20:43:18 -0000 @@ -116,6 +116,31 @@ } /** + * Todo - probably will be removed, if content area in themes is better specified. + * + * @return unknown + */ +function system_popup_settings() { + drupal_set_title("AJAX popup settings"); + $form = array(); + + $form['popup_title_selector'] = array( + '#type' => 'textfield', + '#title' => t('Title selector'), + '#default_value' => variable_get('popup_title_selector', 'div.left-corner > h2:eq(0)'), + '#description' => t("jQuery selector to define the page's title on your Admin theme."), + ); + $form['popup_content_selector'] = array( + '#type' => 'textfield', + '#title' => t('Content selector'), + '#default_value' => variable_get('popup_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/block/block.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/block/block.admin.inc,v retrieving revision 1.14 diff -u -r1.14 block.admin.inc --- modules/block/block.admin.inc 22 Dec 2007 23:24:24 -0000 1.14 +++ modules/block/block.admin.inc 1 Apr 2008 20:43:16 -0000 @@ -30,6 +30,7 @@ // Add CSS drupal_add_css(drupal_get_path('module', 'block') .'/block.css', 'module', 'all', FALSE); + drupal_add_popup(); // If non-default theme configuration has been selected, set the custom theme. $custom_theme = isset($theme) ? $theme : variable_get('theme_default', 'garland'); @@ -76,7 +77,7 @@ } $form[$key]['configure'] = array('#value' => l(t('configure'), 'admin/build/block/configure/'. $block['module'] .'/'. $block['delta'])); if ($block['module'] == 'block') { - $form[$key]['delete'] = array('#value' => l(t('delete'), 'admin/build/block/delete/'. $block['delta'])); + $form[$key]['delete'] = array('#value' => l(t('delete'), 'admin/build/block/delete/'. $block['delta'], array('attributes' => array('class' => 'popup-form')))); } } Index: includes/menu.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/menu.inc,v retrieving revision 1.267 diff -u -r1.267 menu.inc --- includes/menu.inc 21 Mar 2008 08:32:24 -0000 1.267 +++ includes/menu.inc 1 Apr 2008 20:43:15 -0000 @@ -1167,6 +1167,7 @@ // 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_popup(); $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.418 diff -u -r1.418 theme.inc --- includes/theme.inc 25 Mar 2008 14:10:01 -0000 1.418 +++ includes/theme.inc 1 Apr 2008 20:43:16 -0000 @@ -1449,7 +1449,7 @@ * Returns code that emits the 'more help'-link. */ function theme_more_help_link($url) { - 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/filter/filter.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/filter/filter.admin.inc,v retrieving revision 1.10 diff -u -r1.10 filter.admin.inc --- modules/filter/filter.admin.inc 19 Feb 2008 14:07:21 -0000 1.10 +++ modules/filter/filter.admin.inc 1 Apr 2008 20:43:16 -0000 @@ -159,7 +159,8 @@ // Composition tips (guidelines) $tips = _filter_tips($format->format, FALSE); - $extra = ''. l(t('More information about formatting options'), 'filter/tips') .'
'; + drupal_add_popup(); + $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/menu/menu.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/menu/menu.admin.inc,v retrieving revision 1.29 diff -u -r1.29 menu.admin.inc --- modules/menu/menu.admin.inc 23 Feb 2008 08:13:09 -0000 1.29 +++ modules/menu/menu.admin.inc 1 Apr 2008 20:43:17 -0000 @@ -61,6 +61,7 @@ */ function _menu_overview_tree_form($tree) { static $form = array('#tree' => TRUE); + drupal_add_popup(); foreach ($tree as $data) { $title = ''; $item = $data['link']; @@ -97,11 +98,11 @@ $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 -r1.50 content_types.inc --- modules/node/content_types.inc 27 Jan 2008 18:03:05 -0000 1.50 +++ modules/node/content_types.inc 1 Apr 2008 20:43:17 -0000 @@ -10,6 +10,7 @@ * Displays the content type admin overview page. */ function node_overview_types() { + drupal_add_popup(); $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 @@ // 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/user/user.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.admin.inc,v retrieving revision 1.19 diff -u -r1.19 user.admin.inc --- modules/user/user.admin.inc 20 Feb 2008 13:46:43 -0000 1.19 +++ modules/user/user.admin.inc 1 Apr 2008 20:43:20 -0000 @@ -901,9 +901,16 @@ $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_popup(); $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)); Index: misc/tableheader.js =================================================================== RCS file: /cvs/drupal/drupal/misc/tableheader.js,v retrieving revision 1.16 diff -u -r1.16 tableheader.js --- misc/tableheader.js 30 Jan 2008 10:17:39 -0000 1.16 +++ misc/tableheader.js 1 Apr 2008 20:43:16 -0000 @@ -12,6 +12,11 @@ return; } + // If there are no sticky tables in this context, just return. + if (!$('table.sticky-enabled', context).size()) { + return; + } + // Keep track of all cloned table headers. var headers = []; Index: modules/help/help.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/help/help.admin.inc,v retrieving revision 1.5 diff -u -r1.5 help.admin.inc --- modules/help/help.admin.inc 25 Nov 2007 11:11:17 -0000 1.5 +++ modules/help/help.admin.inc 1 Apr 2008 20:43:17 -0000 @@ -23,7 +23,7 @@ $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/path/path.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/path/path.admin.inc,v retrieving revision 1.7 diff -u -r1.7 path.admin.inc --- modules/path/path.admin.inc 8 Jan 2008 10:35:42 -0000 1.7 +++ modules/path/path.admin.inc 1 Apr 2008 20:43:17 -0000 @@ -41,7 +41,12 @@ $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: misc/popup.js =================================================================== RCS file: misc/popup.js diff -N misc/popup.js --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ misc/popup.js 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,464 @@ +// $Id:$ + +/** + * Popup Modal Dialog API + * + * Provide an API for building and displaying JavaScript, in-page, popup modal dialogs. + * Modality is provided by a fixed, semi-opaque div, positioned in front of the page contents. + * + */ + +/** + * Attach the popup bevior to the all the requested links on the page. + * + * @param context + * The jQuery object to apply the behaviors to. + */ +Drupal.behaviors.popup = function(context) { + var $body = $('body'); + if(!$body.hasClass('popup-processed')) { + $(document).bind('keydown', Drupal.popup.keyHandle); + $body.addClass('popup-processed'); + } + Drupal.popup.attach(context, 'a.popup', {}); + Drupal.popup.attach(context, 'a.popup-form', {updatePage: true}); + Drupal.popup.attach(context, 'a.popup-nonmodal', {nonModal: true}); +}; + +/** + * Create the popup object/namespace. + */ +Drupal.popup = function() {}; + +/** + * Attach the popup behavior to a particular link. + * + * @param selector + * jQuery selector for links to attach popup behavior to. + * @param options + * Hash of options associated with these links. + */ +Drupal.popup.attach = function(context, selector, options) { + $(selector, context).not('.popup-processed').each( function() { + var $link = $(this); + $link.click( function(e){ + var a = this; + // If the option is distructive, check if the page is already modified, and offer to save. + var pageIsDirty = $('span.tabledrag-changed').size() > 0; + var willModifyOriginal = options.updatePage; + if( pageIsDirty && willModifyOriginal ) { + // The user will lose modifications, so popup dialog offering to save current state. + $.getJSON(Drupal.settings.basePath + 'popup/save_dialog', function(json) { + // Attach behaviors to the buttons in the save-if-modified dialog. + var buttons = { + 'popups_save': {title: json.buttons.save, func: function(){Drupal.popup.savePage(a, options);}}, + 'popups_submit': {title: json.buttons.submit, func: function(){Drupal.popup.removePopup(); Drupal.popup.openPath(a, options);}}, + 'popups_cancel': {title: json.buttons.cancel, func: Drupal.popup.close} + }; + Drupal.popup.open(json.title, json.content, buttons); + }); + return false; + } + else { + return Drupal.popup.openPath(a, options); + } + }); + var title = $link.attr('title') || ''; + $link.attr('title', title + Drupal.t('[Popup]')); // Append note to link title. + $link.addClass('popup-processed'); + }); +}; + + +/** + * Generic dialog builder. + */ +Drupal.popup.open = function(title, body, buttons) { + + Drupal.popup.addOverlay(); // TODO - nonModal option. + var $popup = $(Drupal.theme('popupsDialog', title, body, buttons)); + // Start with dialog off the side. Making it invisible causes flash in FF2. + $popup.css('left', -9999); + $('body').append( $popup ); // Add the popup to the DOM. + + // Adding button functions + if (buttons) { + for (var id in buttons) { + if (buttons[id]) { // to make jslint happy. + var func = buttons[id].func; + $('#'+id).click( func ); + } + } + } + $('#popup-close').click( Drupal.popup.close ); + + // center on the screen, adding in offsets if the window has been scrolled + var popupWidth = $popup.width(); + var windowWidth = $(window).width(); + var left = (windowWidth / 2) - (popupWidth / 2) + Drupal.popup.scrollLeft(); + + // Get popup's height on the page. + // Causes flash in FF2 if popup is not visible! + var popupHeight = $popup.height(); + var windowHeight = $(window).height(); + if (popupHeight > (0.9 * windowHeight) ) { // Must fit in 90% of window. + popupHeight = 0.9 * windowHeight; + $popup.height(popupHeight); + } + var top = (windowHeight / 2) - (popupHeight / 2) + Drupal.popup.scrollTop(); + + $popup.css('top', top).css('left', left); // Position the popup to be visible. + + this.refocus(); // TODO: capture the focus when it leaves the dialog. + Drupal.popup.removeLoading(); // Remove the loading img. + + return false; +}; + +/** + * Simple popup that functions like the browser's alert box. + */ +Drupal.popup.message = function(message, body) { + body = body || ''; + var buttons = { + 'popups_ok': { title: Drupal.t('OK'), func: Drupal.popup.close } + }; + Drupal.popup.open( message, body, buttons ); +}; + +/** + * Handle any special keys when popup is active. + */ +Drupal.popup.keyHandle = function(e) { + if (!e) { + e = window.event; + } + switch (e.keyCode) { + case 27: // esc + Drupal.popup.close(); + break; + case 191: // '?' key, show help. + if (e.shiftKey && e.ctrlKey) { + var $help = $('a.popup.more-help'); + if ($help.size()) { + $help.click(); + } + else { + Drupal.popup.message(Drupal.t("Sorry, there is no additional help for this page")); + } + } + break; + } +}; + +/***************************************************************************** + * Appearence Functions (overlay, loading graphic, remove popup) ********* + *****************************************************************************/ + +Drupal.popup.removePopup = function() { + $('#popup').fadeOut('fast', function() { + $('#popup').remove(); + }); +}; + +Drupal.popup.addOverlay = function() { + var $overlay = $('#popup-overlay'); + if (!$overlay.size()) { // Overlay does not already exist, so create it. + $overlay = $(Drupal.theme('popupsOverlay')); + $overlay.css('opacity', '0.4'); // for ie6(?) + $body = $('body'); + // Doing absolute positioning, so make overlay's size equal the entire body. + $overlay.width($body.width()).height($body.height()); + $overlay.click(Drupal.popup.close); + $body.prepend($overlay); + } +// return $overlay; +}; + +//Drupal.popup.getOverlay = function() { +// return $('#popup-overlay'); +//}; + +Drupal.popup.removeOverlay = function() { + $('#popup-overlay').fadeOut('fast', function() { + $('#popup-overlay').remove(); + }); +}; + +Drupal.popup.addLoading = function() { + var $loading = $('#popup-loading'); + if (!$loading.size()) { // Overlay does not already exist, so create it. + var waitImageSize = 100; + var left = ($(window).width() / 2) - (waitImageSize / 2) + Drupal.popup.scrollLeft(); + var top = ($(window).height() / 2) - (waitImageSize / 2) + Drupal.popup.scrollTop(); + $loading = $( Drupal.theme('popupsLoading', left, top) ); + $('body').prepend($loading); + } +}; + +Drupal.popup.removeLoading = function() { + $('#popup-loading').remove(); +}; + +/** + * Remove everything. + */ +Drupal.popup.close = function() { + Drupal.popup.removePopup(); + Drupal.popup.removeLoading(); + Drupal.popup.removeOverlay(); +}; + +/** + * Set the focus on the popup to the first visible form element, or the first button, or the close link. + */ +Drupal.popup.refocus = function() { + $focus = $('#popup input:visible:eq(0)'); + if (!focus) { + $focus = $('#popup-close'); // Doesn't seem to work. + } + $focus.focus(); +}; + +/**************************************************************************** + * Theme Functions ******************************************************** + ****************************************************************************/ + +Drupal.theme.prototype.popupsLoading = function(left, top) { + var loading = '