Index: modules/system/system.css =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.css,v retrieving revision 1.53 diff -u -r1.53 system.css --- modules/system/system.css 5 Dec 2008 12:50:28 -0000 1.53 +++ modules/system/system.css 28 Feb 2009 21:26:14 -0000 @@ -559,3 +559,56 @@ div.password-confirm { visibility: hidden; } + +/* +** Ajax popbox dialog box styles +*/ +#popbox-overlay { + position: absolute; + background: black; + z-index: 9; + top: 0; +} +#popbox-loading { + z-index: 10; + opacity: 0.75; + position: relative; + position: absolute; + width: 100px; + height: 100px; + display: none; +} +#popbox { + border: 1px solid black; + background: white; + position: absolute; + z-index: 10; + padding: 0.5em; + width: 600px; + overflow: auto; +} +#popbox-title { + font-weight: bold; + margin-bottom: 0.25em; +} +#popbox-title div.title { + float: left; +} +#popbox-title #popbox-close { + float: right; +} +#popbox-title #popbox-close a { + font-weight: normal; +} +/* Allow messages to be used as the title of the popbox */ +#popbox div.messages { + background: transparent; + border: none; + padding: 0; + margin: 0; +} +a.popbox-processed { + padding-right: 12px; + background: url(../../misc/popbox-icon.png) no-repeat right; +} + Index: modules/system/system.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v retrieving revision 1.129 diff -u -r1.129 system.admin.inc --- modules/system/system.admin.inc 26 Feb 2009 07:30:28 -0000 1.129 +++ modules/system/system.admin.inc 28 Feb 2009 21:26:14 -0000 @@ -1287,6 +1287,20 @@ return system_settings_form($form); } +function system_popbox_settings() { + $form['popboxes_toggle'] = array ( + '#type' => 'radios', + '#title' => t('Popboxes'), + '#default_value' => 1, + '#options' => array ( + 0 => t('Off'), + 1 => t('On'), + ), + '#description' => t('Popboxes are modal confirmation dialogs.'), + ); + return system_settings_form($form); +} + /** * Form builder; Configure site performance settings. * @@ -1771,6 +1785,7 @@ * If true, only returns a boolean whether there are system status errors. */ function system_status($check = FALSE) { + drupal_add_popbox(); // Load .install files include_once DRUPAL_ROOT . '/includes/install.inc'; drupal_load_updates(); Index: modules/system/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.module,v retrieving revision 1.668 diff -u -r1.668 system.module --- modules/system/system.module 22 Feb 2009 17:55:30 -0000 1.668 +++ modules/system/system.module 28 Feb 2009 21:26:16 -0000 @@ -169,6 +169,9 @@ 'arguments' => array('version' => NULL), ), 'system_compact_link' => array(), + 'popbox' => array( + 'template' => 'popbox', + ), )); } @@ -649,6 +652,14 @@ 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -1, ); + $items['admin/settings/logging/popboxes'] = array( + 'title' => 'Popbox Behavior', + 'description' => 'Settings for the popbox dialog behavior.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_popbox_settings'), + 'access arguments' => array('administer site configuration'), + 'type' => MENU_LOCAL_TASK, + ); $items['admin/settings/performance'] = array( 'title' => 'Performance', 'description' => 'Enable or disable page caching for anonymous users and set CSS and JS bandwidth optimization options.', @@ -711,7 +722,7 @@ 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); - + // Reports: $items['admin/reports'] = array( 'title' => 'Reports', @@ -1461,7 +1472,7 @@ $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)); + $cancel = l($no ? $no : t('Cancel'), $path, array('query' => $query, 'fragment' => $fragment, 'attributes' => array('class' => 'popbox-close'))); drupal_set_title($question, PASS_THROUGH); Index: modules/path/path.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/path/path.admin.inc,v retrieving revision 1.17 diff -u -r1.17 path.admin.inc --- modules/path/path.admin.inc 13 Jan 2009 19:27:21 -0000 1.17 +++ modules/path/path.admin.inc 28 Feb 2009 21:26:11 -0000 @@ -12,6 +12,7 @@ * and return the list of matching URL aliases. */ function path_admin_overview($keys = NULL) { + drupal_add_popbox(); // Add the filter form above the overview table. $output = drupal_get_form('path_admin_filter_form', $keys); // Enable language column if locale is enabled or if we have any alias with language @@ -50,7 +51,7 @@ l($data->dst, $data->src), l($data->src, $data->src, array('alias' => TRUE)), l(t('edit'), "admin/build/path/edit/$data->pid", array('query' => $destination)), - l(t('delete'), "admin/build/path/delete/$data->pid", array('query' => $destination)), + l(t('delete'), "admin/build/path/delete/$data->pid", array('query' => $destination, 'attributes' => array('class' => 'popbox-confirm'))), ), ); if ($multilanguage) { Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.870 diff -u -r1.870 common.inc --- includes/common.inc 28 Feb 2009 07:36:06 -0000 1.870 +++ includes/common.inc 28 Feb 2009 21:26:08 -0000 @@ -2755,6 +2755,20 @@ drupal_add_js($settings, 'setting'); } + /** + * Attach the popbox behavior to the page. + */ +function drupal_add_popbox() { + static $added = FALSE; + if (!$added & variable_get('popboxes_toggle', 1)) { + drupal_add_js('misc/jquery.form.js'); + drupal_add_js('misc/popbox.js'); + $settings = array('popbox' => array('template' => theme('popbox'))); + drupal_add_js($settings, 'setting'); + $added = TRUE; + } +} + /** * Aggregate JS files, putting them in the files directory. * Index: modules/block/block.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/block/block.admin.inc,v retrieving revision 1.35 diff -u -r1.35 block.admin.inc --- modules/block/block.admin.inc 11 Feb 2009 03:38:46 -0000 1.35 +++ modules/block/block.admin.inc 28 Feb 2009 21:26:08 -0000 @@ -27,9 +27,10 @@ */ function block_admin_display_form(&$form_state, $blocks, $theme = NULL) { global $theme_key, $custom_theme; - + drupal_add_css(drupal_get_path('module', 'block') . '/block.css', array('preprocess' => FALSE)); - + drupal_add_popbox(); + // If non-default theme configuration has been selected, set the custom theme. $custom_theme = isset($theme) ? $theme : variable_get('theme_default', 'garland'); init_theme(); @@ -81,7 +82,8 @@ if ($block['module'] == 'block') { $form[$key]['delete'] = array( '#markup' => l(t('delete'), - 'admin/build/block/delete/' . $block['delta']), + 'admin/build/block/delete/' . $block['delta'], + array('attributes' => array('class' => 'popbox-confirm'))), ); } } Index: modules/node/node.pages.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.pages.inc,v retrieving revision 1.55 diff -u -r1.55 node.pages.inc --- modules/node/node.pages.inc 13 Feb 2009 02:22:09 -0000 1.55 +++ modules/node/node.pages.inc 28 Feb 2009 21:26:11 -0000 @@ -254,6 +254,7 @@ '#type' => 'submit', '#value' => t('Delete'), '#weight' => 15, + '#attributes' => array('class' => 'popbox-form-confirm'), '#submit' => array('node_form_delete_submit'), ); } Index: modules/node/content_types.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/node/content_types.inc,v retrieving revision 1.64 diff -u -r1.64 content_types.inc --- modules/node/content_types.inc 26 Jan 2009 14:08:43 -0000 1.64 +++ modules/node/content_types.inc 28 Feb 2009 21:26:11 -0000 @@ -10,6 +10,7 @@ * Displays the content type admin overview page. */ function node_overview_types() { + drupal_add_popbox(); $types = node_get_types(); $names = node_get_types('names'); $header = array(t('Name'), array('data' => t('Operations'), 'colspan' => '2')); @@ -25,7 +26,7 @@ // Set the delete column. if ($type->custom) { - $row[] = array('data' => l(t('delete'), 'admin/build/node-type/' . $type_url_str . '/delete')); + $row[] = array('data' => l(t('delete'), 'admin/build/node-type/' . $type_url_str . '/delete', array('attributes' => array('class' => 'popbox-confirm')))); } else { $row[] = array('data' => ''); Index: modules/filter/filter.module =================================================================== RCS file: /cvs/drupal/drupal/modules/filter/filter.module,v retrieving revision 1.240 diff -u -r1.240 filter.module --- modules/filter/filter.module 21 Jan 2009 16:58:42 -0000 1.240 +++ modules/filter/filter.module 28 Feb 2009 21:26:10 -0000 @@ -586,7 +586,8 @@ * @ingroup themeable */ function theme_filter_tips_more_info() { - return '

