diff -upNr ./misc/tableheader.js ../d7overlay/misc/tableheader.js --- ./misc/tableheader.js 2009-09-20 14:14:40.000000000 -0500 +++ ../d7overlay/misc/tableheader.js 2009-10-08 08:29:08.216747146 -0500 @@ -18,8 +18,9 @@ Drupal.behaviors.tableHeader = { var headers = []; $('table.sticky-enabled thead', context).once('tableheader', function () { - // Clone thead so it inherits original jQuery properties. - var headerClone = $(this).clone(true).insertBefore(this.parentNode).wrap('').parent().css({ + // Clone thead so it inherits original jQuery properties. Hide the table + // to avoid a flash of the header clone upon page load. + var headerClone = $(this).clone(true).hide().insertBefore(this.parentNode).wrap('').parent().css({ position: 'fixed', top: '0px' }); @@ -32,6 +33,9 @@ Drupal.behaviors.tableHeader = { headerClone.table = table; // Finish initializing header positioning. tracker(headerClone); + // We hid the header to avoid it showing up erroneously on page load; + // we need to unhide it now so that it will show up when expected. + $(headerClone).children('thead').show(); $(table).addClass('sticky-table'); }); diff -upNr ./modules/locale/locale.test ../d7overlay/modules/locale/locale.test --- ./modules/locale/locale.test 2009-09-28 17:14:30.000000000 -0500 +++ ../d7overlay/modules/locale/locale.test 2009-10-08 08:29:08.216747146 -0500 @@ -236,7 +236,7 @@ class LocaleTranslationFunctionalTest ex $this->clickLink(t('edit')); // We save the lid from the path. $matches = array(); - preg_match('!admin/config/regional/translate/edit/(\d)+!', $this->getUrl(), $matches); + preg_match('!admin/config/regional/translate/edit/(\d+)!', $this->getUrl(), $matches); $lid = $matches[1]; // No t() here, it's surely not translated yet. $this->assertText($name, t('name found on edit screen.')); diff -upNr ./modules/node/node.admin.inc ../d7overlay/modules/node/node.admin.inc --- ./modules/node/node.admin.inc 2009-09-17 19:12:47.000000000 -0500 +++ ../d7overlay/modules/node/node.admin.inc 2009-10-08 08:35:16.776750171 -0500 @@ -447,6 +447,9 @@ function node_admin_nodes() { foreach ($result as $node) { $nodes[$node->nid] = ''; $options = empty($node->language) ? array() : array('language' => $languages[$node->language]); + // Set a class to flag to the overlay, if present, not to open the link in + // the overlay. + $options['attributes']['class'] = 'overlay-escape'; $form['title'][$node->nid] = array('#markup' => l($node->title, 'node/' . $node->nid, $options) . ' ' . theme('mark', node_mark($node->nid, $node->changed))); $form['name'][$node->nid] = array('#markup' => check_plain(node_type_get_name($node))); $form['username'][$node->nid] = array('#markup' => theme('username', $node)); diff -upNr ./modules/overlay/overlay.api.php ../d7overlay/modules/overlay/overlay.api.php --- ./modules/overlay/overlay.api.php 1969-12-31 18:00:00.000000000 -0600 +++ ../d7overlay/modules/overlay/overlay.api.php 2009-10-08 08:29:08.216747146 -0500 @@ -0,0 +1,54 @@ + -1 ? '&' : '?') + 'render=overlay' + fragment; + $(this).attr('href', href); + } + else { + $(this).attr('target', '_new'); + } + }); + $('form:not(.overlay-processed)', context).addClass('overlay-processed').each(function() { + // Obtain the action attribute of the form. + var action = $(this).attr('action'); + if (action.indexOf('http') != 0 && action.indexOf('https') != 0) { + // Keep internal forms in the overlay. + action += (action.indexOf('?') > -1 ? '&' : '?') + 'render=overlay'; + $(this).attr('action', action); + } + else { + $(this).attr('target', '_new'); + } + }); +}; + +})(jQuery); diff -upNr ./modules/overlay/overlay.info ../d7overlay/modules/overlay/overlay.info --- ./modules/overlay/overlay.info 2009-09-16 18:55:40.000000000 -0500 +++ ../d7overlay/modules/overlay/overlay.info 2009-10-08 08:29:08.216747146 -0500 @@ -0,0 +1,7 @@ +; $Id$ +name = Overlay +description = Displays the Drupal administration interface in an overlay. +package = Core +version = VERSION +core = 7.x +files[] = overlay.module diff -upNr ./modules/overlay/overlay.module ../d7overlay/modules/overlay/overlay.module --- ./modules/overlay/overlay.module 1969-12-31 18:00:00.000000000 -0600 +++ ../d7overlay/modules/overlay/overlay.module 2009-10-08 08:29:08.216747146 -0500 @@ -0,0 +1,302 @@ + 'Overlay: Parent', + 'website' => 'http://drupal.org/node/517688', + 'version' => '1.0', + 'js' => array( + $module_path . '/overlay-parent.js' => array(), + ), + 'css' => array( + $module_path . '/overlay-parent.css' => array(), + ), + 'dependencies' => array( + array('system', 'ui.dialog'), + ), + ); + // Overlay child. + $libraries['child'] = array( + 'title' => 'Overlay: Child', + 'website' => 'http://drupal.org/node/517688', + 'version' => '1.0', + 'js' => array( + $module_path . '/overlay-child.js' => array(), + ), + 'dependencies' => array( + array('system', 'ui'), + ), + ); + + return $libraries; +} + +/** + * Implement hook_drupal_goto_alter(). + */ +function overlay_drupal_goto_alter(&$args) { + if (overlay_mode() == 'child') { + if (!empty($args['query'])) { + if (is_array($args['query'])) { + // Query is an array, add our marker as a key. + $args['query']['render'] = 'overlay'; + } + else { + // Query is not an array, add our marker as string. + $args['query'] .= '&render=overlay'; + } + } + else { + $args['query'] = array('render' => 'overlay'); + } + } +} + +/** + * Implement hook_block_info_alter(). + */ +function overlay_block_info_alter(&$blocks) { + global $custom_theme; + + if (!empty($custom_theme) && overlay_mode() == 'child') { + $themes = list_themes(); + $theme = $themes[$custom_theme]; + if (!empty($theme->info['overlay_regions'])) { + // Don't show any blocks except the main page content and the help text if + // we're in the overlay. + foreach ($blocks as $bid => $block) { + if (!in_array($block->region, $theme->info['overlay_regions'])) { + unset($blocks[$bid]); + } + } + } + } +} + +/** + * Implement hook_system_info_alter(). + * + * Add default regions for overlay. + */ +function overlay_system_info_alter(&$info, $file) { + $info['overlay_regions'][] = 'content'; + $info['overlay_regions'][] = 'help'; +} + +/** + * Preprocess template variables for html.tpl.php. + */ +function overlay_preprocess_html(&$variables) { + if (overlay_mode() == 'child') { + // Add overlay class, so themes can react to being displayed in the overlay. + $variables['classes_array'][] = 'overlay'; + // Do not include site name or slogan in the overlay title. + $variables['head_title'] = drupal_get_title(); + } +} + +/** + * Preprocess template variables for page.tpl.php. + */ +function overlay_preprocess_page(&$variables) { + if (overlay_mode() == 'child') { + // Remove 'Home' from the breadcrumbs. + $overlay_breadcrumb = drupal_get_breadcrumb(); + array_shift($overlay_breadcrumb); + $variables['breadcrumb'] = theme('breadcrumb', $overlay_breadcrumb); + } +} + +/** + * Form after build callback. + * + * After all ook_form_alter() implementations have been processed, we look at + * the list of submit handler and add our own at the end, so we can affect the + * redirection done at the end of the form processing if we are in the overlay + * children. + * + * @see _form_builder_handle_input_element() + * @see _form_builder_ie_cleanup() + * @see form_execute_handlers() + * @see form_builder() + * + * @ingroup forms + */ +function overlay_form_after_build($form, &$form_state) { + if (isset($_GET['render']) && $_GET['render'] == 'overlay') { + // Form API may have already captured submit handlers from the submitted + // button before after_build callback is invoked. This may have been done + // by _form_builder_handle_input_element(). + // If so, the list of submit handlers is stored in the $form_state array + // which is something we can also alter from here, luckily. + // Rememeber: our goal here is set $form_state['redirect'] is set to FALSE + // if the API overlay_close_dialog() has been invoked. That's because we + // want to tell the parent window to close the overlay. + if (!empty($form_state['submit_handlers']) && !in_array('overlay_form_submit', $form_state['submit_handlers'])) { + $form_state['submit_handlers'][] = 'overlay_form_submit'; + } + // If this element has submit handlers, then append our own. + if (isset($form['#submit'])) { + $form['#submit'][] = 'overlay_form_submit'; + } + } + return $form; +} + +/** + * Generic form submit handler. + * + * When we are requested to close an overlay, we don't want Form API to + * perform any redirection once the submitted form has been processed. + * + * When $form_state['redirect'] is set to FALSE, then Form API will simply + * re-render the form with the values still in its fields. And this is all + * we need to output the JavaScript that will tell the parent window to close + * the child dialog. + * + * @ingroup forms + */ +function overlay_form_submit($form, &$form_state) { + $settings = &drupal_static(__FUNCTION__); + + // Check if we have a request to close the overlay. + $args = overlay_close_dialog(); + + // Make sure the overlay is closed when a node edit form has been submitted + // in child mode. + if ($args === FALSE && overlay_mode() == 'child' && !empty($form['#node_edit_form'])) { + $args = overlay_close_dialog(TRUE); + } + + // Close the overlay only if specifically requested. + if ($args !== FALSE) { + if (!isset($settings)) { + $settings = array( + 'overlayChild' => array( + 'closeOverlay' => TRUE, + 'statusMessages' => theme('status_messages'), + 'args' => $args, + ), + ); + // Tell the child window to perform the redirection when requested to. + if (!empty($form_state['redirect'])) { + $settings['overlayChild']['redirect'] = url($form_state['redirect']); + } + drupal_add_js($settings, array('type' => 'setting')); + } + // Tell FAPI to redraw the form without redirection after all submit + // callbacks have been processed. + $form_state['redirect'] = FALSE; + } +} + +/** + * Set overlay mode and add proper JavaScript and styles to the page. + * + * @param $mode + * To set the mode, pass in either 'parent' or 'child'. 'parent' is used in + * the context of a parent overlay window, where the overlay may appear, and + * JavaScript is added accordingly to present an overlay dialog. 'child' is + * used in the context of the child overlay window, the one actually appearing + * within the overlay, and certain JavaScript and CSS is added so that Drupal + * behaves nicely from within the overlay. This parameter is optional, and if + * omitted, the current mode will be returned with no action taken. + * @return + * The current mode, if any has been set, or NULL if no mode has been set. + * @ingroup overlay_api + */ +function overlay_mode($mode = NULL) { + global $base_path; + $overlay_mode = &drupal_static(__FUNCTION__); + + // Make sure external resources are not included more than once. Also return + // current mode, if no mode was specified. + if (isset($overlay_mode) || !isset($mode)) { + return $overlay_mode; + } + $overlay_mode = $mode; + + switch ($overlay_mode) { + case 'parent': + drupal_add_library('overlay', 'parent'); + + // Allow modules to act upon overlay events. + module_invoke_all('overlay_parent_initialize'); + break; + + case 'child': + drupal_add_library('overlay', 'child'); + + // Allow modules to act upon overlay events. + module_invoke_all('overlay_child_initialize'); + break; + } + return $overlay_mode; +} + +/** + * Callback to close the overlay dialog. + * + * @param $set + * If set, will set the current close dialog mode to the given state. + * Use FALSE to disable close dialog mode. Otherwise, the argument will + * be forwarded to the onOverlayClose callback of the overlay. + * @return + * The current overlay close dialog mode, TRUE if the overlay should close or + * FALSE if it should not (default). + */ +function overlay_close_dialog($set = NULL) { + $close = &drupal_static(__FUNCTION__, FALSE); + if (isset($set)) { + $close = $set; + } + return $close; +} diff -upNr ./modules/overlay/overlay-parent.css ../d7overlay/modules/overlay/overlay-parent.css --- ./modules/overlay/overlay-parent.css 1969-12-31 18:00:00.000000000 -0600 +++ ../d7overlay/modules/overlay/overlay-parent.css 2009-10-08 08:29:08.216747146 -0500 @@ -0,0 +1,120 @@ +/* $Id$ */ + +/** + * ui-dialog overlay. + */ +.ui-widget-overlay { + background-color: #000; + opacity: 0.7; + filter: alpha(opacity=80); + background-image: none; +} + +/** + * jQuery UI Dialog classes. + */ +.overlay { + padding-right: 26px; +} + +.overlay.ui-widget-content, .overlay .ui-widget-header { + background: none; + border: none; +} + +.overlay .ui-dialog-titlebar { + white-space: nowrap; + padding: 0 20px; +} + +.overlay .ui-dialog-title { + font-family: Verdana,sans-serif; + margin: 0; + padding: 0.3em 0; + color: #fff; + font-size: 20px; +} +.overlay .ui-dialog-title:active, +.overlay .ui-dialog-title:focus { + outline: 0; +} +.overlay .ui-dialog-titlebar-close, +.overlay .ui-dialog-titlebar-close:hover { + display: block; + right: -25px; + top: 100%; + margin: 0; + border: none; + padding: 0; + width: 26px; + height: 36px; + background: transparent url(images/close.png) no-repeat; + -moz-border-radius-topleft: 0; +} +.overlay .ui-dialog-titlebar-close span { + display: none; +} +.overlay .ui-dialog-content { + color: #292929; + background-color: #f8f8f8; +} + +/** + * Overlay content and shadows. + */ +.overlay #overlay-container { + margin: 0; + padding: 0; + overflow: visible; + background: #fff url(images/loading.gif) no-repeat 50% 50%; + -webkit-box-shadow: 8px 8px 8px rgba(0,0,0,.5); + -moz-box-shadow: 8px 8px 8px rgba(0,0,0,.5); + box-shadow: 8px 8px 8px rgba(0,0,0,.5); +} +.overlay #overlay-element { + overflow: hidden; +} + +/** + * Tabs on the overlay. + */ +.overlay .ui-dialog-titlebar ul { + position: absolute; + right: 20px; + bottom: 0; + margin: 0; + line-height: 2.2em; + text-transform: uppercase; +} +.overlay .ui-dialog-titlebar ul li { + display: inline-block; + list-style: none; + margin: 0 0 0 -3px; + padding: 0; +} +.overlay .ui-dialog-titlebar ul li a, +.overlay .ui-dialog-titlebar ul li a:active, +.overlay .ui-dialog-titlebar ul li a:visited, +.overlay .ui-dialog-titlebar ul li a:hover { + background-color: #a6a7a2; + -moz-border-radius: 8px 8px 0 0; + -webkit-border-top-left-radius: 8px; + -webkit-border-top-right-radius: 8px; + border-radius: 8px 8px 0 0; + color: #000; + font-weight: bold; + padding: 0.5em 1.5em; + text-decoration: none; +} +.overlay .ui-dialog-titlebar ul li.active a, +.overlay .ui-dialog-titlebar ul li.active a.active, +.overlay .ui-dialog-titlebar ul li.active a:active, +.overlay .ui-dialog-titlebar ul li.active a:visited { + background-color: #fff; +} +.overlay .ui-dialog-titlebar ul li a:hover { + color: #fff; +} +.overlay .ui-dialog-titlebar ul li.active a:hover { + color: #000; +} diff -upNr ./modules/overlay/overlay-parent.js ../d7overlay/modules/overlay/overlay-parent.js --- ./modules/overlay/overlay-parent.js 1969-12-31 18:00:00.000000000 -0600 +++ ../d7overlay/modules/overlay/overlay-parent.js 2009-10-08 08:29:08.216747146 -0500 @@ -0,0 +1,651 @@ +// $Id: parent.js,v 1.1.4.4 2009/06/19 15:32:57 markuspetrux Exp $ + +(function ($) { + +/** + * Open or modify overlay based on clicks of links marked with .to-overlay. + */ +Drupal.behaviors.overlayParent = { + attach: function(context, settings) { + // Attach on the .to-overlay class. + $('a.to-overlay:not(.overlay-exclude)').once('overlay').click(function() { +// @todo Toolbar. + // Remove the active class from where it was, and add the active class to + // this link, so the button keeps highlighting where we are. Only + // highlight active items in the shortcuts bar. + $('#toolbar a').each(function() { + $(this).removeClass('active'); + }); + if ($(this).parents('div.toolbar-shortcuts').length) { + $(this).addClass('active'); + } + + // Append render variable, so the server side can choose the right + // rendering and add child modal frame code to the page if needed. + this.search += (!this.search.length ? '?' : '&') + 'render=overlay'; + var linkURL = $(this).attr('href'); + + // If the modal frame is already open, replace the loaded document with + // this new one. Keeps browser history. + if (Drupal.overlay.isOpen) { + Drupal.overlay.load(linkURL); + return false; + } + + // There is overlay opened yet, we should open a new one. +// @todo Toolbar? Toolbar doesn't belong in here. Please stop doing such stuff. + var toolbarHeight = $('#toolbar').height(); + var overlayOptions = { + url: linkURL, +// @todo What is 40? + width: $(window).width() - 40, + height: $(window).height() - 40 - toolbarHeight, + // Remove active class from all header buttons. + onOverlayClose: function() { + $('#toolbar a').each(function() { + $(this).removeClass('active'); + }); + }, + draggable: false + }; + Drupal.overlay.open(overlayOptions); + + // Set position and styling to let the admin toolbar work. + $('.overlay').css('top', toolbarHeight + 20); + + // Prevent default action of the link click event. + return false; + }); + } +}; + +/** + * Overlay object for parent windows. + */ +Drupal.overlay = Drupal.overlay || { + options: {}, + iframe: { $container: null, $element: null }, + isOpen: false +}; + +/** + * Open an overlay. + * + * Ensure that only one overlay is opened ever. Use Drupal.overlay.load() if + * the overlay is already open but a new page needs to be opened. + * + * @param options + * Properties of the overlay to open: + * - url: the URL of the page to open in the overlay. + * - width: width of the overlay in pixels. + * - height: height of the overlay in pixels. + * - autoFit: boolean indicating whether the overlay should be resized to + * fit the contents of the document loaded. + * - onOverlayOpen: callback to invoke when the overlay is opened. + * - onOverlayCanClose: callback to allow external scripts decide if the + * overlay can be closed. + * - onOverlayClose: callback to invoke when the overlay is closed. + * - customDialogOptions: an object with custom jQuery UI Dialog options. + * + * @return + * If the overlay was opened true, otherwise false. + */ +Drupal.overlay.open = function(options) { + var self = this; + + // Just one overlay is allowed. + if (self.isOpen || $('#overlay-container').size()) { + return false; + } + + var defaultOptions = { + url: options.url, + width: options.width, + height: options.height, + autoFit: (options.autoFit == undefined || options.autoFit), + onOverlayOpen: options.onOverlayOpen, + onOverlayCanClose: options.onOverlayCanClose, + onOverlayClose: options.onOverlayClose, + customDialogOptions: options.customDialogOptions || {} + } + + self.options = $.extend(defaultOptions, options); + + // Create the dialog and related DOM elements. + self.create(); + + // Open the dialog offscreen where we can set its size, etc. + self.iframe.$container.dialog('option', { position: ['-999em', '-999em'] }).dialog('open'); + + return true; +}; + +/** + * Create the underlying markup and behaviors for the overlay. + * + * Reuses jQuery UI's dialog component to construct the overlay markup and + * behaviors, sanitizing the options previously set in self.options. + */ +Drupal.overlay.create = function() { + var self = this; + + // Note: We use scrolling="yes" for IE as a workaround to yet another IE bug + // where the horizontal scrollbar is always rendered no matter how wide the + // iframe element is defined. + self.iframe.$element = $('