Skip to content
......@@ -105,7 +105,8 @@
* generate the same form (or very similar forms) using different $form_ids
* can implement hook_forms(), which maps different $form_id values to the
* proper form constructor function. Examples may be found in node_forms(),
* and search_forms().
* and search_forms(). hook_forms() can also be used to define forms in
* classes.
* @param ...
* Any additional arguments are passed on to the functions called by
* drupal_get_form(), including the unique form constructor function. For
......@@ -809,7 +810,7 @@ function drupal_retrieve_form($form_id, &$form_state) {
}
if (isset($form_definition['callback'])) {
$callback = $form_definition['callback'];
$form_state['build_info']['base_form_id'] = $callback;
$form_state['build_info']['base_form_id'] = isset($form_definition['base_form_id']) ? $form_definition['base_form_id'] : $callback;
}
// In case $form_state['wrapper_callback'] is not defined already, we also
// allow hook_forms() to define one.
......@@ -830,7 +831,7 @@ function drupal_retrieve_form($form_id, &$form_state) {
// the actual form builder function ($callback) expects. This allows for
// pre-populating a form with common elements for certain forms, such as
// back/next/save buttons in multi-step form wizards. See drupal_build_form().
if (isset($form_state['wrapper_callback']) && function_exists($form_state['wrapper_callback'])) {
if (isset($form_state['wrapper_callback']) && is_callable($form_state['wrapper_callback'])) {
$form = call_user_func_array($form_state['wrapper_callback'], $args);
// Put the prepopulated $form into $args.
$args[0] = $form;
......@@ -2571,7 +2572,7 @@ function form_type_select_value($element, $input = FALSE) {
* for this element. Return nothing to use the default.
*/
function form_type_textarea_value($element, $input = FALSE) {
if ($input !== FALSE) {
if ($input !== FALSE && $input !== NULL) {
// This should be a string, but allow other scalars since they might be
// valid input in programmatic form submissions.
return is_scalar($input) ? (string) $input : '';
......@@ -3028,7 +3029,7 @@ function form_process_password_confirm($element) {
function password_confirm_validate($element, &$element_state) {
$pass1 = trim($element['pass1']['#value']);
$pass2 = trim($element['pass2']['#value']);
if (!empty($pass1) || !empty($pass2)) {
if (strlen($pass1) > 0 || strlen($pass2) > 0) {
if (strcmp($pass1, $pass2)) {
form_error($element, t('The specified passwords do not match.'));
}
......@@ -3385,9 +3386,12 @@ function form_process_container($element, &$form_state) {
/**
* Returns HTML to wrap child elements in a container.
*
* Used for grouped form items. Can also be used as a #theme_wrapper for any
* Used for grouped form items. Can also be used as a theme wrapper for any
* renderable element, to surround it with a <div> and add attributes such as
* classes or an HTML id.
* classes or an HTML ID.
*
* See the @link forms_api_reference.html Form API reference @endlink for more
* information on the #theme_wrappers render array property.
*
* @param $variables
* An associative array containing:
......@@ -3542,6 +3546,7 @@ function form_process_tableselect($element) {
'#return_value' => $key,
'#default_value' => isset($value[$key]) ? $key : NULL,
'#attributes' => $element['#attributes'],
'#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
);
}
else {
......@@ -3979,7 +3984,12 @@ function form_process_autocomplete($element) {
// browser interpreting the path plus search string as an actual file.
$current_clean_url = isset($GLOBALS['conf']['clean_url']) ? $GLOBALS['conf']['clean_url'] : NULL;
$GLOBALS['conf']['clean_url'] = 0;
$element['#autocomplete_input']['#url_value'] = url($element['#autocomplete_path'], array('absolute' => TRUE));
// Force the script path to 'index.php', in case the server is not
// configured to find it automatically. Normally it is the responsibility
// of the site to do this themselves using hook_url_outbound_alter() (see
// url()) but since this code is forcing non-clean URLs on sites that don't
// normally use them, it is done here instead.
$element['#autocomplete_input']['#url_value'] = url($element['#autocomplete_path'], array('absolute' => TRUE, 'script' => 'index.php'));
$GLOBALS['conf']['clean_url'] = $current_clean_url;
}
return $element;
......
......@@ -809,6 +809,13 @@ function install_system_module(&$install_state) {
variable_set('install_profile_modules', array_diff($modules, array('system')));
$install_state['database_tables_exist'] = TRUE;
// Prevent the hook_requirements() check from telling us to convert the
// database to utf8mb4.
$connection = Database::getConnection();
if ($connection->utf8mb4IsConfigurable() && $connection->utf8mb4IsActive()) {
variable_set('drupal_all_databases_are_utf8mb4', TRUE);
}
}
/**
......@@ -1590,7 +1597,9 @@ function install_finished(&$install_state) {
}
/**
* Batch callback for batch installation of modules.
* Implements callback_batch_operation().
*
* Performs batch installation of modules.
*/
function _install_module_batch($module, $module_name, &$context) {
// Install and enable the module right away, so that the module will be
......@@ -1603,6 +1612,8 @@ function _install_module_batch($module, $module_name, &$context) {
}
/**
* Implements callback_batch_finished().
*
* 'Finished' callback for module installation batch.
*/
function _install_profile_modules_finished($success, $results, $operations) {
......
......@@ -750,7 +750,7 @@ function drupal_install_system() {
/**
* Uninstalls a given list of disabled modules.
*
* @param array $module_list
* @param string[] $module_list
* The modules to uninstall. It is the caller's responsibility to ensure that
* all modules in this list have already been disabled before this function
* is called.
......@@ -769,6 +769,7 @@ function drupal_install_system() {
* included in $module_list).
*
* @see module_disable()
* @see module_enable()
*/
function drupal_uninstall_modules($module_list = array(), $uninstall_dependents = TRUE) {
if ($uninstall_dependents) {
......
......@@ -435,6 +435,13 @@ function locale_language_url_rewrite_url(&$path, &$options) {
switch (variable_get('locale_language_negotiation_url_part', LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX)) {
case LOCALE_LANGUAGE_NEGOTIATION_URL_DOMAIN:
if ($options['language']->domain) {
// Save the original base URL. If it contains a port, we need to
// retain it below.
if (!empty($options['base_url'])) {
// The colon in the URL scheme messes up the port checking below.
$normalized_base_url = str_replace(array('https://', 'http://'), '', $options['base_url']);
}
// Ask for an absolute URL with our modified base_url.
global $is_https;
$url_scheme = ($is_https) ? 'https://' : 'http://';
......@@ -449,6 +456,19 @@ function locale_language_url_rewrite_url(&$path, &$options) {
// Apply the appropriate protocol to the URL.
$options['base_url'] = $url_scheme . $host;
// In case either the original base URL or the HTTP host contains a
// port, retain it.
$http_host = $_SERVER['HTTP_HOST'];
if (isset($normalized_base_url) && strpos($normalized_base_url, ':') !== FALSE) {
list($host, $port) = explode(':', $normalized_base_url);
$options['base_url'] .= ':' . $port;
}
elseif (strpos($http_host, ':') !== FALSE) {
list($host, $port) = explode(':', $http_host);
$options['base_url'] .= ':' . $port;
}
if (isset($options['https']) && variable_get('https', FALSE)) {
if ($options['https'] === TRUE) {
$options['base_url'] = str_replace('http://', 'https://', $options['base_url']);
......@@ -523,6 +543,22 @@ function locale_language_url_rewrite_session(&$path, &$options) {
* possible attack vector (img).
*/
function locale_string_is_safe($string) {
// Some strings have tokens in them. For tokens in the first part of href or
// src HTML attributes, filter_xss() removes part of the token, the part
// before the first colon. filter_xss() assumes it could be an attempt to
// inject javascript. When filter_xss() removes part of tokens, it causes the
// string to not be translatable when it should be translatable. See
// LocaleStringIsSafeTest::testLocaleStringIsSafe().
//
// We can recognize tokens since they are wrapped with brackets and are only
// composed of alphanumeric characters, colon, underscore, and dashes. We can
// be sure these strings are safe to strip out before the string is checked in
// filter_xss() because no dangerous javascript will match that pattern.
//
// @todo Do not strip out the token. Fix filter_xss() to not incorrectly
// alter the string. https://www.drupal.org/node/2372127
$string = preg_replace('/\[[a-z0-9_-]+(:[a-z0-9_-]+)+\]/i', '', $string);
return decode_entities($string) == decode_entities(filter_xss($string, array('a', 'abbr', 'acronym', 'address', 'b', 'bdo', 'big', 'blockquote', 'br', 'caption', 'cite', 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'ins', 'kbd', 'li', 'ol', 'p', 'pre', 'q', 'samp', 'small', 'span', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'tt', 'ul', 'var')));
}
......@@ -631,9 +667,6 @@ function locale_add_language($langcode, $name = NULL, $native = NULL, $direction
* translations).
*/
function _locale_import_po($file, $langcode, $mode, $group = NULL) {
// Try to allocate enough time to parse and import the data.
drupal_set_time_limit(240);
// Check if we have the language already in the database.
if (!db_query("SELECT COUNT(language) FROM {languages} WHERE language = :language", array(':language' => $langcode))->fetchField()) {
drupal_set_message(t('The language selected for import is not supported.'), 'error');
......@@ -717,6 +750,12 @@ function _locale_import_read_po($op, $file, $mode = NULL, $lang = NULL, $group =
$lineno = 0;
while (!feof($fd)) {
// Refresh the time limit every 10 parsed rows to ensure there is always
// enough time to import the data for large PO files.
if (!($lineno % 10)) {
drupal_set_time_limit(30);
}
// A line should not be longer than 10 * 1024.
$line = fgets($fd, 10 * 1024);
......@@ -2306,6 +2345,8 @@ function _locale_batch_build($files, $finished = NULL, $components = array()) {
}
/**
* Implements callback_batch_operation().
*
* Perform interface translation import as a batch step.
*
* @param $filepath
......@@ -2324,6 +2365,8 @@ function _locale_batch_import($filepath, &$context) {
}
/**
* Implements callback_batch_finished().
*
* Finished callback of system page locale import batch.
* Inform the user of translation files imported.
*/
......@@ -2334,6 +2377,8 @@ function _locale_batch_system_finished($success, $results) {
}
/**
* Implements callback_batch_finished().
*
* Finished callback of language addition locale import batch.
* Inform the user of translation files imported.
*/
......
......@@ -566,7 +566,7 @@ function _drupal_wrap_mail_line(&$line, $key, $values) {
// Use soft-breaks only for purely quoted or unindented text.
$line = wordwrap($line, 77 - $values['length'], $values['soft'] ? " \n" : "\n");
// Break really long words at the maximum width allowed.
$line = wordwrap($line, 996 - $values['length'], $values['soft'] ? " \n" : "\n");
$line = wordwrap($line, 996 - $values['length'], $values['soft'] ? " \n" : "\n", TRUE);
}
/**
......
......@@ -229,12 +229,20 @@
define('MENU_FOUND', 1);
/**
* Internal menu status code -- Menu item was not found.
* Menu status code -- Not found.
*
* This can be used as the return value from a page callback, although it is
* preferable to use a load function to accomplish this; see the hook_menu()
* documentation for details.
*/
define('MENU_NOT_FOUND', 2);
/**
* Internal menu status code -- Menu item access is denied.
* Menu status code -- Access denied.
*
* This can be used as the return value from a page callback, although it is
* preferable to use an access callback to accomplish this; see the hook_menu()
* documentation for details.
*/
define('MENU_ACCESS_DENIED', 3);
......@@ -431,7 +439,7 @@ function menu_set_item($path, $router_item) {
*
* @param $path
* The path; for example, 'node/5'. The function will find the corresponding
* node/% item and return that.
* node/% item and return that. Defaults to the current path.
* @param $router_item
* Internal use only.
*
......@@ -2411,7 +2419,7 @@ function menu_set_active_trail($new_trail = NULL) {
// argument placeholders (%). Such links are not contained in regular
// menu trees, and have only been loaded for the additional
// translation that happens here, so as to be able to display them in
// the breadcumb for the current page.
// the breadcrumb for the current page.
// @see _menu_tree_check_access()
// @see _menu_link_translate()
if (strpos($link['href'], '%') !== FALSE) {
......
......@@ -227,6 +227,10 @@ function system_list_reset() {
drupal_static_reset('list_themes');
cache_clear_all('bootstrap_modules', 'cache_bootstrap');
cache_clear_all('system_list', 'cache_bootstrap');
// Clean up the bootstrap file scan cache.
drupal_static_reset('_drupal_file_scan_cache');
cache_clear_all('_drupal_file_scan_cache', 'cache_bootstrap');
}
/**
......@@ -320,16 +324,27 @@ function module_load_install($module) {
* The name of the included file, if successful; FALSE otherwise.
*/
function module_load_include($type, $module, $name = NULL) {
static $files = array();
if (!isset($name)) {
$name = $module;
}
$key = $type . ':' . $module . ':' . $name;
if (isset($files[$key])) {
return $files[$key];
}
if (function_exists('drupal_get_path')) {
$file = DRUPAL_ROOT . '/' . drupal_get_path('module', $module) . "/$name.$type";
if (is_file($file)) {
require_once $file;
$files[$key] = $file;
return $file;
}
else {
$files[$key] = FALSE;
}
}
return FALSE;
}
......@@ -365,20 +380,22 @@ function module_load_all_includes($type, $name = NULL) {
* - Invoke hook_modules_installed().
* - Invoke hook_modules_enabled().
*
* @param $module_list
* @param string[] $module_list
* An array of module names.
* @param $enable_dependencies
* @param bool $enable_dependencies
* If TRUE, dependencies will automatically be added and enabled in the
* correct order. This incurs a significant performance cost, so use FALSE
* if you know $module_list is already complete and in the correct order.
*
* @return
* @return bool
* FALSE if one or more dependencies are missing, TRUE otherwise.
*
* @see hook_install()
* @see hook_enable()
* @see hook_modules_installed()
* @see hook_modules_enabled()
* @see module_disable()
* @see drupal_uninstall_modules()
*/
function module_enable($module_list, $enable_dependencies = TRUE) {
if ($enable_dependencies) {
......@@ -505,12 +522,15 @@ function module_enable($module_list, $enable_dependencies = TRUE) {
/**
* Disables a given set of modules.
*
* @param $module_list
* @param string[] $module_list
* An array of module names.
* @param $disable_dependents
* @param bool $disable_dependents
* If TRUE, dependent modules will automatically be added and disabled in the
* correct order. This incurs a significant performance cost, so use FALSE
* if you know $module_list is already complete and in the correct order.
*
* @see drupal_uninstall_modules()
* @see module_enable()
*/
function module_disable($module_list, $disable_dependents = TRUE) {
if ($disable_dependents) {
......@@ -722,6 +742,7 @@ function module_implements($hook, $sort = FALSE, $reset = FALSE) {
drupal_static_reset('module_hook_info');
drupal_static_reset('drupal_alter');
cache_clear_all('hook_info', 'cache_bootstrap');
cache_clear_all('system_cache_tables', 'cache');
return;
}
......@@ -919,7 +940,9 @@ function module_invoke($module, $hook) {
*
* @return
* An array of return values of the hook implementations. If modules return
* arrays from their implementations, those are merged into one array.
* arrays from their implementations, those are merged into one array
* recursively. Note: integer keys in arrays will be lost, as the merge is
* done using array_merge_recursive().
*
* @see drupal_alter()
*/
......
......@@ -347,7 +347,8 @@ function drupal_match_path($path, $patterns) {
* drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL) makes this function available.
*
* @return
* The current Drupal URL path.
* The current Drupal URL path. The path is untrusted user input and must be
* treated as such.
*
* @see request_path()
*/
......
......@@ -164,7 +164,7 @@ function _registry_parse_files($files) {
* (optional) Weight of the module.
*/
function _registry_parse_file($filename, $contents, $module = '', $weight = 0) {
if (preg_match_all('/^\s*(?:abstract|final)?\s*(class|interface)\s+([a-zA-Z0-9_]+)/m', $contents, $matches)) {
if (preg_match_all('/^\s*(?:abstract|final)?\s*(class|interface|trait)\s+([a-zA-Z0-9_]+)/m', $contents, $matches)) {
foreach ($matches[2] as $key => $name) {
db_merge('registry')
->key(array(
......
......@@ -163,7 +163,7 @@ function _drupal_session_write($sid, $value) {
try {
if (!drupal_save_session()) {
// We don't have anything to do if we are not allowed to save the session.
return;
return TRUE;
}
// Check whether $_SESSION has been changed in this request.
......@@ -425,7 +425,7 @@ function _drupal_session_destroy($sid) {
// Nothing to do if we are not allowed to change the session.
if (!drupal_save_session()) {
return;
return TRUE;
}
// Delete session data.
......@@ -446,6 +446,8 @@ function _drupal_session_destroy($sid) {
elseif (variable_get('https', FALSE)) {
_drupal_session_delete_cookie('S' . session_name(), TRUE);
}
return TRUE;
}
/**
......
......@@ -1248,6 +1248,7 @@ function path_to_theme() {
function drupal_find_theme_functions($cache, $prefixes) {
$implementations = array();
$functions = get_defined_functions();
$theme_functions = preg_grep('/^(' . implode(')|(', $prefixes) . ')_/', $functions['user']);
foreach ($cache as $hook => $info) {
foreach ($prefixes as $prefix) {
......@@ -1264,7 +1265,7 @@ function drupal_find_theme_functions($cache, $prefixes) {
// intermediary suggestion.
$pattern = isset($info['pattern']) ? $info['pattern'] : ($hook . '__');
if (!isset($info['base hook']) && !empty($pattern)) {
$matches = preg_grep('/^' . $prefix . '_' . $pattern . '/', $functions['user']);
$matches = preg_grep('/^' . $prefix . '_' . $pattern . '/', $theme_functions);
if ($matches) {
foreach ($matches as $match) {
$new_hook = substr($match, strlen($prefix) + 1);
......@@ -1710,11 +1711,29 @@ function theme_status_messages($variables) {
* copy if none of the enabled modules or the active theme implement any
* preprocess or process functions or override this theme implementation.
*
* @param $variables
* An associative array containing the keys 'text', 'path', and 'options'.
* See the l() function for information about these variables.
* @param array $variables
* An associative array containing the keys:
* - text: The text of the link.
* - path: The internal path or external URL being linked to. It is used as
* the $path parameter of the url() function.
* - options: (optional) An array that defaults to empty, but can contain:
* - attributes: Can contain optional attributes:
* - class: must be declared in an array. Example: 'class' =>
* array('class_name1','class_name2').
* - title: must be a string. Example: 'title' => 'Example title'
* - Others are more flexible as long as they work with
* drupal_attributes($variables['options']['attributes]).
* - html: Boolean flag that tells whether text contains HTML or plain
* text. If set to TRUE, the text value will not be sanitized so the
calling function must ensure that it already contains safe HTML.
* The elements $variables['options']['attributes'] and
* $variables['options']['html'] are used in this function similarly to the
* way that $options['attributes'] and $options['html'] are used in l().
* The link itself is built by the url() function, which takes
* $variables['path'] and $variables['options'] as arguments.
*
* @see l()
* @see url()
*/
function theme_link($variables) {
return '<a href="' . check_plain(url($variables['path'], $variables['options'])) . '"' . drupal_attributes($variables['options']['attributes']) . '>' . ($variables['options']['html'] ? $variables['text'] : check_plain($variables['text'])) . '</a>';
......@@ -1791,7 +1810,8 @@ function theme_links($variables) {
foreach ($links as $key => $link) {
$class = array($key);
// Add first, last and active classes to the list of links to help out themers.
// Add first, last and active classes to the list of links to help out
// themers.
if ($i == 1) {
$class[] = 'first';
}
......@@ -1809,7 +1829,8 @@ function theme_links($variables) {
$output .= l($link['title'], $link['href'], $link);
}
elseif (!empty($link['title'])) {
// Some links are actually not links, but we wrap these in <span> for adding title and class attributes.
// Some links are actually not links, but we wrap these in <span> for
// adding title and class attributes.
if (empty($link['html'])) {
$link['title'] = check_plain($link['title']);
}
......@@ -2618,7 +2639,7 @@ function template_preprocess_page(&$variables) {
// Move some variables to the top level for themer convenience and template cleanliness.
$variables['show_messages'] = $variables['page']['#show_messages'];
foreach (system_region_list($GLOBALS['theme']) as $region_key => $region_name) {
foreach (system_region_list($GLOBALS['theme'], REGIONS_ALL, FALSE) as $region_key) {
if (!isset($variables['page'][$region_key])) {
$variables['page'][$region_key] = array();
}
......
......@@ -795,6 +795,14 @@ function update_fix_d7_requirements() {
function update_fix_d7_install_profile() {
$profile = drupal_get_profile();
// 'Default' profile has been renamed to 'Standard' in D7.
// We change the profile here to prevent a broken record in the system table.
// See system_update_7049().
if ($profile == 'default') {
$profile = 'standard';
variable_set('install_profile', $profile);
}
$results = db_select('system', 's')
->fields('s', array('name', 'schema_version'))
->condition('name', $profile)
......@@ -908,6 +916,8 @@ function update_get_d6_session_name() {
}
/**
* Implements callback_batch_operation().
*
* Performs one update and stores the results for display on the results page.
*
* If an update function completes successfully, it should return a message
......@@ -1078,6 +1088,8 @@ function update_batch($start, $redirect = NULL, $url = NULL, $batch = array(), $
}
/**
* Implements callback_batch_finished().
*
* Finishes the update process and stores the results for eventual display.
*
* After the updates run, all caches are flushed. The update results are
......
......@@ -264,6 +264,10 @@ function xmlrpc_server_call($xmlrpc_server, $methodname, $args) {
*/
function xmlrpc_server_multicall($methodcalls) {
// See http://www.xmlrpc.com/discuss/msgReader$1208
// To avoid multicall expansion attacks, limit the number of duplicate method
// calls allowed with a default of 1. Set to -1 for unlimited.
$duplicate_method_limit = variable_get('xmlrpc_multicall_duplicate_method_limit', 1);
$method_count = array();
$return = array();
$xmlrpc_server = xmlrpc_server_get();
foreach ($methodcalls as $call) {
......@@ -273,10 +277,14 @@ function xmlrpc_server_multicall($methodcalls) {
$ok = FALSE;
}
$method = $call['methodName'];
$method_count[$method] = isset($method_count[$method]) ? $method_count[$method] + 1 : 1;
$params = $call['params'];
if ($method == 'system.multicall') {
$result = xmlrpc_error(-32600, t('Recursive calls to system.multicall are forbidden.'));
}
elseif ($duplicate_method_limit > 0 && $method_count[$method] > $duplicate_method_limit) {
$result = xmlrpc_error(-156579, t('Too many duplicate method calls in system.multicall.'));
}
elseif ($ok) {
$result = xmlrpc_server_call($xmlrpc_server, $method, $params);
}
......
......@@ -476,7 +476,7 @@ Drupal.ajax.prototype.getEffect = function (response) {
* Handler for the form redirection error.
*/
Drupal.ajax.prototype.error = function (xmlhttprequest, uri, customMessage) {
alert(Drupal.ajaxError(xmlhttprequest, uri, customMessage));
Drupal.displayAjaxError(Drupal.ajaxError(xmlhttprequest, uri, customMessage));
// Remove the progress element.
if (this.progress.element) {
$(this.progress.element).remove();
......
......@@ -310,7 +310,7 @@ Drupal.ACDB.prototype.search = function (searchString) {
}
},
error: function (xmlhttp) {
alert(Drupal.ajaxError(xmlhttp, db.uri));
Drupal.displayAjaxError(Drupal.ajaxError(xmlhttp, db.uri));
}
});
}, this.delay);
......
......@@ -413,6 +413,29 @@ Drupal.getSelection = function (element) {
return { 'start': element.selectionStart, 'end': element.selectionEnd };
};
/**
* Add a global variable which determines if the window is being unloaded.
*
* This is primarily used by Drupal.displayAjaxError().
*/
Drupal.beforeUnloadCalled = false;
$(window).bind('beforeunload pagehide', function () {
Drupal.beforeUnloadCalled = true;
});
/**
* Displays a JavaScript error from an Ajax response when appropriate to do so.
*/
Drupal.displayAjaxError = function (message) {
// Skip displaying the message if the user deliberately aborted (for example,
// by reloading the page or navigating to a different page) while the Ajax
// request was still ongoing. See, for example, the discussion at
// http://stackoverflow.com/questions/699941/handle-ajax-error-when-a-user-clicks-refresh.
if (!Drupal.beforeUnloadCalled) {
alert(message);
}
};
/**
* Build an error message from an Ajax response.
*/
......
......@@ -493,7 +493,11 @@ $(document).bind('state:disabled', function(e) {
$(document).bind('state:required', function(e) {
if (e.trigger) {
if (e.value) {
$(e.target).closest('.form-item, .form-wrapper').find('label').append('<span class="form-required">*</span>');
var $label = $(e.target).closest('.form-item, .form-wrapper').find('label');
// Avoids duplicate required markers on initialization.
if (!$label.find('.form-required').length) {
$label.append('<span class="form-required">*</span>');
}
}
else {
$(e.target).closest('.form-item, .form-wrapper').find('label .form-required').remove();
......
......@@ -106,8 +106,10 @@ Drupal.tableDrag = function (table, tableSettings) {
// Add mouse bindings to the document. The self variable is passed along
// as event handlers do not have direct access to the tableDrag object.
$(document).bind('mousemove', function (event) { return self.dragRow(event, self); });
$(document).bind('mouseup', function (event) { return self.dropRow(event, self); });
$(document).bind('mousemove pointermove', function (event) { return self.dragRow(event, self); });
$(document).bind('mouseup pointerup', function (event) { return self.dropRow(event, self); });
$(document).bind('touchmove', function (event) { return self.dragRow(event.originalEvent.touches[0], self); });
$(document).bind('touchend', function (event) { return self.dropRow(event.originalEvent.touches[0], self); });
};
/**
......@@ -274,7 +276,10 @@ Drupal.tableDrag.prototype.makeDraggable = function (item) {
});
// Add the mousedown action for the handle.
handle.mousedown(function (event) {
handle.bind('mousedown touchstart pointerdown', function (event) {
if (event.originalEvent.type == "touchstart") {
event = event.originalEvent.touches[0];
}
// Create a new dragObject recording the event information.
self.dragObject = {};
self.dragObject.initMouseOffset = self.getMouseOffset(item, event);
......
......@@ -72,7 +72,7 @@ function aggregator_aggregator_remove($feed) {
*/
function aggregator_form_aggregator_admin_form_alter(&$form, $form_state) {
if (in_array('aggregator', variable_get('aggregator_processors', array('aggregator')))) {
$info = module_invoke('aggregator', 'aggregator_process', 'info');
$info = module_invoke('aggregator', 'aggregator_process_info');
$items = drupal_map_assoc(array(3, 5, 10, 15, 20, 25), '_aggregator_items');
$period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800), 'format_interval');
$period[AGGREGATOR_CLEAR_NEVER] = t('Never');
......
......@@ -24,7 +24,7 @@ Drupal.behaviors.blockSettingsSummary = {
$('fieldset#edit-node-type', context).drupalSetSummary(function (context) {
var vals = [];
$('input[type="checkbox"]:checked', context).each(function () {
vals.push($.trim($(this).next('label').text()));
vals.push($.trim($(this).next('label').html()));
});
if (!vals.length) {
vals.push(Drupal.t('Not restricted'));
......@@ -35,7 +35,7 @@ Drupal.behaviors.blockSettingsSummary = {
$('fieldset#edit-role', context).drupalSetSummary(function (context) {
var vals = [];
$('input[type="checkbox"]:checked', context).each(function () {
vals.push($.trim($(this).next('label').text()));
vals.push($.trim($(this).next('label').html()));
});
if (!vals.length) {
vals.push(Drupal.t('Not restricted'));
......@@ -49,7 +49,7 @@ Drupal.behaviors.blockSettingsSummary = {
return Drupal.t('Not customizable');
}
else {
return $radio.next('label').text();
return $radio.next('label').html();
}
});
}
......