' . l(t('More information about formatting options'), 'filter/tips') . '

'; + drupal_add_popbox(); + return '

' . l(t('More information about formatting options'), 'filter/tips', array('attributes' => array('class' => 'popbox'))) . '

'; } /** Index: modules/filter/filter.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/filter/filter.admin.inc,v retrieving revision 1.24 diff -u -r1.24 filter.admin.inc --- modules/filter/filter.admin.inc 5 Feb 2009 19:52:02 -0000 1.24 +++ modules/filter/filter.admin.inc 28 Feb 2009 21:26:08 -0000 @@ -14,7 +14,8 @@ * @see filter_admin_overview_submit() */ function filter_admin_overview() { - + drupal_add_popbox(); + // Overview of all formats. $formats = filter_formats(); $error = FALSE; @@ -33,7 +34,7 @@ $form[$id]['name'] = array('#markup' => $format->name); $form[$id]['roles'] = array('#markup' => $default ? t('All roles may use the default format') : ($roles ? implode(', ', $roles) : t('No roles may use this format'))); $form[$id]['configure'] = array('#markup' => l(t('configure'), 'admin/settings/filter/' . $id)); - $form[$id]['delete'] = array('#markup' => $default ? '' : l(t('delete'), 'admin/settings/filter/delete/' . $id)); + $form[$id]['delete'] = array('#markup' => $default ? '' : l(t('delete'), 'admin/settings/filter/delete/' . $id, array('attributes' => array('class' => 'popbox-confirm')))); $form[$id]['weight'] = array('#type' => 'weight', '#default_value' => $format->weight); } $form['default'] = array('#type' => 'radios', '#options' => $options, '#default_value' => variable_get('filter_default_format', 1)); Index: modules/menu/menu.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/menu/menu.admin.inc,v retrieving revision 1.38 diff -u -r1.38 menu.admin.inc --- modules/menu/menu.admin.inc 3 Feb 2009 18:55:30 -0000 1.38 +++ modules/menu/menu.admin.inc 28 Feb 2009 21:26:10 -0000 @@ -60,6 +60,7 @@ * Recursive helper function for menu_overview_form(). */ function _menu_overview_tree_form($tree) { + drupal_add_popbox(); static $form = array('#tree' => TRUE); foreach ($tree as $data) { $title = ''; @@ -97,7 +98,7 @@ $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' => 'popbox-confirm'))); } // Set the reset column. elseif ($item['module'] == 'system' && $item['customized']) { Index: modules/system/popbox.tpl.php =================================================================== RCS file: modules/system/popbox.tpl.php diff -N modules/system/popbox.tpl.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/system/popbox.tpl.php 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,16 @@ + +
+
+
+
%title
+
+
+
%body
+
%buttons
+ +
Index: misc/popbox.js =================================================================== RCS file: misc/popbox.js diff -N misc/popbox.js --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ misc/popbox.js 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,333 @@ +// $Id$ +(function($) { + +/** + * popbox Modal Dialog API + * + * Provide an API for building and displaying JavaScript, in-page, popbox modal dialogs (lightbox style). + * Modality is provided by a fixed, semi-opaque div, positioned in front of the page contents. + * + * popboxes xhtml is themeable, but the outter most element must have id="popbox". + */ + +/** + * Create the popbox object/namespace. + */ +Drupal.popbox = function() {}; +Drupal.popbox.contentSelector = '#content-area'; // The theme must wrap it's page content. +Drupal.popbox.titleSelector = '#page-title'; // The theme must wrap it's page title. + +/** + * Attach the popbox behavior to the all the requested links on the page. + * + * @param context + * The jQuery object to apply the behaviors to. + */ +Drupal.behaviors.popbox = { + attach: function(context) { + console.log("popbox"); + // Add keybinding to close popbox. + var $body = $('body'); + if(!$body.hasClass('popbox-processed')) { + $body.addClass('popbox-processed'); + $(document).bind('keydown', Drupal.popbox.keyHandle); + + // If we are on the status report page, run the selector test and report the result. + status = 'admin/reports/status'; + current = window.location.href; + if (current.substring(current.length - status.length) === status) { + Drupal.popbox.testContentSelector(); + } + } + + Drupal.popbox.attach(context, '.popbox', {noUpdate: true}); + // Only attach to confirmation if content selector is correct for theme. + if ($(Drupal.popbox.contentSelector).length === 1) { + Drupal.popbox.attach(context, '.popbox-confirm', {reloadWhenDone: true}); // whole page reload. + Drupal.popbox.attachToForm(context, {}); + } + } +}; + +/** + * Attach the popbox behavior to a particular link. + * + * @param selector + * jQuery selector for links to attach popbox behavior to. + * @param options + * Hash of options associated with these links. + */ +Drupal.popbox.attach = function(context, selector, options) { + $(selector, context).not('.popbox-processed').each(function() { + var $element = $(this); + // Tag the element as attached, so it is not processed again. + $element.addClass('popbox-processed'); + + // Append note to link title (will show on hover). + var title = $element.attr('title') || ''; + $element.attr('title', title + Drupal.t('[popbox]')); + + // Attach the on-click popbox behavior to the element. + $element.click(function(e){ + return Drupal.popbox.openPath(this, options); + }); + }); +}; + +Drupal.popbox.attachToForm = function(context, options) { + $('form input.popbox-form-confirm', context).parents('form').not('.popbox-processed').each(function() { + $form = $(this); + // Tag the form as attached, so it is not processed again. + $form.addClass('popbox-processed'); + + // Attach ajaxForm submission to form. + $form.ajaxForm({ + success: function(response, status) { + $title = $(Drupal.popbox.titleSelector, response); + $content = $(Drupal.popbox.contentSelector, response); + Drupal.popbox.showPopbox($title.html(), $content.html(), null, options.width); + } + }); + + // If submit button is NOT the popbox button, remove the ajaxForm submit. + // We need to do it this way so the submit button value is submitted with rest of form. + $('input:submit', $form).not('.popbox-form-confirm').click(function(e){ + $form.ajaxFormUnbind(); + }); + }); +}; + +/** + * Generic dialog builder. + * Add a popbox to the page. + */ +Drupal.popbox.showPopbox = function(title, body, buttons, width) { + Drupal.popbox.addOverlay(); + var $popbox = $(Drupal.theme('popboxDialog', title, body, buttons)); + // Start with dialog off the side. Hiding it with display:none causes flash in FF2. + $popbox.css('left', '-9999px'); + if (width) { + $popbox.css('width', width); + } + $('body').append($popbox); // Add the popbox to the DOM. + + // Adding button functions + if (buttons) { + jQuery.each(buttons, function (id, button) { + $('#'+id).click(button.func); + }); + } + $('#popbox-close').click(Drupal.popbox.close); + $('.popbox-close').click(function(){Drupal.popbox.close(); return false;}); + + // center on the screen, adding in offsets if the window has been scrolled + var popboxWidth = $popbox.width(); + var windowWidth = $(window).width(); + var left = (windowWidth / 2) - (popboxWidth / 2) + Drupal.popbox.scrollLeft(); + + // Get popbox's height on the page. + // Need to do it this way, since we get visible flash in FF2 if popbox is not visible! + var popboxHeight = $popbox.height(); + var windowHeight = $(window).height(); + if (popboxHeight > (0.9 * windowHeight) ) { // Must fit in 90% of window. + popboxHeight = 0.9 * windowHeight; + $popbox.height(popboxHeight); + } + var top = (windowHeight / 2) - (popboxHeight / 2) + Drupal.popbox.scrollTop(); + + $popbox.css('top', top).css('left', left); // Position the popbox to be visible. + + // Focus on the first input element in the popbox window. + this.refocus(); + + // Remove the loading image. + Drupal.popbox.removeLoading(); + + return false; +}; + +Drupal.popbox.removePopbox = function() { + $('#popbox').remove(); +}; + +/** + * Use Ajax to open the URL inside a popbox window. + * + * @param element + * Element that was clicked to open the popbox. + * @param options + * Hash of options controlling how the popbox interacts with the underlying page. + */ +Drupal.popbox.openPath = function(element, options) { + // let the user know something is happening + $('body').css("cursor", "wait"); + + Drupal.popbox.addOverlay(); + Drupal.popbox.addLoading(); + + var href = options.href ? options.href : element.href; + $(document).trigger('popbox_open_path', [element, href]); // Broadcast popbox Open Path event. + + ajaxOptions = { + url: href, + success: function(page) { + $title = $(Drupal.popbox.titleSelector, page); + $content = $(Drupal.popbox.contentSelector, page); + Drupal.popbox.showPopbox($title.html(), $content.html(), null, options.width); + }, + complete: function() { + $('body').css("cursor", "auto"); // Return the cursor to normal state. + }, + error: function() { + Drupal.popbox.message("Unable to open: " + href); + } + }; + $.ajax(ajaxOptions); + + return false; +}; + +/** + * Simple popbox that functions like the browser's alert box. + */ +Drupal.popbox.message = function(title, message) { + message = message || ''; + var buttons = { + 'popbox_ok': {title: Drupal.t('OK'), func: Drupal.popbox.close} + }; + Drupal.popbox.showPopbox(title, message, buttons); +}; + +/** + * Handle any special keys when popbox is active. + */ +Drupal.popbox.keyHandle = function(e) { + if (!e) { + e = window.event; + } + if (e.keyCode === 27) { // esc + Drupal.popbox.close(); + } +}; + +Drupal.popbox.addOverlay = function() { + var $overlay = $('#popbox-overlay'); + if ($overlay.length === 0) { // Overlay does not already exist, so create it. + $overlay = $(Drupal.theme('popboxOverlay')); + $overlay.css('opacity', '0.4'); // for ie6(?) + // Doing absolute positioning, so make overlay's size equal the entire body. + $doc = $(document); + $overlay.width($doc.width()).height($doc.height()); + $overlay.click(Drupal.popbox.close); + $('body').prepend($overlay); + } +}; + +Drupal.popbox.removeOverlay = function() { + $('#popbox-overlay').remove(); +}; + +Drupal.popbox.addLoading = function() { + var $loading = $('#popbox-loading'); + if ($loading.length === 0) { // Loading graphic does not already exist, so create it. + $loading = $(Drupal.theme('popboxLoading')); + $('body').prepend($loading); // Loading div is initially display:none. + var width = $loading.width(); + var height = $loading.height(); + var left = ($(window).width() / 2) - (width / 2) + Drupal.popbox.scrollLeft(); + var top = ($(window).height() / 2) - (height / 2) + Drupal.popbox.scrollTop(); + $loading.css({'top': top, 'left': left, 'display': 'block'}); // Center it and make it visible. + } +}; + +Drupal.popbox.removeLoading = function() { + $('#popbox-loading').remove(); +}; + +/** + * Remove everything. + */ +Drupal.popbox.close = function() { + Drupal.popbox.removePopbox(); + Drupal.popbox.removeLoading(); + Drupal.popbox.removeOverlay(); + return false; +}; + +/** + * Set the focus on the popbox to the first visible form element, + * or the close link if there are no visible form elements. + */ +Drupal.popbox.refocus = function() { + $focus = $('#popbox :input:visible:enabled:first'); + if ($focus.length === 0) { + $focus = $('#popbox-close a'); + } + $focus.focus(); +}; + +/** + * Get current position of the left side of the browser window. + * Copied from jQuery offset. + */ +Drupal.popbox.scrollLeft = function() { + return Math.max(document.documentElement.scrollLeft, document.body.scrollLeft); +}; + +/** + * Get current position of the top of the browser window. + * Copied from jQuery offset. + */ +Drupal.popbox.scrollTop = function() { + return Math.max(document.documentElement.scrollTop, document.body.scrollTop); +}; + +/** + * Warn the user if ajax will not work with the current theme. + */ +Drupal.popbox.testContentSelector = function() { + var body = ''; + if ($(Drupal.popbox.titleSelector).length !== 1) { + body += Drupal.t('The page title must be wrapped in an element with id') + ' = "' + Drupal.popbox.titleSelector + '".
'; + } + if ($(Drupal.popbox.contentSelector).length !== 1) { + body += Drupal.t('The page content must be wrapped in an element with id') + ' = "' + Drupal.popbox.contentSelector + '".
'; + body += Drupal.t('The popbox behavior is disabled for confirmation dialogs.'); + } + if (body) { + title = Drupal.t('Your current theme does not support the popbox behavior.'); + Drupal.popbox.showPopbox(title, body); + } +}; + +Drupal.theme.prototype.popboxLoading = function() { + var loading = '
'; + loading += ''; + loading += '
'; + return loading; +}; + + +Drupal.theme.prototype.popboxOverlay = function() { + return '
'; +}; + +Drupal.theme.prototype.popboxButton = function(title, id) { + return ''; +}; + +Drupal.theme.prototype.popboxDialog = function(title, body, buttons) { + var template = Drupal.settings.popbox.template; + var popbox = template.replace('%title', title).replace('%body', body); + + var themedButtons = ''; + if (buttons) { + jQuery.each(buttons, function (id, button) { + themedButtons += Drupal.theme('popboxButton', button.title, id); + }); + } + popbox = popbox.replace('%buttons', themedButtons); + return popbox; +}; + +})(jQuery);