Index: includes/batch.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/batch.inc,v retrieving revision 1.42 diff -u -r1.42 batch.inc --- includes/batch.inc 15 Oct 2009 16:18:44 -0000 1.42 +++ includes/batch.inc 17 Oct 2009 17:14:30 -0000 @@ -109,11 +109,20 @@ $current_set = _batch_current_set(); drupal_set_title($current_set['title'], PASS_THROUGH); + // Add ?id=x to the batch URL. + $url_options = $batch['url_options']; + if (isset($url_options['query'])) { + $url_options['query']['id'] = $batch['id']; + } + else { + $url_options['query'] = array('id' => $batch['id']); + } + $js_setting = array( 'batch' => array( 'errorMessage' => $current_set['error_message'] . '
' . $batch['error_message'], 'initMessage' => $current_set['init_message'], - 'uri' => url($batch['url'], array('query' => array('id' => $batch['id']))), + 'uri' => url($batch['url'], $url_options), ), ); drupal_add_js($js_setting, 'setting'); @@ -189,7 +198,17 @@ ob_end_clean(); } - $url = url($batch['url'], array('query' => array('id' => $batch['id'], 'op' => $new_op))); + // Add ?id=x&op=y to the batch URL. + $url_options = $batch['url_options']; + if (isset($url_options['query'])) { + $url_options['query']['id'] = $batch['id']; + $url_options['query']['op'] = $new_op; + } + else { + $url_options['query'] = array('id' => $batch['id'], 'op' => $new_op); + } + + $url = url($batch['url'], $batch['url_options']); drupal_add_html_head(''); return theme('progress_bar', array('percent' => $percentage, 'message' => $message)); Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.386 diff -u -r1.386 form.inc --- includes/form.inc 16 Oct 2009 19:20:34 -0000 1.386 +++ includes/form.inc 17 Oct 2009 17:15:15 -0000 @@ -3050,7 +3050,7 @@ $process_info = array( 'current_set' => 0, 'progressive' => TRUE, - 'url' => $url, + 'url_options' => array(), 'source_page' => $_GET['q'], 'redirect' => $redirect, 'theme' => $GLOBALS['theme_key'], Index: misc/drupal.js =================================================================== RCS file: /cvs/drupal/drupal/misc/drupal.js,v retrieving revision 1.58 diff -u -r1.58 drupal.js --- misc/drupal.js 31 Aug 2009 05:51:07 -0000 1.58 +++ misc/drupal.js 17 Oct 2009 17:17:19 -0000 @@ -344,4 +344,11 @@ } }; + /** + * Check if the given variable is an object. + */ + Drupal.isObject = function(something) { + return (something !== null && typeof something === 'object'); + }; + })(jQuery); Index: misc/tableheader.js =================================================================== RCS file: /cvs/drupal/drupal/misc/tableheader.js,v retrieving revision 1.27 diff -u -r1.27 tableheader.js --- misc/tableheader.js 20 Sep 2009 19:14:40 -0000 1.27 +++ misc/tableheader.js 17 Oct 2009 17:19:25 -0000 @@ -18,8 +18,9 @@ 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 the table header 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 @@ 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'); }); Index: modules/dashboard/dashboard.css =================================================================== RCS file: /cvs/drupal/drupal/modules/dashboard/dashboard.css,v retrieving revision 1.2 diff -u -r1.2 dashboard.css --- modules/dashboard/dashboard.css 18 Oct 2009 11:20:26 -0000 1.2 +++ modules/dashboard/dashboard.css 18 Oct 2009 13:38:34 -0000 @@ -64,9 +64,9 @@ border: 0; } -#dashboard .canvas-content input { - float: right; - margin: 0 0 0 10px; +#dashboard .canvas-content a.button { + color: #5a5a5a; + text-decoration: none; } #dashboard .region { Index: modules/dashboard/dashboard.js =================================================================== RCS file: /cvs/drupal/drupal/modules/dashboard/dashboard.js,v retrieving revision 1.2 diff -u -r1.2 dashboard.js --- modules/dashboard/dashboard.js 18 Oct 2009 11:20:26 -0000 1.2 +++ modules/dashboard/dashboard.js 18 Oct 2009 13:40:03 -0000 @@ -65,7 +65,7 @@ * Helper for enterCustomizeMode; sets up drag-and-drop and close button. */ setupDrawer: function () { - $('div.customize .canvas-content').prepend(''); + $('div.customize .canvas-content').prepend('' + Drupal.t('Done') + ''); $('div.customize .canvas-content input').click(Drupal.behaviors.dashboard.exitCustomizeMode); // Initialize drag-and-drop. Index: modules/locale/locale.test =================================================================== RCS file: /cvs/drupal/drupal/modules/locale/locale.test,v retrieving revision 1.48 diff -u -r1.48 locale.test --- modules/locale/locale.test 17 Oct 2009 05:50:28 -0000 1.48 +++ modules/locale/locale.test 17 Oct 2009 17:22:02 -0000 @@ -237,7 +237,7 @@ $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.')); Index: modules/toolbar/toolbar.css =================================================================== RCS file: /cvs/drupal/drupal/modules/toolbar/toolbar.css,v retrieving revision 1.6 diff -u -r1.6 toolbar.css --- modules/toolbar/toolbar.css 18 Oct 2009 12:06:06 -0000 1.6 +++ modules/toolbar/toolbar.css 18 Oct 2009 13:42:33 -0000 @@ -36,7 +36,7 @@ left: 0; right: 0; top: 0; - z-index: 100; + z-index: 600; } div#toolbar .collapsed { Index: modules/toolbar/toolbar.js =================================================================== RCS file: /cvs/drupal/drupal/modules/toolbar/toolbar.js,v retrieving revision 1.7 diff -u -r1.7 toolbar.js --- modules/toolbar/toolbar.js 17 Oct 2009 00:51:53 -0000 1.7 +++ modules/toolbar/toolbar.js 17 Oct 2009 18:24:56 -0000 @@ -15,6 +15,16 @@ Drupal.admin.toolbar.toggle(); return false; }); + + // Set the most recently clicked item as active. + $('#toolbar a').once().click(function() { + $('#toolbar a').each(function() { + $(this).removeClass('active'); + }); + if ($(this).parents('div.toolbar-shortcuts').length) { + $(this).addClass('active'); + } + }); } }; Index: modules/toolbar/toolbar.module =================================================================== RCS file: /cvs/drupal/drupal/modules/toolbar/toolbar.module,v retrieving revision 1.14 diff -u -r1.14 toolbar.module --- modules/toolbar/toolbar.module 17 Oct 2009 00:51:53 -0000 1.14 +++ modules/toolbar/toolbar.module 17 Oct 2009 18:29:39 -0000 @@ -36,13 +36,30 @@ * Add admin toolbar to the page_top region automatically. */ function toolbar_page_build(&$page) { - if (user_access('access toolbar')) { + if (user_access('access toolbar') && toolbar_enabled()) { $page['page_top']['toolbar'] = toolbar_build(); $page['page_top']['toolbar']['toolbar_drawer'] = isset($page['toolbar_drawer']) ? $page['toolbar_drawer'] : array(); } } /** + * Enable or disable the toolbar, or find out the current status of the toolbar. + * + * @param $enabled + * If given, will change the display mode of the toolbar to the given + * boolean. + * @return + * The current status of the toolbar, TRUE for enabled, FALSE for disabled. + */ +function toolbar_enabled($enabled = NULL) { + $setting = &drupal_static(__FUNCTION__, TRUE); + if (isset($enabled)) { + $setting = $enabled; + } + return $setting; +} + +/** * Implement hook_preprocess_html(). * * Add some page classes, so global page theming can adjust to the toolbar. @@ -53,6 +70,10 @@ } } +function template_preprocess_toolbar(&$variables) { + $variables['classes_array'][] = 'clearfix'; +} + /** * Build the admin menu as a structured array ready for drupal_render(). */ @@ -180,3 +201,12 @@ } return in_array($path, $active_paths); } + +/** + * Implement hook_overlay_child_initialize(). + */ +function toolbar_overlay_child_initialize() { + // Disable admin toolbar, which is something child windows don't need and + // shouldn't have. + toolbar_enabled(FALSE); +} Index: modules/toolbar/toolbar.tpl.php =================================================================== RCS file: /cvs/drupal/drupal/modules/toolbar/toolbar.tpl.php,v retrieving revision 1.5 diff -u -r1.5 toolbar.tpl.php --- modules/toolbar/toolbar.tpl.php 17 Oct 2009 00:51:53 -0000 1.5 +++ modules/toolbar/toolbar.tpl.php 17 Oct 2009 18:31:07 -0000 @@ -6,15 +6,17 @@ * Default template for admin toolbar. * * Available variables: + * - $classes: Classes for the toolbar div element. Can be + * manipulated in preprocess functions via $variables['classes_array']. * - $toolbar['toolbar_user']: User account / logout links. * - $toolbar['toolbar_menu']: Top level management menu links. * - $toolbar['toolbar_drawer']: A place for extended toolbar content. * * @see template_preprocess() - * @see template_preprocess_admin_toolbar() + * @see template_preprocess_toolbar() */ ?> -
+
Index: profiles/default/default.info =================================================================== RCS file: /cvs/drupal/drupal/profiles/default/default.info,v retrieving revision 1.6 diff -u -r1.6 default.info --- profiles/default/default.info 17 Oct 2009 01:15:40 -0000 1.6 +++ profiles/default/default.info 17 Oct 2009 18:31:28 -0000 @@ -16,6 +16,7 @@ dependencies[] = search dependencies[] = shortcut dependencies[] = toolbar +dependencies[] = overlay dependencies[] = field_ui dependencies[] = file files[] = default.profile Index: themes/garland/style.css =================================================================== RCS file: /cvs/drupal/drupal/themes/garland/style.css,v retrieving revision 1.66 diff -u -r1.66 style.css --- themes/garland/style.css 17 Oct 2009 05:50:29 -0000 1.66 +++ themes/garland/style.css 17 Oct 2009 18:32:24 -0000 @@ -508,6 +508,15 @@ font-size: 1.5em; } +/* Don't display any header elements when within the overlay, and adjust the page height accordingly. */ +body.overlay #header * { + display: none; +} + +body.overlay { + margin-top: -80px; +} + #wrapper #container #header h1 a:hover { text-decoration: none; } Index: themes/seven/style.css =================================================================== RCS file: /cvs/drupal/drupal/themes/seven/style.css,v retrieving revision 1.20 diff -u -r1.20 style.css --- themes/seven/style.css 18 Oct 2009 04:35:30 -0000 1.20 +++ themes/seven/style.css 18 Oct 2009 13:42:00 -0000 @@ -55,7 +55,7 @@ */ #branding { overflow: hidden; - padding: 20px 40px 0 40px; + padding: 20px 20px 0 20px; position: relative; background-color: #e0e0d8; } @@ -115,7 +115,7 @@ */ div.messages { padding: 9px; - margin: 1em 0; + margin: 0.5em 0 0; color: #036; background: #bdf; border: 1px solid #ace; @@ -158,9 +158,8 @@ /** * Console. */ -#page .console { - border-top: 1px solid #ccc; - padding: 9px 0 10px; +#console { + margin: 9px 0 10px; } /** @@ -549,7 +548,7 @@ } /* Buttons */ -input.form-submit { +input.form-submit, a.button { cursor: pointer; padding: 4px 17px; color: #5a5a5a; @@ -566,6 +565,11 @@ font-size: 1.1em; } +a.button:link, a.button:visited, a.button:hover, a.button:active { + text-decoration: none; + color: #5a5a5a; +} + div.node-form input#edit-submit, div.node-form input#edit-submit-1 { border: 1px solid #8eB7cd; @@ -618,9 +622,14 @@ ul.action-links { margin: 1em 0; + padding: 0 20px 0 20px; overflow: hidden; } +#block-system-main ul.action-links { + padding: 0; +} + ul.action-links li { float: left; margin: 0 1em 0 0; @@ -716,24 +725,40 @@ } /* Overlay theming */ -body.overlay { - background: #fff; +.overlay #branding { + background-color: #fff; + padding-top: 15px; } -body.overlay #branding, -body.overlay #page-title, -body.overlay #page #left, -body.overlay #page #footer { +.overlay .primary, +.overlay #branding h1.page-title, +.overlay #page #left, +.overlay #page #footer { display: none; } -body.overlay #page { +.overlay #page { margin: 0; - padding: 0; } -body.overlay #block-system-main { - padding: 20px; +.overlay #branding div.breadcrumb { + float: left; + position: relative; + z-index: 10; +} + +.overlay ul.secondary { + background: transparent none; + margin: -2.4em 0 0; + padding: 3px 10px; +} + +.overlay #content { + padding: 0 20px; +} + +.overlay #block-system-main { + padding: 0; } /* Shortcut theming */ Index: modules/overlay/overlay-child.js =================================================================== --- modules/overlay/overlay-child.js +++ modules/overlay/overlay-child.js @@ -0,0 +1,138 @@ +// $Id: child.js,v 1.1.4.3 2009/06/17 15:16:26 markuspetrux Exp $ + +(function ($) { + +/** + * Overlay object for child windows. + */ +Drupal.overlayChild = Drupal.overlayChild || { processed: false, behaviors: {} }; + +/** + * Attach the child dialog behavior to new content. + */ +Drupal.behaviors.overlayChild = { + attach: function (context, settings) { + var self = Drupal.overlayChild; + var settings = settings.overlayChild || {}; + + // Make sure this behavior is not processed more than once. + if (self.processed) { + return; + } + self.processed = true; + + // If we cannot reach the parent window, then we have nothing else to do + // here. + if (!Drupal.isObject(parent.Drupal) || !Drupal.isObject(parent.Drupal.overlay)) { + return; + } + + // If a form has been submitted successfully, then the server side script + // may have decided to tell us the parent window to close the popup dialog. + if (settings.closeOverlay) { + parent.Drupal.overlay.bindChild(window, true); + // Close the child window from a separate thread because the current + // one is busy processing Drupal behaviors. + setTimeout(function () { + // We need to store the parent variable locally because it will + // disappear as soon as we close the iframe. + var p = parent; + p.Drupal.overlay.close(settings.args, settings.statusMessages); + if (typeof settings.redirect == 'string') { + p.Drupal.overlay.redirect(settings.redirect); + } + }, 1); + return; + } + + // Ok, now we can tell the parent window we're ready. + parent.Drupal.overlay.bindChild(window); + + // Install onBeforeUnload callback, if module is present. + if (Drupal.isObject(Drupal.onBeforeUnload) && !Drupal.onBeforeUnload.callbackExists('overlayChild')) { + Drupal.onBeforeUnload.addCallback('overlayChild', function () { + // Tell the parent window we're unloading. + parent.Drupal.overlay.unbindChild(window); + }); + } + + // Attach child related behaviors to the iframe document. + self.attachBehaviors(context, settings); + } +}; + +/** + * Attach child related behaviors to the iframe document. + */ +Drupal.overlayChild.attachBehaviors = function (context, settings) { + $.each(this.behaviors, function () { + this(context, settings); + }); +}; + +/** + * Scroll to the top of the page. + * + * This makes the overlay visible to users even if it is not as tall as the + * previously shown overlay was. + */ +Drupal.overlayChild.behaviors.scrollToTop = function (context, settings) { + window.scrollTo(0, 0); +}; + +/** + * Modify links and forms depending on their relation to the overlay. + * + * By default, forms and links are assumed to keep the flow in the overlay. + * Thus their action and href attributes respectively get a ?render=overlay + * suffix. Non-administrative links should however close the overlay and + * redirect the parent page to the given link. This would include links in a + * content listing, where administration options are mixed with links to the + * actual content to be shown on the site out of the overlay. + * + * @see Drupal.overlay.isAdminLink() + */ +Drupal.overlayChild.behaviors.parseLinks = function (context, settings) { + $('a:not(.overlay-exclude)', context).once('overlay').each(function () { + // Non-admin links should close the overlay and open in the main window. + if (!parent.Drupal.overlay.isAdminLink(this.href)) { + $(this).click(function () { + // We need to store the parent variable locally because it will + // disappear as soon as we close the iframe. + var parentWindow = parent; + if (parentWindow.Drupal.overlay.close(false)) { + parentWindow.Drupal.overlay.redirect($(this).attr('href')); + } + return false; + }); + return; + } + else { + var href = $(this).attr('href'); + if (href.indexOf('http') > 0 || href.indexOf('https') > 0) { + $(this).attr('target', '_new'); + } + else { + $(this).click(function () { + var linkURL = parent.Drupal.overlay.addOverlayParam($(this).attr('href')); + parent.Drupal.overlay.load(linkURL); + return false; + }); + } + } + }); + $('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); Index: modules/overlay/overlay-parent.css =================================================================== --- modules/overlay/overlay-parent.css +++ modules/overlay/overlay-parent.css @@ -0,0 +1,122 @@ +/* $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: 27px; + 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: 5px 14px; + text-decoration: none; + font-size: 11px; +} +.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; + padding-bottom: 7px; +} +.overlay .ui-dialog-titlebar ul li a:hover { + color: #fff; +} +.overlay .ui-dialog-titlebar ul li.active a:hover { + color: #000; +} Index: modules/overlay/overlay-parent.js =================================================================== --- modules/overlay/overlay-parent.js +++ modules/overlay/overlay-parent.js @@ -0,0 +1,747 @@ +// $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 all admin links without the 'overlay-exclude' class. + $('a:not(.overlay-exclude)').filter(function () { + return Drupal.overlay.isAdminLink(this.href); + }) + // Respond to their click event. + .once('overlay').click(function () { + + // Append render variable, so the server side can choose the right + // rendering and add child modal frame code to the page if needed. + var linkURL = Drupal.overlay.addOverlayParam($(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 not an overlay opened yet, we should open a new one. + var overlayOptions = { + url: linkURL, + + // Remove active class from all header buttons. + onOverlayClose: function () { + $('a.to-overlay').each(function () { + $(this).removeClass('active'); + }); + }, + draggable: false + }; + Drupal.overlay.open(overlayOptions); + + // Prevent default action of the link click event. + return false; + }); + + // Automatically open an overlay if defined in Drupal.settings.overlay.autoOpen. + if (Drupal.settings.overlay.autoOpen) { + var linkURL = Drupal.overlay.addOverlayParam(Drupal.settings.overlay.autoOpen); + + // Unset autoOpen to prevent looping. + delete Drupal.settings.overlay.autoOpen; + + // 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 not an overlay opened yet, we should open a new one. + var overlayOptions = { + url: linkURL, + + // Remove active class from all header buttons. + onOverlayClose: function () { + $('a.to-overlay').each(function () { + $(this).removeClass('active'); + }); + }, + draggable: false + }; + Drupal.overlay.open(overlayOptions); + } + } +}; + +/** + * 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 = $('