diff --git a/core/includes/ajax.inc b/core/includes/ajax.inc
index 0f056dc..8683ff9 100644
--- a/core/includes/ajax.inc
+++ b/core/includes/ajax.inc
@@ -1216,4 +1216,3 @@
'selector' => $selector,
);
}
-
diff --git a/core/includes/archiver.inc b/core/includes/archiver.inc
index 2db2db1..835d46f 100644
--- a/core/includes/archiver.inc
+++ b/core/includes/archiver.inc
@@ -66,4 +66,3 @@
*/
public function listContents();
}
-
diff --git a/core/includes/batch.inc b/core/includes/batch.inc
index 15129a4..83ddd30 100644
--- a/core/includes/batch.inc
+++ b/core/includes/batch.inc
@@ -537,4 +537,3 @@
->execute();
}
}
-
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index f01a3de..35c9e0c 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -2624,7 +2624,7 @@
foreach ($types as $type) {
$GLOBALS[$type] = $default;
}
- if (drupal_multilingual()) {
+ if (language_multilingual()) {
include_once DRUPAL_ROOT . '/core/includes/language.inc';
foreach ($types as $type) {
$GLOBALS[$type] = language_initialize($type);
@@ -2653,7 +2653,7 @@
/**
* Returns TRUE if there is more than one language enabled.
*/
-function drupal_multilingual() {
+function language_multilingual() {
// The "language_count" variable stores the number of enabled languages to
// avoid unnecessarily querying the database when building the list of
// enabled languages on monolingual sites.
@@ -2686,8 +2686,8 @@
// Init language list
if (!isset($languages)) {
$default = language_default();
- if (drupal_multilingual() || module_exists('locale')) {
- $languages['language'] = db_query('SELECT * FROM {languages} ORDER BY weight ASC, name ASC')->fetchAllAssoc('language');
+ if (language_multilingual() || module_exists('language')) {
+ $languages['language'] = db_query('SELECT * FROM {language} ORDER BY weight ASC, name ASC')->fetchAllAssoc('language');
}
else {
// No locale module, so use the default language only.
diff --git a/core/includes/cache.inc b/core/includes/cache.inc
index 5d82fa0..e8c7477 100644
--- a/core/includes/cache.inc
+++ b/core/includes/cache.inc
@@ -40,158 +40,19 @@
}
/**
- * Returns data from the persistent cache.
- *
- * Data may be stored as either plain text or as serialized data. cache_get
- * will automatically return unserialized objects and arrays.
- *
- * @param $cid
- * The cache ID of the data to retrieve.
- * @param $bin
- * The cache bin to store the data in. Valid core values are 'cache_block',
- * 'cache_bootstrap', 'cache_field', 'cache_filter', 'cache_form',
- * 'cache_menu', 'cache_page', 'cache_path', 'cache_update' or 'cache' for
- * the default cache.
- *
- * @return
- * The cache or FALSE on failure.
+ * Expires data from the block and page caches.
*/
-function cache_get($cid, $bin = 'cache') {
- return cache($bin)->get($cid);
-}
-
-/**
- * Returns data from the persistent cache when given an array of cache IDs.
- *
- * @param $cids
- * An array of cache IDs for the data to retrieve. This is passed by
- * reference, and will have the IDs successfully returned from cache removed.
- * @param $bin
- * The cache bin where the data is stored.
- *
- * @return
- * An array of the items successfully returned from cache indexed by cid.
- */
-function cache_get_multiple(array &$cids, $bin = 'cache') {
- return cache($bin)->getMultiple($cids);
-}
-
-/**
- * Stores data in the persistent cache.
- *
- * The persistent cache is split up into several cache bins. In the default
- * cache implementation, each cache bin corresponds to a database table by the
- * same name. Other implementations might want to store several bins in data
- * structures that get flushed together. While it is not a problem for most
- * cache bins if the entries in them are flushed before their expire time, some
- * might break functionality or are extremely expensive to recalculate. These
- * will be marked with a (*). The other bins expired automatically by core.
- * Contributed modules can add additional bins and get them expired
- * automatically by implementing hook_flush_caches().
- *
- * - cache: Generic cache storage bin (used for variables, theme registry,
- * locale date, list of simpletest tests etc).
- *
- * - cache_block: Stores the content of various blocks.
- *
- * - cache field: Stores the field data belonging to a given object.
- *
- * - cache_filter: Stores filtered pieces of content.
- *
- * - cache_form(*): Stores multistep forms. Flushing this bin means that some
- * forms displayed to users lose their state and the data already submitted
- * to them.
- *
- * - cache_menu: Stores the structure of visible navigation menus per page.
- *
- * - cache_page: Stores generated pages for anonymous users. It is flushed
- * very often, whenever a page changes, at least for every ode and comment
- * submission. This is the only bin affected by the page cache setting on
- * the administrator panel.
- *
- * - cache path: Stores the system paths that have an alias.
- *
- * - cache update(*): Stores available releases. The update server (for
- * example, drupal.org) needs to produce the relevant XML for every project
- * installed on the current site. As this is different for (almost) every
- * site, it's very expensive to recalculate for the update server.
- *
- * The reasons for having several bins are as follows:
- *
- * - smaller bins mean smaller database tables and allow for faster selects and
- * inserts
- * - we try to put fast changing cache items and rather static ones into
- * different bins. The effect is that only the fast changing bins will need a
- * lot of writes to disk. The more static bins will also be better cacheable
- * with MySQL's query cache.
- *
- * @param $cid
- * The cache ID of the data to store.
- * @param $data
- * The data to store in the cache. Complex data types will be automatically
- * serialized before insertion.
- * Strings will be stored as plain text and not serialized.
- * @param $bin
- * The cache bin to store the data in. Valid core values are 'cache_block',
- * 'cache_bootstrap', 'cache_field', 'cache_filter', 'cache_form',
- * 'cache_menu', 'cache_page', 'cache_update' or 'cache' for the default
- * cache.
- * @param $expire
- * One of the following values:
- * - CACHE_PERMANENT: Indicates that the item should never be removed unless
- * explicitly told to using cache_clear_all() with a cache ID.
- * - CACHE_TEMPORARY: Indicates that the item should be removed at the next
- * general cache wipe.
- * - A Unix timestamp: Indicates that the item should be kept at least until
- * the given time, after which it behaves like CACHE_TEMPORARY.
- */
-function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT) {
- return cache($bin)->set($cid, $data, $expire);
-}
-
-/**
- * Expires data from the cache.
- *
- * If called without arguments, expirable entries will be cleared from the
- * cache_page and cache_block bins.
- *
- * @param $cid
- * If set, the cache ID to delete. Otherwise, all cache entries that can
- * expire are deleted.
- * @param $bin
- * If set, the cache bin to delete from. Mandatory argument if $cid is set.
- * @param $wildcard
- * If TRUE, cache IDs starting with $cid are deleted in addition to the
- * exact cache ID specified by $cid. If $wildcard is TRUE and $cid is '*',
- * the entire cache bin is emptied.
- */
-function cache_clear_all($cid = NULL, $bin = NULL, $wildcard = FALSE) {
- if (!isset($cid) && !isset($bin)) {
- // Clear the block cache first, so stale data will
- // not end up in the page cache.
- if (module_exists('block')) {
- cache('block')->expire();
- }
- cache('page')->expire();
- return;
+function cache_clear_all() {
+ // @todo: remove before release.
+ if (func_get_args()) {
+ throw new Exception(t('cache_clear_all() no longer takes arguments, use cache() instead.'));
}
- return cache($bin)->clear($cid, $wildcard);
-}
-
-/**
- * Checks if a cache bin is empty.
- *
- * A cache bin is considered empty if it does not contain any valid data for any
- * cache ID.
- *
- * @param $bin
- * The cache bin to check.
- *
- * @return
- * TRUE if the cache bin specified is empty.
- */
-function cache_is_empty($bin) {
- return cache($bin)->isEmpty();
+ // Clear the block cache first, so stale data will
+ // not end up in the page cache.
+ if (module_exists('block')) {
+ cache('block')->expire();
+ }
+ cache('page')->expire();
}
/**
@@ -327,25 +188,6 @@
function garbageCollection();
/**
- * Expires data from the cache.
- *
- * If called without arguments, expirable entries will be cleared from the
- * cache_page and cache_block bins.
- *
- * @param $cid
- * If set, the cache ID to delete. Otherwise, all cache entries that can
- * expire are deleted.
- * @param $wildcard
- * If set to TRUE, the $cid is treated as a substring
- * to match rather than a complete ID. The match is a right hand
- * match. If '*' is given as $cid, the bin $bin will be emptied.
- *
- * @todo: This method is deprecated, as its functionality is covered by more
- * targeted methods in the interface.
- */
- function clear($cid = NULL, $wildcard = FALSE);
-
- /**
* Checks if a cache bin is empty.
*
* A cache bin is considered empty if it does not contain any valid data for
@@ -425,11 +267,6 @@
function garbageCollection() {}
/**
- * Implements DrupalCacheInterface::clear().
- */
- function clear($cid = NULL, $wildcard = FALSE) {}
-
- /**
* Implements DrupalCacheInterface::isEmpty().
*/
function isEmpty() {
@@ -450,8 +287,8 @@
* Constructs a new DrupalDatabaseCache object.
*/
function __construct($bin) {
- // All cache tables should be prefixed with 'cache_', apart from the
- // default 'cache' bin, which would look silly.
+ // All cache tables should be prefixed with 'cache_', except for the
+ // default 'cache' bin.
if ($bin != 'cache') {
$bin = 'cache_' . $bin;
}
@@ -522,9 +359,9 @@
// If enforcing a minimum cache lifetime, validate that the data is
// currently valid for this user before we return it by making sure the cache
// entry was created before the timestamp in the current session's cache
- // timer. The cache variable is loaded into the $user object by _drupal_session_read()
- // in session.inc. If the data is permanent or we're not enforcing a minimum
- // cache lifetime always return the cached data.
+ // timer. The cache variable is loaded into the $user object by
+ // _drupal_session_read() in session.inc. If the data is permanent or we're
+ // not enforcing a minimum cache lifetime always return the cached data.
if ($cache->expire != CACHE_PERMANENT && variable_get('cache_lifetime', 0) && $user->cache > $cache->created) {
// This cache data is too old and thus not valid for us, ignore it.
return FALSE;
@@ -562,7 +399,7 @@
->execute();
}
catch (Exception $e) {
- // The database may not be available, so we'll ignore cache_set requests.
+ // The database may not be available, so we'll ignore these calls.
}
}
@@ -617,12 +454,12 @@
$cache_flush = variable_get('cache_flush_' . $this->bin, 0);
if ($cache_flush == 0) {
- // This is the first request to clear the cache, start a timer.
+ // This is the first request to clear the cache; start a timer.
variable_set('cache_flush_' . $this->bin, REQUEST_TIME);
}
elseif (REQUEST_TIME > ($cache_flush + variable_get('cache_lifetime', 0))) {
- // Clear the cache for everyone, cache_lifetime seconds have
- // passed since the first request to clear the cache.
+ // Clear the cache for everyone; cache_lifetime seconds have passed
+ // since the first request to clear the cache.
db_delete($this->bin)
->condition('expire', CACHE_PERMANENT, '<>')
->condition('expire', REQUEST_TIME, '<')
@@ -631,7 +468,7 @@
}
}
else {
- // No minimum cache lifetime, flush all temporary cache entries now.
+ // No minimum cache lifetime; flush all temporary cache entries now.
db_delete($this->bin)
->condition('expire', CACHE_PERMANENT, '<>')
->condition('expire', REQUEST_TIME, '<')
@@ -649,40 +486,14 @@
// often since this will remove temporary cache items indiscriminately.
$cache_flush = variable_get('cache_flush_' . $this->bin, 0);
if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= REQUEST_TIME)) {
- // Reset the variable immediately to prevent a meltdown in heavy load situations.
+ // Reset the variable immediately to prevent a meltdown in heavy load
+ // situations.
variable_set('cache_flush_' . $this->bin, 0);
// Time to flush old cache data
db_delete($this->bin)
->condition('expire', CACHE_PERMANENT, '<>')
->condition('expire', $cache_flush, '<=')
->execute();
- }
- }
-
- /**
- * Implements DrupalCacheInterface::clear().
- */
- function clear($cid = NULL, $wildcard = FALSE) {
- global $user;
-
- if (empty($cid)) {
- $this->expire();
- }
- else {
- if ($wildcard) {
- if ($cid == '*') {
- $this->flush();
- }
- else {
- $this->deletePrefix($cid);
- }
- }
- elseif (is_array($cid)) {
- $this->deleteMultiple($cid);
- }
- else {
- $this->delete($cid);
- }
}
}
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 99fcdba..668dc39 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2957,8 +2957,13 @@
// Provide the page with information about the individual CSS files used,
// information not otherwise available when CSS aggregation is enabled.
- $setting['ajaxPageState']['css'] = array_fill_keys(array_keys($css), 1);
- $styles['#attached']['js'][] = array('type' => 'setting', 'data' => $setting);
+ // Skip if no files were added to the page or jQuery.extend() will overwrite
+ // the Drupal.settings.ajaxPageState.css object with an empty array.
+ // Cast the array to an object to be on the safe side even if not empty.
+ if (!empty($css)) {
+ $setting['ajaxPageState']['css'] = (object) array_fill_keys(array_keys($css), 1);
+ $styles['#attached']['js'][] = array('type' => 'setting', 'data' => $setting);
+ }
return drupal_render($styles);
}
@@ -6090,7 +6095,7 @@
* added to this string and is also part of the cache key in
* drupal_render_cache_set() and drupal_render_cache_get().
* @param $expire
- * The cache expire time, passed eventually to cache_set().
+ * The cache expire time, passed eventually to cache()->set().
* @param $granularity
* One or more granularity constants passed to drupal_render_cid_parts().
*
@@ -6136,7 +6141,7 @@
$cid_parts[] = $theme;
// If Locale is enabled but we have only one language we do not need it as cid
// part.
- if (drupal_multilingual()) {
+ if (language_multilingual()) {
foreach (language_types_configurable() as $language_type) {
$cid_parts[] = $GLOBALS[$language_type]->language;
}
@@ -6647,7 +6652,7 @@
'variables' => array('text' => NULL, 'path' => NULL, 'options' => array()),
),
'links' => array(
- 'variables' => array('links' => NULL, 'attributes' => array('class' => array('links')), 'heading' => array()),
+ 'variables' => array('links' => array(), 'attributes' => array('class' => array('links')), 'heading' => array()),
),
'image' => array(
// HTML 4 and XHTML 1.0 always require an alt attribute. The HTML 5 draft
@@ -7367,7 +7372,11 @@
system_rebuild_theme_data();
drupal_theme_rebuild();
- node_types_rebuild();
+ // @todo D8: Split cache flushing from rebuilding.
+ // @see http://drupal.org/node/996236
+ if (module_exists('node')) {
+ node_types_rebuild();
+ }
// node_menu() defines menu items based on node types so it needs to come
// after node types are rebuilt.
menu_rebuild();
diff --git a/core/includes/database/database.inc b/core/includes/database/database.inc
index dcf0d1e..7c96e07 100644
--- a/core/includes/database/database.inc
+++ b/core/includes/database/database.inc
@@ -1016,9 +1016,9 @@
throw new DatabaseTransactionNoActiveException();
}
// A previous rollback to an earlier savepoint may mean that the savepoint
- // in question has already been rolled back.
- if (!in_array($savepoint_name, $this->transactionLayers)) {
- return;
+ // in question has already been accidentally committed.
+ if (!isset($this->transactionLayers[$savepoint_name])) {
+ throw new DatabaseTransactionNoActiveException();
}
// We need to find the point we're rolling back to, all other savepoints
@@ -1096,8 +1096,12 @@
if (!$this->supportsTransactions()) {
return;
}
+ // The transaction has already been committed earlier. There is nothing we
+ // need to do. If this transaction was part of an earlier out-of-order
+ // rollback, an exception would already have been thrown by
+ // Database::rollback().
if (!isset($this->transactionLayers[$name])) {
- throw new DatabaseTransactionNoActiveException();
+ return;
}
// Mark this layer as committable.
diff --git a/core/includes/database/mysql/database.inc b/core/includes/database/mysql/database.inc
index a57f7dd..e024a7f 100644
--- a/core/includes/database/mysql/database.inc
+++ b/core/includes/database/mysql/database.inc
@@ -183,8 +183,11 @@
// succeed for MySQL error code 1305 ("SAVEPOINT does not exist").
if ($e->errorInfo[1] == '1305') {
// If one SAVEPOINT was released automatically, then all were.
- // Therefore, we keep just the topmost transaction.
- $this->transactionLayers = array('drupal_transaction' => 'drupal_transaction');
+ // Therefore, clean the transaction stack.
+ $this->transactionLayers = array();
+ // We also have to explain to PDO that the transaction stack has
+ // been cleaned-up.
+ PDO::commit();
}
else {
throw $e;
diff --git a/core/includes/database/query.inc b/core/includes/database/query.inc
index 9cdd878..0effeda 100644
--- a/core/includes/database/query.inc
+++ b/core/includes/database/query.inc
@@ -22,6 +22,9 @@
* parameters, they are taken as $field and $value with $operator having a
* value of IN if $value is an array and = otherwise.
*
+ * Do not use this method to test for NULL values. Instead, use
+ * QueryConditionInterface::isNull() or QueryConditionInterface::isNotNull().
+ *
* @param $field
* The name of the field to check. If you would like to add a more complex
* condition involving operators or functions, use where().
@@ -36,6 +39,9 @@
*
* @return QueryConditionInterface
* The called object.
+ *
+ * @see QueryConditionInterface::isNull()
+ * @see QueryConditionInterface::isNotNull()
*/
public function condition($field, $value = NULL, $operator = NULL);
diff --git a/core/includes/database/sqlite/database.inc b/core/includes/database/sqlite/database.inc
index 98b35a2..5de219e 100644
--- a/core/includes/database/sqlite/database.inc
+++ b/core/includes/database/sqlite/database.inc
@@ -59,7 +59,7 @@
$this->statementClass = NULL;
// This driver defaults to transaction support, except if explicitly passed FALSE.
- $this->transactionSupport = !isset($connection_options['transactions']) || $connection_options['transactions'] !== FALSE;
+ $this->transactionSupport = $this->transactionalDDLSupport = !isset($connection_options['transactions']) || $connection_options['transactions'] !== FALSE;
$this->connectionOptions = $connection_options;
diff --git a/core/includes/file.inc b/core/includes/file.inc
index 645c64b..babf465 100644
--- a/core/includes/file.inc
+++ b/core/includes/file.inc
@@ -828,6 +828,10 @@
* is reported.
* - If file already exists in $destination either the call will error out,
* replace the file or rename the file based on the $replace parameter.
+ * - Provides a fallback using realpaths if the move fails using stream
+ * wrappers. This can occur because PHP's copy() function does not properly
+ * support streams if safe_mode or open_basedir are enabled. See
+ * https://bugs.php.net/bug.php?id=60456
*
* @param $source
* A string specifying the filepath or URI of the source file.
@@ -907,8 +911,12 @@
file_ensure_htaccess();
// Perform the copy operation.
if (!@copy($source, $destination)) {
- watchdog('file', 'The specified file %file could not be copied to %destination.', array('%file' => $source, '%destination' => $destination), WATCHDOG_ERROR);
- return FALSE;
+ // If the copy failed and realpaths exist, retry the operation using them
+ // instead.
+ if ($real_source === FALSE || $real_destination === FALSE || !@copy($real_source, $real_destination)) {
+ watchdog('file', 'The specified file %file could not be copied to %destination.', array('%file' => $source, '%destination' => $destination), WATCHDOG_ERROR);
+ return FALSE;
+ }
}
// Set the permissions on the new file.
diff --git a/core/includes/gettext.inc b/core/includes/gettext.inc
index 08fa38f..61ced9d 100644
--- a/core/includes/gettext.inc
+++ b/core/includes/gettext.inc
@@ -1095,6 +1095,7 @@
function _locale_export_remove_plural($entry) {
return preg_replace('/(@count)\[[0-9]\]/', '\\1', $entry);
}
+
/**
* @} End of "locale-api-import-export"
*/
diff --git a/core/includes/graph.inc b/core/includes/graph.inc
index 416fad6..7fcc57a 100644
--- a/core/includes/graph.inc
+++ b/core/includes/graph.inc
@@ -143,4 +143,3 @@
// topological order if the graph is acyclic.
$state['last_visit_order'][] = $start;
}
-
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 091618f..f76606b 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -533,8 +533,8 @@
// Determine whether translation import tasks will need to be performed.
$needs_translations = count($install_state['translations']) > 1 && !empty($install_state['parameters']['langcode']) && $install_state['parameters']['langcode'] != 'en';
- // The first two installation tasks are (by default) language selection and
- // profile selection.
+ // Start with the core installation tasks that run before handing control
+ // to the install profile.
$tasks = array(
'install_select_language' => array(
'display_name' => st('Choose language'),
@@ -1119,12 +1119,15 @@
}
foreach ($names as $profile => $name) {
+ // The profile name and description are extracted for translation from the
+ // .info file, so we can use st() on them even though they are dynamic data
+ // at this point.
$form['profile'][$name] = array(
'#type' => 'radio',
'#value' => 'standard',
'#return_value' => $profile,
- '#title' => $name,
- '#description' => isset($profiles[$profile]['description']) ? $profiles[$profile]['description'] : '',
+ '#title' => st($name),
+ '#description' => isset($profiles[$profile]['description']) ? st($profiles[$profile]['description']) : '',
'#parents' => array('profile'),
);
}
@@ -1146,7 +1149,7 @@
foreach ($files as $key => $file) {
// Strip off the file name component before the language code.
$files[$key]->langcode = preg_replace('!^(.+\.)?([^\.]+)$!', '\2', $file->name);
- // Language codes cannot exceed 12 characters to fit into the {languages}
+ // Language codes cannot exceed 12 characters to fit into the {language}
// table.
if (strlen($files[$key]->langcode) > 12) {
unset($files[$key]);
@@ -1229,19 +1232,6 @@
return;
}
else {
- // Allow profile to pre-select the language, skipping the selection.
- if (isset($install_state['parameters']['profile'])) {
- $info = install_profile_info($install_state['parameters']['profile']);
- if (isset($info['langcode'])) {
- foreach ($files as $file) {
- if ($info['langcode'] == $file->langcode) {
- $install_state['parameters']['langcode'] = $file->langcode;
- return;
- }
- }
- }
- }
-
// We still don't have a langcode, so display a form for selecting one.
// Only do this in the case of interactive installations, since this is
// not a real form with submit handlers (the database isn't even set up
@@ -1277,7 +1267,7 @@
$select_options[$file->langcode] = $standard_languages[$file->langcode][1];
}
else {
- // If language not found in standard.inc, display it's langcode
+ // If the language was not found in standard.inc, display its langcode.
$select_options[$file->langcode] = $file->langcode;
}
// Build a list of languages simulated for browser detection.
@@ -1432,7 +1422,7 @@
'name' => $langcode,
'default' => TRUE,
);
- locale_language_save($language);
+ language_save($language);
}
else {
// A known predefined language, details will be filled in properly.
@@ -1440,7 +1430,7 @@
'language' => $langcode,
'default' => TRUE,
);
- locale_language_save($language);
+ language_save($language);
}
// Collect files to import for this language.
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 8d7f22d..533678f 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -663,7 +663,6 @@
*/
function drupal_verify_profile($install_state) {
$profile = $install_state['parameters']['profile'];
- $langcode = $install_state['parameters']['langcode'];
include_once DRUPAL_ROOT . '/core/includes/file.inc';
include_once DRUPAL_ROOT . '/core/includes/common.inc';
@@ -1101,7 +1100,7 @@
if (!isset($strings)) {
$strings = array();
- if (isset($install_state['parameters']['profile']) && isset($install_state['parameters']['langcode'])) {
+ if (isset($install_state['parameters']['langcode'])) {
// If the given langcode was selected, there should be at least one .po file
// with its name ending in install.{$install_state['parameters']['langcode']}.po
// This might or might not be the entire filename. It is also possible
@@ -1264,13 +1263,8 @@
'version' => NULL,
'hidden' => FALSE,
'php' => DRUPAL_MINIMUM_PHP,
- 'langcode' => NULL,
- 'custom_language_selection' => FALSE,
);
$info = drupal_parse_info_file("profiles/$profile/$profile.info") + $defaults;
- if (isset($info['langcode'])) {
- $info['custom_language_selection'] = TRUE;
- }
$info['dependencies'] = array_unique(array_merge(
drupal_required_modules(),
$info['dependencies'],
diff --git a/core/includes/locale.inc b/core/includes/locale.inc
index 4cd0c59..d218236 100644
--- a/core/includes/locale.inc
+++ b/core/includes/locale.inc
@@ -535,63 +535,6 @@
}
/**
- * API function to add or update a language.
- *
- * @param $language
- * Language object with properties corresponding to 'languages' table columns.
- */
-function locale_language_save($language) {
- $language->is_new = !(bool) db_query_range('SELECT 1 FROM {languages} WHERE language = :language', 0, 1, array(':language' => $language->language))->fetchField();
-
- // If name was not set, we add a predefined language.
- if (!isset($language->name)) {
- include_once DRUPAL_ROOT . '/core/includes/standard.inc';
- $predefined = standard_language_list();
- $language->name = $predefined[$language->language][0];
- $language->direction = isset($predefined[$language->language][2]) ? $predefined[$language->language][2] : LANGUAGE_LTR;
- }
-
- // Set to enabled for the default language and unless specified otherwise.
- if (!empty($language->default) || !isset($language->enabled)) {
- $language->enabled = TRUE;
- }
- // Let other modules modify $language before saved.
- module_invoke_all('locale_language_presave', $language);
-
- // Save the record and inform others about the change.
- if ($language->is_new) {
- drupal_write_record('languages', $language);
- module_invoke_all('locale_language_insert', $language);
- watchdog('locale', 'The %language (%langcode) language has been created.', array('%language' => $language->name, '%langcode' => $language->language));
- }
- else {
- drupal_write_record('languages', $language, array('language'));
- module_invoke_all('locale_language_update', $language);
- watchdog('locale', 'The %language (%langcode) language has been updated.', array('%language' => $language->name, '%langcode' => $language->language));
- }
-
- if (!empty($language->default)) {
- // Set the new version of this language as default in a variable.
- $default_language = language_default();
- variable_set('language_default', $language);
- }
-
- // Update language count based on enabled language count.
- variable_set('language_count', db_query('SELECT COUNT(language) FROM {languages} WHERE enabled = 1')->fetchField());
-
- // Kill the static cache in language_list().
- drupal_static_reset('language_list');
-
- // @todo move these two cache clears out. See http://drupal.org/node/1293252
- // Changing the language settings impacts the interface.
- cache_clear_all('*', 'cache_page', TRUE);
- // Force JavaScript translation file re-creation for the modified language.
- _locale_invalidate_js($language->language);
-
- return $language;
-}
-
-/**
* Parses a JavaScript file, extracts strings wrapped in Drupal.t() and
* Drupal.formatPlural() and inserts them into the database.
*/
@@ -864,34 +807,6 @@
return TRUE;
}
}
-
-/**
- * @defgroup locale-api-predefined List of predefined languages
- * @{
- * API to provide a list of predefined languages.
- */
-
-/**
- * Prepares the language code list for a select form item with only the unsupported ones
- */
-function _locale_prepare_predefined_list() {
- include_once DRUPAL_ROOT . '/core/includes/standard.inc';
- $languages = language_list();
- $predefined = standard_language_list();
- foreach ($predefined as $key => $value) {
- if (isset($languages[$key])) {
- unset($predefined[$key]);
- continue;
- }
- $predefined[$key] = t($value[0]);
- }
- asort($predefined);
- return $predefined;
-}
-
-/**
- * @} End of "locale-api-languages-predefined"
- */
/**
* Get list of all predefined and custom countries.
diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index 3011a3b..9412310 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -224,19 +224,14 @@
*/
/**
- * Internal menu status code -- Menu item was found.
- */
-const MENU_FOUND = 1;
-
-/**
* Internal menu status code -- Menu item was not found.
*/
-const MENU_NOT_FOUND = 2;
+const MENU_NOT_FOUND = 404;
/**
* Internal menu status code -- Menu item access is denied.
*/
-const MENU_ACCESS_DENIED = 3;
+const MENU_ACCESS_DENIED = 403;
/**
* Internal menu status code -- Menu item inaccessible because site is offline.
@@ -2617,17 +2612,7 @@
* Clears the cached cached data for a single named menu.
*/
function menu_cache_clear($menu_name = 'navigation') {
- $cache_cleared = &drupal_static(__FUNCTION__, array());
-
- if (empty($cache_cleared[$menu_name])) {
- cache('menu')->deletePrefix('links:' . $menu_name . ':');
- $cache_cleared[$menu_name] = 1;
- }
- elseif ($cache_cleared[$menu_name] == 1) {
- drupal_register_shutdown_function('cache_clear_all', 'links:' . $menu_name . ':', 'cache_menu', TRUE);
- $cache_cleared[$menu_name] = 2;
- }
-
+ cache('menu')->deletePrefix('links:' . $menu_name . ':');
// Also clear the menu system static caches.
menu_reset_static_cache();
}
diff --git a/core/includes/module.inc b/core/includes/module.inc
index 221ad60..1a52a80 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -520,11 +520,6 @@
foreach ($module_list as $module) {
if (module_exists($module)) {
- // Check if node_access table needs rebuilding.
- if (!node_access_needs_rebuild() && module_hook($module, 'node_grants')) {
- node_access_needs_rebuild(TRUE);
- }
-
module_load_install($module);
module_invoke($module, 'disable');
db_update('system')
@@ -548,12 +543,6 @@
// Update the registry to remove the newly-disabled module.
registry_update();
_system_update_bootstrap_status();
- }
-
- // If there remains no more node_access module, rebuilding will be
- // straightforward, we can do it right now.
- if (node_access_needs_rebuild() && count(module_implements('node_grants')) == 0) {
- node_access_rebuild();
}
}
@@ -700,10 +689,10 @@
// request. Benchmarks show that the benefit of this caching outweighs the
// additional database hit even when using the default database caching
// backend and only a small number of modules are enabled. The cost of the
- // cache_get() is more or less constant and reduced further when non-database
- // caching backends are used, so there will be more significant gains when a
- // large number of modules are installed or hooks invoked, since this can
- // quickly lead to module_hook() being called several thousand times
+ // cache('bootstrap')->get() is more or less constant and reduced further when
+ // non-database caching backends are used, so there will be more significant
+ // gains when a large number of modules are installed or hooks invoked, since
+ // this can quickly lead to module_hook() being called several thousand times
// per request.
drupal_static_reset('module_implements');
cache('bootstrap')->set('module_implements', array());
@@ -1018,4 +1007,3 @@
$function($data, $context1, $context2);
}
}
-
diff --git a/core/includes/password.inc b/core/includes/password.inc
index 9020fbb..b052a4a 100644
--- a/core/includes/password.inc
+++ b/core/includes/password.inc
@@ -286,4 +286,3 @@
// Check whether the iteration count used differs from the standard number.
return (_password_get_count_log2($account->pass) !== $count_log2);
}
-
diff --git a/core/includes/path.inc b/core/includes/path.inc
index 1fac235..9ae1875 100644
--- a/core/includes/path.inc
+++ b/core/includes/path.inc
@@ -16,7 +16,7 @@
// Ensure $_GET['q'] is set before calling drupal_normal_path(), to support
// path caching with hook_url_inbound_alter().
if (empty($_GET['q'])) {
- $_GET['q'] = variable_get('site_frontpage', 'node');
+ $_GET['q'] = variable_get('site_frontpage', 'user');
}
$_GET['q'] = drupal_get_normal_path($_GET['q']);
}
@@ -292,7 +292,7 @@
if (!isset($is_front_page)) {
// As drupal_path_initialize updates $_GET['q'] with the 'site_frontpage' path,
// we can check it against the 'site_frontpage' variable.
- $is_front_page = ($_GET['q'] == variable_get('site_frontpage', 'node'));
+ $is_front_page = ($_GET['q'] == variable_get('site_frontpage', 'user'));
}
return $is_front_page;
@@ -323,7 +323,7 @@
$replacements = array(
'|',
'.*',
- '\1' . preg_quote(variable_get('site_frontpage', 'node'), '/') . '\2'
+ '\1' . preg_quote(variable_get('site_frontpage', 'user'), '/') . '\2'
);
$patterns_quoted = preg_quote($patterns, '/');
$regexps[$patterns] = '/^(' . preg_replace($to_replace, $replacements, $patterns_quoted) . ')$/';
diff --git a/core/includes/registry.inc b/core/includes/registry.inc
index 8961f7a..2ddd1f7 100644
--- a/core/includes/registry.inc
+++ b/core/includes/registry.inc
@@ -183,4 +183,3 @@
/**
* @} End of "defgroup registry".
*/
-
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index b785c19..94d69d2 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -652,7 +652,7 @@
// serve as the basic registry. Since the list of enabled modules is the same
// regardless of the theme used, this is cached in its own entry to save
// building it for every theme.
- if ($cached = cache_get('theme_registry:build:modules')) {
+ if ($cached = cache()->get('theme_registry:build:modules')) {
$cache = $cached->data;
}
else {
@@ -661,7 +661,7 @@
}
// Only cache this registry if all modules are loaded.
if (module_load_all(NULL)) {
- cache_set('theme_registry:build:modules', $cache);
+ cache()->set('theme_registry:build:modules', $cache);
}
}
@@ -1561,73 +1561,79 @@
* http://www.w3.org/TR/WCAG-TECHS/H42.html for more information.
*/
function theme_links($variables) {
+ global $language_url;
+
$links = $variables['links'];
$attributes = $variables['attributes'];
$heading = $variables['heading'];
- global $language_url;
$output = '';
- if (count($links) > 0) {
- $output = '';
-
- // Treat the heading first if it is present to prepend it to the
- // list of links.
+ if (!empty($links)) {
+ // Prepend the heading to the list, if any.
if (!empty($heading)) {
+ // Convert a string heading into an array, using a H2 tag by default.
if (is_string($heading)) {
- // Prepare the array that will be used when the passed heading
- // is a string.
- $heading = array(
- 'text' => $heading,
- // Set the default level of the heading.
- 'level' => 'h2',
- );
+ $heading = array('text' => $heading);
}
- $output .= '<' . $heading['level'];
- if (!empty($heading['class'])) {
- $output .= drupal_attributes(array('class' => $heading['class']));
+ // Merge in default array properties into $heading.
+ $heading += array(
+ 'level' => 'h2',
+ 'attributes' => array(),
+ );
+ // @todo Remove backwards compatibility for $heading['class'].
+ if (isset($heading['class'])) {
+ $heading['attributes']['class'] = $heading['class'];
}
- $output .= '>' . check_plain($heading['text']) . '' . $heading['level'] . '>';
+
+ $output .= '<' . $heading['level'] . drupal_attributes($heading['attributes']) . '>';
+ $output .= check_plain($heading['text']);
+ $output .= '' . $heading['level'] . '>';
}
$output .= '
';
$num_links = count($links);
- $i = 1;
-
+ $i = 0;
foreach ($links as $key => $link) {
- $class = array($key);
+ $i++;
- // Add first, last and active classes to the list of links to help out themers.
+ $class = array();
+ // Use the array key as class name.
+ $class[] = drupal_html_class($key);
+ // Add odd/even, first, and last classes.
+ $class[] = ($i % 2 ? 'odd' : 'even');
if ($i == 1) {
$class[] = 'first';
}
if ($i == $num_links) {
$class[] = 'last';
}
- if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '' && drupal_is_front_page()))
- && (empty($link['language']) || $link['language']->language == $language_url->language)) {
- $class[] = 'active';
- }
- $output .= '
$class)) . '>';
+ // Handle links.
if (isset($link['href'])) {
+ $is_current_path = ($link['href'] == $_GET['q'] || ($link['href'] == '' && drupal_is_front_page()));
+ $is_current_language = (empty($link['language']) || $link['language']->language == $language_url->language);
+ if ($is_current_path && $is_current_language) {
+ $class[] = 'active';
+ }
// Pass in $link as $options, they share the same keys.
- $output .= l($link['title'], $link['href'], $link);
+ $item = l($link['title'], $link['href'], $link);
}
- elseif (!empty($link['title'])) {
- // Some links are actually not links, but we wrap these in for adding title and class attributes.
- if (empty($link['html'])) {
- $link['title'] = check_plain($link['title']);
- }
- $span_attributes = '';
- if (isset($link['attributes'])) {
- $span_attributes = drupal_attributes($link['attributes']);
- }
- $output .= '' . $link['title'] . '';
+ // Handle title-only text items.
+ else {
+ // Merge in default array properties into $link.
+ $link += array(
+ 'html' => FALSE,
+ 'attributes' => array(),
+ );
+ $item = '';
+ $item .= ($link['html'] ? $link['title'] : check_plain($link['title']));
+ $item .= '';
}
- $i++;
- $output .= "
";return k},_adjustInstDate:function(a,b,c){var e=a.drawYear+(c=="Y"?b:0),f=a.drawMonth+
+(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&ba?a:b},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");if(b)b.apply(a.input?
+a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);c=this._daylightSavingAdjust(new Date(c,
+e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,
+"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=function(a){if(!this.length)return this;
+if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));return this.each(function(){typeof a==
+"string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new M;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.16";window["DP_jQuery_"+B]=d})(jQuery);
diff --git a/core/misc/ui/jquery.ui.dialog.css b/core/misc/ui/jquery.ui.dialog.css
index 156e03a..1b95d7f 100644
--- a/core/misc/ui/jquery.ui.dialog.css
+++ b/core/misc/ui/jquery.ui.dialog.css
@@ -1,16 +1,15 @@
-
/*
- * jQuery UI Dialog 1.8.7
+ * jQuery UI Dialog 1.8.16
*
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Dialog#theming
*/
.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
-.ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative; }
-.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; }
+.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
diff --git a/core/misc/ui/jquery.ui.dialog.min.js b/core/misc/ui/jquery.ui.dialog.min.js
index d60151c..a16bf9e 100644
--- a/core/misc/ui/jquery.ui.dialog.min.js
+++ b/core/misc/ui/jquery.ui.dialog.min.js
@@ -1,8 +1,7 @@
-
/*
- * jQuery UI Dialog 1.8.7
+ * jQuery UI Dialog 1.8.16
*
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
@@ -17,25 +16,25 @@
* jquery.ui.position.js
* jquery.ui.resizable.js
*/
-(function(c,j){var k={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},l={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&
-c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||" ",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",
--1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),h=c('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role",
-"button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("").addClass("ui-dialog-title").attr("id",e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=
-b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");a.uiDialog.remove();a.originalTitle&&
-a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!==b.uiDialog[0]){e=c(this).css("z-index");
-isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.attr("scrollTop"),scrollLeft:d.element.attr("scrollLeft")};c.ui.dialog.maxZ+=1;d.uiDialog.css("z-index",c.ui.dialog.maxZ);
-d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target===f[0]&&e.shiftKey){g.focus(1);return false}}});
-c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a,function(){return!(d=true)});if(d){c.each(a,function(f,
-h){h=c.isFunction(h)?{click:h,text:f}:h;f=c('').attr(h,true).unbind("click").click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.fn.button&&f.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=
-d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition,originalSize:f.originalSize,
-position:f.position,size:f.size}}a=a===j?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize",f,b(h))},stop:function(f,
-h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "):[a[0],a[1]];if(b.length===
-1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f);if(g in k)e=true;if(g in
-l)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"):e.removeClass("ui-dialog-disabled");
-break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a=this.options,b,d,e=
-this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height-b,0));this.uiDialog.is(":data(resizable)")&&
-this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.7",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(a){if(this.instances.length===
-0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),
-height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);
-b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+
+b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&!i.isDefaultPrevented()&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),
+h=c('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("").addClass("ui-dialog-title").attr("id",
+e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");
+a.uiDialog.remove();a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!==
+b.uiDialog[0]){e=c(this).css("z-index");isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()};c.ui.dialog.maxZ+=1;
+d.uiDialog.css("z-index",c.ui.dialog.maxZ);d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target===
+f[0]&&e.shiftKey){g.focus(1);return false}}});c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a,
+function(){return!(d=true)});if(d){c.each(a,function(f,h){h=c.isFunction(h)?{click:h,text:f}:h;var i=c('').click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.each(h,function(j,k){if(j!=="click")j in o?i[j](k):i.attr(j,k)});c.fn.button&&i.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",
+handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition,
+originalSize:f.originalSize,position:f.position,size:f.size}}a=a===l?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize",
+f,b(h))},stop:function(f,h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "):
+[a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f);
+if(g in m)e=true;if(g in n)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"):
+e.removeClass("ui-dialog-disabled");break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a=
+this.options,b,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height-
+b,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.16",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),
+create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&&
+c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return athis.containment[2])e=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/
-b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.topthis.containment[3])?g:!(g-this.offset.click.topthis.containment[2])?e:!(e-this.offset.click.left').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")})},
-stop:function(){d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("opacity"))b._opacity=a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable");if(a.scrollParent[0]!=
-document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){if(!c.axis||c.axis!="x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY=0;h--){var i=c.snapElements[h].left,k=i+c.snapElements[h].width,j=c.snapElements[h].top,l=j+c.snapElements[h].height;if(i-e').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")});return true},_mouseStart:function(a){var b=this.options;
+this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});
+this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);d.ui.ddmanager&&d.ui.ddmanager.dragStart(this,a);return true},
+_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b=
+false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,
+10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},_mouseUp:function(a){this.options.iframeFix===true&&d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});d.ui.ddmanager&&d.ui.ddmanager.dragStop(this,a);return d.ui.mouse.prototype._mouseUp.call(this,a)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle||
+!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone().removeAttr("id"):this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&&
+a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=
+this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),
+10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),
+10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[a.containment=="document"?0:d(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,a.containment=="document"?0:d(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,
+(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){a=d(a.containment);var b=a[0];if(b){a.offset();var c=d(b).css("overflow")!=
+"hidden";this.containment=[(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0),(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0),(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),
+10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=a}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+
+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&
+!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,h=a.pageY;if(this.originalPosition){var g;if(this.containment){if(this.relative_container){g=this.relative_container.offset();g=[this.containment[0]+g.left,this.containment[1]+g.top,this.containment[2]+g.left,this.containment[3]+g.top]}else g=this.containment;if(a.pageX-this.offset.click.leftg[2])e=g[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>g[3])h=g[3]+this.offset.click.top}if(b.grid){h=b.grid[1]?this.originalPageY+Math.round((h-this.originalPageY)/b.grid[1])*b.grid[1]:this.originalPageY;h=g?!(h-this.offset.click.topg[3])?h:!(h-this.offset.click.topg[2])?e:!(e-this.offset.click.left=0;i--){var j=c.snapElements[i].left,l=j+c.snapElements[i].width,k=c.snapElements[i].top,m=k+c.snapElements[i].height;if(j-e=j&&f<=l||h>=j&&h<=l||fl)&&(e>=
i&&e<=k||g>=i&&g<=k||ek);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);
-return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;a.target==this._mouseDownEvent.target&&c.data(a.target,this.widgetName+".preventClickEvent",
-true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
+(function(b){var d=false;b(document).mouseup(function(){d=false});b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(c){return a._mouseDown(c)}).bind("click."+this.widgetName,function(c){if(true===b.data(c.target,a.widgetName+".preventClickEvent")){b.removeData(c.target,a.widgetName+".preventClickEvent");c.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+
+this.widgetName)},_mouseDown:function(a){if(!d){this._mouseStarted&&this._mouseUp(a);this._mouseDownEvent=a;var c=this,f=a.which==1,g=typeof this.options.cancel=="string"&&a.target.nodeName?b(a.target).closest(this.options.cancel).length:false;if(!f||g||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){c.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=
+this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();return true}}true===b.data(a.target,this.widgetName+".preventClickEvent")&&b.removeData(a.target,this.widgetName+".preventClickEvent");this._mouseMoveDelegate=function(e){return c._mouseMove(e)};this._mouseUpDelegate=function(e){return c._mouseUp(e)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);a.preventDefault();return d=true}},_mouseMove:function(a){if(b.browser.msie&&
+!(document.documentMode>=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=
+false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
diff --git a/core/misc/ui/jquery.ui.position.min.js b/core/misc/ui/jquery.ui.position.min.js
index 2e1451e..42d9365 100644
--- a/core/misc/ui/jquery.ui.position.min.js
+++ b/core/misc/ui/jquery.ui.position.min.js
@@ -1,8 +1,7 @@
-
/*
- * jQuery UI Position 1.8.7
+ * jQuery UI Position 1.8.16
*
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
@@ -10,8 +9,8 @@
*/
(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY,
left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+=
-k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+parseInt(c.curCSS(this,"marginRight",true))||0,w=m+q+parseInt(c.curCSS(this,"marginBottom",true))||0,i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-=m/2;
-i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left=
+k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-=
+m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left=
d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+=
a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b),
g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery);
diff --git a/core/misc/ui/jquery.ui.progressbar.css b/core/misc/ui/jquery.ui.progressbar.css
index 7561030..e885ced 100644
--- a/core/misc/ui/jquery.ui.progressbar.css
+++ b/core/misc/ui/jquery.ui.progressbar.css
@@ -1,12 +1,11 @@
-
/*
- * jQuery UI Progressbar 1.8.7
+ * jQuery UI Progressbar 1.8.16
*
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Progressbar#theming
*/
.ui-progressbar { height:2em; text-align: left; }
-.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file
diff --git a/core/misc/ui/jquery.ui.progressbar.min.js b/core/misc/ui/jquery.ui.progressbar.min.js
index 7a8f0b7..b758eba 100644
--- a/core/misc/ui/jquery.ui.progressbar.min.js
+++ b/core/misc/ui/jquery.ui.progressbar.min.js
@@ -1,8 +1,7 @@
-
/*
- * jQuery UI Progressbar 1.8.7
+ * jQuery UI Progressbar 1.8.16
*
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
@@ -14,4 +13,4 @@
*/
(function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow");
this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*
-this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.7"})})(jQuery);
+this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.16"})})(jQuery);
diff --git a/core/misc/ui/jquery.ui.resizable.css b/core/misc/ui/jquery.ui.resizable.css
index e0f15cc..dc70679 100644
--- a/core/misc/ui/jquery.ui.resizable.css
+++ b/core/misc/ui/jquery.ui.resizable.css
@@ -1,15 +1,14 @@
-
/*
- * jQuery UI Resizable 1.8.7
+ * jQuery UI Resizable 1.8.16
*
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Resizable#theming
*/
.ui-resizable { position: relative;}
-.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; }
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
@@ -18,4 +17,4 @@
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
-.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
\ No newline at end of file
diff --git a/core/misc/ui/jquery.ui.resizable.min.js b/core/misc/ui/jquery.ui.resizable.min.js
index 4df6eb7..d6b71b3 100644
--- a/core/misc/ui/jquery.ui.resizable.min.js
+++ b/core/misc/ui/jquery.ui.resizable.min.js
@@ -1,8 +1,7 @@
-
/*
- * jQuery UI Resizable 1.8.7
+ * jQuery UI Resizable 1.8.16
*
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
@@ -18,31 +17,33 @@
top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=
this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",
nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor==
-String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),k=0;k=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,k);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection();
-this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){e(this).removeClass("ui-resizable-autohide");b._handles.show()},function(){if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};
-if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),
-d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"});this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=
-this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:
-this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis];if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",
-b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;
-f={width:c.size.width-(f?0:c.sizeDiff.width),height:c.size.height-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",
-b);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(l(b.left))this.position.left=b.left;if(l(b.top))this.position.top=b.top;if(l(b.height))this.size.height=b.height;if(l(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(d=="nw"){b.top=
-a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,d=l(b.width)&&a.maxWidth&&a.maxWidthb.width,h=l(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,
-k=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&k)b.left=i-a.minWidth;if(d&&k)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+
-a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,
-arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,
-{version:"1.8.7"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,
-function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var k=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:k.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=
-(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(k.css("position"))){c._revertToRelativePosition=true;k.css({position:"absolute",top:"auto",left:"auto"})}k.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType?e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=
-false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a=e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-
-a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",
-b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top",
-"Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,
-f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=
-a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+
-a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition,f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&
-e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",
-height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b=e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=
-d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},l=function(b){return!isNaN(parseInt(b,10))}})(jQuery);
+String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),l=0;l=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,l);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection();
+this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){if(!a.disabled){e(this).removeClass("ui-resizable-autohide");b._handles.show()}},function(){if(!a.disabled)if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();
+var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=
+false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"});
+this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff=
+{width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis];
+if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},
+_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;f=f?0:c.sizeDiff.width;f={width:c.helper.width()-f,height:c.helper.height()-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,
+{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",b);this._helper&&this.helper.remove();return false},_updateVirtualBoundaries:function(b){var a=this.options,c,d,f;a={minWidth:k(a.minWidth)?a.minWidth:0,maxWidth:k(a.maxWidth)?a.maxWidth:Infinity,minHeight:k(a.minHeight)?a.minHeight:0,maxHeight:k(a.maxHeight)?a.maxHeight:
+Infinity};if(this._aspectRatio||b){b=a.minHeight*this.aspectRatio;d=a.minWidth/this.aspectRatio;c=a.maxHeight*this.aspectRatio;f=a.maxWidth/this.aspectRatio;if(b>a.minWidth)a.minWidth=b;if(d>a.minHeight)a.minHeight=d;if(cb.width,h=k(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,l=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&l)b.left=i-a.minWidth;if(d&&l)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=
+null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+
+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+
+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);
+b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,{version:"1.8.16"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),
+10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-
+f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var l=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:l.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(l.css("position"))){c._revertToRelativePosition=true;l.css({position:"absolute",top:"auto",left:"auto"})}l.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType?
+e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a=
+e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,
+step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=
+e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top","Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;
+var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:
+a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-
+d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition,
+f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,
+display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b=
+e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=
+d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},k=function(b){return!isNaN(parseInt(b,10))}})(jQuery);
diff --git a/core/misc/ui/jquery.ui.selectable.css b/core/misc/ui/jquery.ui.selectable.css
index 1489dcf..2d505fb 100644
--- a/core/misc/ui/jquery.ui.selectable.css
+++ b/core/misc/ui/jquery.ui.selectable.css
@@ -1,8 +1,7 @@
-
/*
- * jQuery UI Selectable 1.8.7
+ * jQuery UI Selectable 1.8.16
*
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
diff --git a/core/misc/ui/jquery.ui.selectable.min.js b/core/misc/ui/jquery.ui.selectable.min.js
index e2ec516..3c600af 100644
--- a/core/misc/ui/jquery.ui.selectable.min.js
+++ b/core/misc/ui/jquery.ui.selectable.min.js
@@ -1,8 +1,7 @@
-
/*
- * jQuery UI Selectable 1.8.7
+ * jQuery UI Selectable 1.8.16
*
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
@@ -20,4 +19,4 @@
this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.righti||a.bottomb&&a.rightg&&a.bottom");if(!a.values)a.values=[this._valueMin(),this._valueMin()];if(a.values.length&&a.values.length!==2)a.values=[a.values[0],a.values[0]]}else this.range=d("");this.range.appendTo(this.element).addClass("ui-slider-range");if(a.range==="min"||a.range==="max")this.range.addClass("ui-slider-range-"+a.range);this.range.addClass("ui-widget-header")}d(".ui-slider-handle",this.element).length===0&&d("").appendTo(this.element).addClass("ui-slider-handle");
-if(a.values&&a.values.length)for(;d(".ui-slider-handle",this.element).length").appendTo(this.element).addClass("ui-slider-handle");this.handles=d(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(c){c.preventDefault()}).hover(function(){a.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(a.disabled)d(this).blur();
-else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(c){d(this).data("index.ui-slider-handle",c)});this.handles.keydown(function(c){var e=true,f=d(this).data("index.ui-slider-handle"),h,g,i;if(!b.options.disabled){switch(c.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:e=
-false;if(!b._keySliding){b._keySliding=true;d(this).addClass("ui-state-active");h=b._start(c,f);if(h===false)return}break}i=b.options.step;h=b.options.values&&b.options.values.length?(g=b.values(f)):(g=b.value());switch(c.keyCode){case d.ui.keyCode.HOME:g=b._valueMin();break;case d.ui.keyCode.END:g=b._valueMax();break;case d.ui.keyCode.PAGE_UP:g=b._trimAlignValue(h+(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:g=b._trimAlignValue(h-(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(h===
-b._valueMax())return;g=b._trimAlignValue(h+i);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(h===b._valueMin())return;g=b._trimAlignValue(h-i);break}b._slide(c,f,g);return e}}).keyup(function(c){var e=d(this).data("index.ui-slider-handle");if(b._keySliding){b._keySliding=false;b._stop(c,e);b._change(c,e);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");
-this._mouseDestroy();return this},_mouseCapture:function(b){var a=this.options,c,e,f,h,g;if(a.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:b.pageX,y:b.pageY});e=this._valueMax()-this._valueMin()+1;h=this;this.handles.each(function(i){var j=Math.abs(c-h.values(i));if(e>j){e=j;f=d(this);g=i}});if(a.range===true&&this.values(1)===a.min){g+=1;f=d(this.handles[g])}if(this._start(b,
-g)===false)return false;this._mouseSliding=true;h._handleIndex=g;f.addClass("ui-state-active").focus();a=f.offset();this._clickOffset=!d(b.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:b.pageX-a.left-f.width()/2,top:b.pageY-a.top-f.height()/2-(parseInt(f.css("borderTopWidth"),10)||0)-(parseInt(f.css("borderBottomWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(b,g,c);return this._animateOff=true},_mouseStart:function(){return true},
-_mouseDrag:function(b){var a=this._normValueFromMouse({x:b.pageX,y:b.pageY});this._slide(b,this._handleIndex,a);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(b){var a;
-if(this.orientation==="horizontal"){a=this.elementSize.width;b=b.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{a=this.elementSize.height;b=b.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}a=b/a;if(a>1)a=1;if(a<0)a=0;if(this.orientation==="vertical")a=1-a;b=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+a*b)},_start:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=
-this.values(a);c.values=this.values()}return this._trigger("start",b,c)},_slide:function(b,a,c){var e;if(this.options.values&&this.options.values.length){e=this.values(a?0:1);if(this.options.values.length===2&&this.options.range===true&&(a===0&&c>e||a===1&&c1){this.options.values[b]=this._trimAlignValue(a);this._refreshValue();this._change(null,b)}if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;e=arguments[0];for(f=0;f=this._valueMax())return this._valueMax();var a=this.options.step>0?this.options.step:1,c=(b-this._valueMin())%a;alignValue=b-c;if(Math.abs(c)*2>=a)alignValue+=c>0?a:-a;return parseFloat(alignValue.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},
-_refreshValue:function(){var b=this.options.range,a=this.options,c=this,e=!this._animateOff?a.animate:false,f,h={},g,i,j,l;if(this.options.values&&this.options.values.length)this.handles.each(function(k){f=(c.values(k)-c._valueMin())/(c._valueMax()-c._valueMin())*100;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";d(this).stop(1,1)[e?"animate":"css"](h,a.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(k===0)c.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},a.animate);
-if(k===1)c.range[e?"animate":"css"]({width:f-g+"%"},{queue:false,duration:a.animate})}else{if(k===0)c.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},a.animate);if(k===1)c.range[e?"animate":"css"]({height:f-g+"%"},{queue:false,duration:a.animate})}g=f});else{i=this.value();j=this._valueMin();l=this._valueMax();f=l!==j?(i-j)/(l-j)*100:0;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";this.handle.stop(1,1)[e?"animate":"css"](h,a.animate);if(b==="min"&&this.orientation==="horizontal")this.range.stop(1,
-1)[e?"animate":"css"]({width:f+"%"},a.animate);if(b==="max"&&this.orientation==="horizontal")this.range[e?"animate":"css"]({width:100-f+"%"},{queue:false,duration:a.animate});if(b==="min"&&this.orientation==="vertical")this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},a.animate);if(b==="max"&&this.orientation==="vertical")this.range[e?"animate":"css"]({height:100-f+"%"},{queue:false,duration:a.animate})}}});d.extend(d.ui.slider,{version:"1.8.7"})})(jQuery);
+(function(d){d.widget("ui.slider",d.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var a=this,b=this.options,c=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f=b.values&&b.values.length||1,e=[];this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+
+this.orientation+" ui-widget ui-widget-content ui-corner-all"+(b.disabled?" ui-slider-disabled ui-disabled":""));this.range=d([]);if(b.range){if(b.range===true){if(!b.values)b.values=[this._valueMin(),this._valueMin()];if(b.values.length&&b.values.length!==2)b.values=[b.values[0],b.values[0]]}this.range=d("").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(b.range==="min"||b.range==="max"?" ui-slider-range-"+b.range:""))}for(var j=c.length;j");
+this.handles=c.add(d(e.join("")).appendTo(a.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(g){g.preventDefault()}).hover(function(){b.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(b.disabled)d(this).blur();else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(g){d(this).data("index.ui-slider-handle",
+g)});this.handles.keydown(function(g){var k=true,l=d(this).data("index.ui-slider-handle"),i,h,m;if(!a.options.disabled){switch(g.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:k=false;if(!a._keySliding){a._keySliding=true;d(this).addClass("ui-state-active");i=a._start(g,l);if(i===false)return}break}m=a.options.step;i=a.options.values&&a.options.values.length?
+(h=a.values(l)):(h=a.value());switch(g.keyCode){case d.ui.keyCode.HOME:h=a._valueMin();break;case d.ui.keyCode.END:h=a._valueMax();break;case d.ui.keyCode.PAGE_UP:h=a._trimAlignValue(i+(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:h=a._trimAlignValue(i-(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(i===a._valueMax())return;h=a._trimAlignValue(i+m);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(i===a._valueMin())return;h=a._trimAlignValue(i-
+m);break}a._slide(g,l,h);return k}}).keyup(function(g){var k=d(this).data("index.ui-slider-handle");if(a._keySliding){a._keySliding=false;a._stop(g,k);a._change(g,k);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy();
+return this},_mouseCapture:function(a){var b=this.options,c,f,e,j,g;if(b.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:a.pageX,y:a.pageY});f=this._valueMax()-this._valueMin()+1;j=this;this.handles.each(function(k){var l=Math.abs(c-j.values(k));if(f>l){f=l;e=d(this);g=k}});if(b.range===true&&this.values(1)===b.min){g+=1;e=d(this.handles[g])}if(this._start(a,g)===false)return false;
+this._mouseSliding=true;j._handleIndex=g;e.addClass("ui-state-active").focus();b=e.offset();this._clickOffset=!d(a.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:a.pageX-b.left-e.width()/2,top:a.pageY-b.top-e.height()/2-(parseInt(e.css("borderTopWidth"),10)||0)-(parseInt(e.css("borderBottomWidth"),10)||0)+(parseInt(e.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(a,g,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(a){var b=
+this._normValueFromMouse({x:a.pageX,y:a.pageY});this._slide(a,this._handleIndex,b);return false},_mouseStop:function(a){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(a,this._handleIndex);this._change(a,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b;if(this.orientation==="horizontal"){b=
+this.elementSize.width;a=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{b=this.elementSize.height;a=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}b=a/b;if(b>1)b=1;if(b<0)b=0;if(this.orientation==="vertical")b=1-b;a=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+b*a)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);
+c.values=this.values()}return this._trigger("start",a,c)},_slide:function(a,b,c){var f;if(this.options.values&&this.options.values.length){f=this.values(b?0:1);if(this.options.values.length===2&&this.options.range===true&&(b===0&&c>f||b===1&&c1){this.options.values[a]=this._trimAlignValue(b);this._refreshValue();this._change(null,a)}else if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;f=arguments[0];for(e=0;e=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b;a=a-c;if(Math.abs(c)*2>=b)a+=c>0?b:-b;return parseFloat(a.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var a=
+this.options.range,b=this.options,c=this,f=!this._animateOff?b.animate:false,e,j={},g,k,l,i;if(this.options.values&&this.options.values.length)this.handles.each(function(h){e=(c.values(h)-c._valueMin())/(c._valueMax()-c._valueMin())*100;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";d(this).stop(1,1)[f?"animate":"css"](j,b.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(h===0)c.range.stop(1,1)[f?"animate":"css"]({left:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({width:e-
+g+"%"},{queue:false,duration:b.animate})}else{if(h===0)c.range.stop(1,1)[f?"animate":"css"]({bottom:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({height:e-g+"%"},{queue:false,duration:b.animate})}g=e});else{k=this.value();l=this._valueMin();i=this._valueMax();e=i!==l?(k-l)/(i-l)*100:0;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";this.handle.stop(1,1)[f?"animate":"css"](j,b.animate);if(a==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[f?"animate":"css"]({width:e+"%"},
+b.animate);if(a==="max"&&this.orientation==="horizontal")this.range[f?"animate":"css"]({width:100-e+"%"},{queue:false,duration:b.animate});if(a==="min"&&this.orientation==="vertical")this.range.stop(1,1)[f?"animate":"css"]({height:e+"%"},b.animate);if(a==="max"&&this.orientation==="vertical")this.range[f?"animate":"css"]({height:100-e+"%"},{queue:false,duration:b.animate})}}});d.extend(d.ui.slider,{version:"1.8.16"})})(jQuery);
diff --git a/core/misc/ui/jquery.ui.sortable.min.js b/core/misc/ui/jquery.ui.sortable.min.js
index 2cb1eaa..d0ad528 100644
--- a/core/misc/ui/jquery.ui.sortable.min.js
+++ b/core/misc/ui/jquery.ui.sortable.min.js
@@ -1,8 +1,7 @@
-
/*
- * jQuery UI Sortable 1.8.7
+ * jQuery UI Sortable 1.8.16
*
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
@@ -13,49 +12,49 @@
* jquery.ui.mouse.js
* jquery.ui.widget.js
*/
-(function(d){d.widget("ui.sortable",d.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){this.containerCache={};this.element.addClass("ui-sortable");
-this.refresh();this.floating=this.items.length?/left|right/.test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a==="disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,
-arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&&!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=
-c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,
-{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();
-if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",
-a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a);return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");
-if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0],e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,
-c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset();c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==
-document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp();this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",
-null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):
-d(this.domPosition.parent).prepend(this.currentItem);return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")},toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||
-"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+jg&&b+la[this.floating?"width":"height"]?j:g0?"down":"up")},
-_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith();if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=
-this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=
-this.currentItem.find(":data(sortable-item)"),b=0;b=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");
-if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h=
-0;b--){var c=this.items[b],e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b=this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=
-this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f=d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},
-update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=
-null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out",a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));
-this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h-f)this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.topthis.containment[3])?
-g:!(g-this.offset.click.topthis.containment[2])?f:!(f-this.offset.click.left=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",
-g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this,this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=
-0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop",a,this._uiHash());for(e=0;e *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){var a=this.options;this.containerCache={};this.element.addClass("ui-sortable");
+this.refresh();this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a===
+"disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&&
+!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,
+left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};
+this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!=
+document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a);
+return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0],
+e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset();
+c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):
+this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null,
+dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):d(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")},
+toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+jg&&b+la[this.floating?"width":"height"]?j:g0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith();
+if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),
+this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),b=0;b=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h=0;b--){var c=this.items[b];if(!(c.instance!=this.currentContainer&&this.currentContainer&&c.item[0]!=this.currentItem[0])){var e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b=
+this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f=
+d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||
+0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out",
+a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h-
+f)this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-
+this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.topthis.containment[3])?g:!(g-this.offset.click.topthis.containment[2])?f:!(f-this.offset.click.left=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this,
+this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop",
+a,this._uiHash());for(e=0;e=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");
-if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"));
+if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"));
this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+
g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal",
function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")};
@@ -32,5 +31,5 @@
this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this},
load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c,
"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this},
-url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.7"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++kcondition('cid', $edit['cid'])
->execute();
// Make sure there is no active block for this category.
- db_delete('block')
- ->condition('module', 'aggregator')
- ->condition('delta', 'category-' . $edit['cid'])
- ->execute();
+ if (module_exists('block')) {
+ db_delete('block')
+ ->condition('module', 'aggregator')
+ ->condition('delta', 'category-' . $edit['cid'])
+ ->execute();
+ }
$edit['title'] = '';
$op = 'delete';
}
@@ -521,10 +523,12 @@
->condition('fid', $edit['fid'])
->execute();
// Make sure there is no active block for this feed.
- db_delete('block')
- ->condition('module', 'aggregator')
- ->condition('delta', 'feed-' . $edit['fid'])
- ->execute();
+ if (module_exists('block')) {
+ db_delete('block')
+ ->condition('module', 'aggregator')
+ ->condition('delta', 'feed-' . $edit['fid'])
+ ->execute();
+ }
}
elseif (!empty($edit['title'])) {
$edit['fid'] = db_insert('aggregator_feed')
diff --git a/core/modules/block/block.js b/core/modules/block/block.js
index 6455599..ce4995d 100644
--- a/core/modules/block/block.js
+++ b/core/modules/block/block.js
@@ -117,11 +117,11 @@
var select = $(this);
tableDrag.rowObject = new tableDrag.row(row);
- // Find the correct region and insert the row as the last in the region.
+ // Find the correct region and insert the row as the first in the region.
$('tr.region-message', table).each(function () {
if ($(this).is('.region-' + select[0].value + '-message')) {
// Add the new row and remove the old one.
- $(this).nextUntil('.region-title').last().after(row);
+ $(this).after(row);
// Manually update weights and restripe.
tableDrag.updateFields(row.get(0));
tableDrag.rowObject.changed = true;
diff --git a/core/modules/book/book.info b/core/modules/book/book.info
index 15984ad..f370800 100644
--- a/core/modules/book/book.info
+++ b/core/modules/book/book.info
@@ -3,6 +3,7 @@
package = Core
version = VERSION
core = 8.x
+dependencies[] = node
files[] = book.test
configure = admin/content/book/settings
stylesheets[all][] = book.theme.css
diff --git a/core/modules/book/book.test b/core/modules/book/book.test
index 6b45742..83328e0 100644
--- a/core/modules/book/book.test
+++ b/core/modules/book/book.test
@@ -156,7 +156,7 @@
}
// Fetch links in the current breadcrumb.
- $links = $this->xpath('//div[@class="breadcrumb"]/a');
+ $links = $this->xpath('//nav[@class="breadcrumb"]/ol/li/a');
$got_breadcrumb = array();
foreach ($links as $link) {
$got_breadcrumb[] = (string) $link['href'];
diff --git a/core/modules/comment/comment-node-form.js b/core/modules/comment/comment-node-form.js
index 76db240..e46f05e 100644
--- a/core/modules/comment/comment-node-form.js
+++ b/core/modules/comment/comment-node-form.js
@@ -1,3 +1,7 @@
+/**
+ * @file
+ * Attaches comment behaviors to the node form.
+ */
(function ($) {
diff --git a/core/modules/comment/comment-wrapper.tpl.php b/core/modules/comment/comment-wrapper.tpl.php
index d855631..5e58a67 100644
--- a/core/modules/comment/comment-wrapper.tpl.php
+++ b/core/modules/comment/comment-wrapper.tpl.php
@@ -2,7 +2,7 @@
/**
* @file
- * Default theme implementation to provide an HTML container for comments.
+ * Provides an HTML container for comments.
*
* Available variables:
* - $content: The array of content-related elements for the node. Use
diff --git a/core/modules/comment/comment.admin.inc b/core/modules/comment/comment.admin.inc
index 4f3d350..550de56 100644
--- a/core/modules/comment/comment.admin.inc
+++ b/core/modules/comment/comment.admin.inc
@@ -2,11 +2,20 @@
/**
* @file
- * Admin page callbacks for the comment module.
+ * Admin page callbacks for the Comment module.
*/
/**
- * Menu callback; present an administrative comment listing.
+ * Page callback: Presents an administrative comment listing.
+ *
+ * Path: admin/content/comment
+ *
+ * @param $type
+ * The type of the overview form ('approval' or 'new'). See
+ * comment_admin_overview() for details.
+ *
+ * @see comment_menu()
+ * @see comment_multiple_delete_confirm()
*/
function comment_admin($type = 'new') {
$edit = $_POST;
@@ -20,13 +29,13 @@
}
/**
- * Form builder for the comment overview administration form.
+ * Form constructor for the comment overview administration form.
*
* @param $arg
- * Current path's fourth component: the type of overview form ('approval' or
- * 'new').
+ * The type of overview form ('approval' or 'new').
*
* @ingroup forms
+ * @see comment_admin()
* @see comment_admin_overview_validate()
* @see comment_admin_overview_submit()
* @see theme_comment_admin_overview()
@@ -140,7 +149,9 @@
}
/**
- * Validate comment_admin_overview form submissions.
+ * Form validation handler for comment_admin_overview().
+ *
+ * @see comment_admin_overview_submit()
*/
function comment_admin_overview_validate($form, &$form_state) {
$form_state['values']['comments'] = array_diff($form_state['values']['comments'], array(0));
@@ -151,10 +162,12 @@
}
/**
- * Process comment_admin_overview form submissions.
+ * Form submission handler for comment_admin_overview().
*
- * Execute the chosen 'Update option' on the selected comments, such as
+ * Executes the chosen 'Update option' on the selected comments, such as
* publishing, unpublishing or deleting.
+ *
+ * @see comment_admin_overview_validate()
*/
function comment_admin_overview_submit($form, &$form_state) {
$operation = $form_state['values']['operation'];
@@ -182,13 +195,10 @@
}
/**
- * List the selected comments and verify that the admin wants to delete them.
+ * Form constructor for the confirmation form for bulk comment deletion.
*
- * @param $form_state
- * An associative array containing the current state of the form.
- * @return
- * TRUE if the comments should be deleted, FALSE otherwise.
* @ingroup forms
+ * @see comment_admin()
* @see comment_multiple_delete_confirm_submit()
*/
function comment_multiple_delete_confirm($form, &$form_state) {
@@ -224,7 +234,7 @@
}
/**
- * Process comment_multiple_delete_confirm form submissions.
+ * Form submission handler for comment_multiple_delete_confirm().
*/
function comment_multiple_delete_confirm_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
@@ -238,7 +248,15 @@
}
/**
- * Page callback for comment deletions.
+ * Page callback: Shows a confirmation page for comment deletions.
+ *
+ * Path: comment/%/delete
+ *
+ * @param $cid
+ * The ID of the comment that is about to be deleted.
+ *
+ * @see comment_menu()
+ * @see comment_confirm_delete()
*/
function comment_confirm_delete_page($cid) {
if ($comment = comment_load($cid)) {
@@ -248,10 +266,15 @@
}
/**
- * Form builder; Builds the confirmation form for deleting a single comment.
+ * Form constructor for the confirmation form for comment deletion.
+ *
+ * @param $comment
+ * The comment that is about to be deleted.
*
* @ingroup forms
+ * @see comment_confirm_delete_page()
* @see comment_confirm_delete_submit()
+ * @see confirm_form()
*/
function comment_confirm_delete($form, &$form_state, $comment) {
$form['#comment'] = $comment;
@@ -268,7 +291,7 @@
}
/**
- * Process comment_confirm_delete form submissions.
+ * Form submission handler for comment_confirm_delete().
*/
function comment_confirm_delete_submit($form, &$form_state) {
$comment = $form['#comment'];
diff --git a/core/modules/comment/comment.api.php b/core/modules/comment/comment.api.php
index b381b6c..f270aad 100644
--- a/core/modules/comment/comment.api.php
+++ b/core/modules/comment/comment.api.php
@@ -11,9 +11,10 @@
*/
/**
- * The comment passed validation and is about to be saved.
+ * Act on a comment being inserted or updated.
*
- * Modules may make changes to the comment before it is saved to the database.
+ * This hook is invoked from comment_save() before the comment is saved to the
+ * database.
*
* @param $comment
* The comment object.
@@ -24,7 +25,7 @@
}
/**
- * The comment is being inserted.
+ * Respond to creation of a new comment.
*
* @param $comment
* The comment object.
@@ -35,7 +36,7 @@
}
/**
- * The comment is being updated.
+ * Respond to updates to a comment.
*
* @param $comment
* The comment object.
@@ -46,7 +47,7 @@
}
/**
- * Comments are being loaded from the database.
+ * Act on comments being loaded from the database.
*
* @param $comments
* An array of comment objects indexed by cid.
@@ -59,7 +60,7 @@
}
/**
- * The comment is being viewed. This hook can be used to add additional data to the comment before theming.
+ * Act on a comment that is being assembled before rendering.
*
* @param $comment
* Passes in the comment the action is being performed on.
@@ -76,16 +77,16 @@
}
/**
- * The comment was built; the module may modify the structured content.
+ * Alter the results of comment_view().
*
- * This hook is called after the content has been assembled in a structured array
- * and may be used for doing processing which requires that the complete comment
- * content structure has been built.
+ * This hook is called after the content has been assembled in a structured
+ * array and may be used for doing processing which requires that the complete
+ * comment content structure has been built.
*
- * If the module wishes to act on the rendered HTML of the comment rather than the
- * structured content array, it may use this hook to add a #post_render callback.
- * Alternatively, it could also implement hook_preprocess_comment(). See
- * drupal_render() and theme() documentation respectively for details.
+ * If the module wishes to act on the rendered HTML of the comment rather than
+ * the structured content array, it may use this hook to add a #post_render
+ * callback. Alternatively, it could also implement hook_preprocess_comment().
+ * See drupal_render() and theme() documentation respectively for details.
*
* @param $build
* A renderable array representing the comment.
@@ -105,24 +106,20 @@
}
/**
- * The comment is being published by the moderator.
+ * Respond to a comment being published by a moderator.
*
* @param $comment
- * Passes in the comment the action is being performed on.
- * @return
- * Nothing.
+ * The comment the action is being performed on.
*/
function hook_comment_publish($comment) {
drupal_set_message(t('Comment: @subject has been published', array('@subject' => $comment->subject)));
}
/**
- * The comment is being unpublished by the moderator.
+ * Respond to a comment being unpublished by a moderator.
*
* @param $comment
- * Passes in the comment the action is being performed on.
- * @return
- * Nothing.
+ * The comment the action is being performed on.
*/
function hook_comment_unpublish($comment) {
drupal_set_message(t('Comment: @subject has been unpublished', array('@subject' => $comment->subject)));
diff --git a/core/modules/comment/comment.info b/core/modules/comment/comment.info
index 606f46d..db6dc2c 100644
--- a/core/modules/comment/comment.info
+++ b/core/modules/comment/comment.info
@@ -3,6 +3,7 @@
package = Core
version = VERSION
core = 8.x
+dependencies[] = node
dependencies[] = text
dependencies[] = entity
files[] = comment.entity.inc
diff --git a/core/modules/comment/comment.install b/core/modules/comment/comment.install
index 0213808..c1be493 100644
--- a/core/modules/comment/comment.install
+++ b/core/modules/comment/comment.install
@@ -2,7 +2,7 @@
/**
* @file
- * Install, update and uninstall functions for the comment module.
+ * Install, update and uninstall functions for the Comment module.
*/
/**
@@ -51,10 +51,10 @@
/**
* Implements hook_modules_enabled().
*
- * Creates comment body fields for node types existing before the comment module
+ * Creates comment body fields for node types existing before the Comment module
* is enabled. We use hook_modules_enabled() rather than hook_enable() so we can
* react to node types of existing modules, and those of modules being enabled
- * both before and after comment module in the loop of module_enable().
+ * both before and after the Comment module in the loop of module_enable().
*
* There is a separate comment bundle for each node type to allow for
* per-node-type customization of comment fields. Each one of these bundles
@@ -65,7 +65,7 @@
* @see comment_node_type_insert()
*/
function comment_modules_enabled($modules) {
- // Only react if comment module is one of the modules being enabled.
+ // Only react if the Comment module is one of the modules being enabled.
// hook_node_type_insert() is used to create body fields while the comment
// module is enabled.
if (in_array('comment', $modules)) {
@@ -168,7 +168,7 @@
'description' => "The comment author's home page address from the comment form, if user is anonymous, and the 'Anonymous users may/must leave their contact information' setting is turned on.",
),
'language' => array(
- 'description' => 'The {languages}.language of this comment.',
+ 'description' => 'The {language}.language of this comment.',
'type' => 'varchar',
'length' => 12,
'not null' => TRUE,
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index e5e636b..d69ea94 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -4,9 +4,9 @@
* @file
* Enables users to comment on published content.
*
- * When enabled, the Drupal comment module creates a discussion
- * board for each Drupal node. Users can post comments to discuss
- * a forum topic, story, collaborative book page, etc.
+ * When enabled, the Comment module creates a discussion board for each Drupal
+ * node. Users can post comments to discuss a forum topic, story, collaborative
+ * book page, etc.
*/
/**
@@ -141,9 +141,19 @@
}
/**
- * Menu loader callback for Field UI paths.
+ * Loads the comment bundle name corresponding a given content type.
*
- * Return a comment bundle name from a node type in the URL.
+ * This function is used as a menu loader callback in comment_menu().
+ *
+ * @param $name
+ * The URL-formatted machine name of the node type whose comment fields are
+ * to be edited. 'URL-formatted' means that underscores are replaced by
+ * hyphens.
+ *
+ * @return
+ * The comment bundle name corresponding to the node type.
+ *
+ * @see comment_menu_alter()
*/
function comment_node_type_load($name) {
if ($type = node_type_get_type(strtr($name, array('-' => '_')))) {
@@ -318,8 +328,8 @@
/**
* Implements hook_node_type_insert().
*
- * Creates a comment body field for a node type created while the comment module
- * is enabled. For node types created before the comment module is enabled,
+ * Creates a comment body field for a node type created while the Comment module
+ * is enabled. For node types created before the Comment module is enabled,
* hook_modules_enabled() serves to create the body fields.
*
* @see comment_modules_enabled()
@@ -358,6 +368,11 @@
/**
* Creates a comment_body field instance for a given node type.
+ *
+ * @param $info
+ * An object representing the content type. The only property that is
+ * currently used is $info->type, which is the machine name of the content
+ * type for which the body field (instance) is to be created.
*/
function _comment_body_field_create($info) {
// Create the field if needed.
@@ -473,6 +488,7 @@
*
* @param $cid
* A comment identifier.
+ *
* @return
* The comment listing set to the page on which the comment appears.
*/
@@ -494,7 +510,7 @@
}
/**
- * Find the most recent comments that are available to the current user.
+ * Finds the most recent comments that are available to the current user.
*
* @param integer $number
* (optional) The maximum number of comments to find. Defaults to 10.
@@ -523,7 +539,7 @@
}
/**
- * Calculate page number for first new comment.
+ * Calculates the page number for the first new comment.
*
* @param $num_comments
* Number of comments.
@@ -531,6 +547,7 @@
* Number of new replies.
* @param $node
* The first new comment node.
+ *
* @return
* "page=X" if the page number is greater than zero; empty string otherwise.
*/
@@ -590,7 +607,7 @@
}
/**
- * Returns HTML for a list of recent comments to be displayed in the comment block.
+ * Returns HTML for a list of recent comments.
*
* @ingroup themeable
*/
@@ -714,10 +731,14 @@
}
/**
- * Build the comment-related elements for node detail pages.
+ * Builds the comment-related elements for node detail pages.
*
* @param $node
- * A node object.
+ * The node object for which to build the comment-related elements.
+ *
+ * @return
+ * A renderable array representing the comment-related page elements for the
+ * node.
*/
function comment_node_page_additions($node) {
$additions = array();
@@ -756,7 +777,7 @@
}
/**
- * Retrieve comments for a thread.
+ * Retrieves comments for a thread.
*
* @param $node
* The node whose comment(s) needs rendering.
@@ -764,6 +785,9 @@
* The comment display mode; COMMENT_MODE_FLAT or COMMENT_MODE_THREADED.
* @param $comments_per_page
* The amount of comments to display per page.
+ *
+ * @return
+ * An array of the IDs of the comment to be displayed.
*
* To display threaded comments in the correct order we keep a 'thread' field
* and order by that value. This field keeps this data in
@@ -859,12 +883,14 @@
}
/**
- * Loop over comment thread, noting indentation level.
+ * Calculates the indentation level of each comment in a comment thread.
+ *
+ * This function loops over an array representing a comment thread. For each
+ * comment, the function calculates the indentation level and saves it in the
+ * 'divs' property of the comment object.
*
* @param array $comments
- * An array of comment objects, keyed by cid.
- * @return
- * The $comments argument is altered by reference with indentation information.
+ * An array of comment objects, keyed by comment ID.
*/
function comment_prepare_thread(&$comments) {
// A flag stating if we are still searching for first new comment on the thread.
@@ -902,10 +928,10 @@
}
/**
- * Generate an array for rendering the given comment.
+ * Generates an array for rendering a comment.
*
* @param $comment
- * A comment object.
+ * The comment object.
* @param $node
* The node the comment is attached to.
* @param $view_mode
@@ -971,8 +997,8 @@
/**
* Builds a structured array representing the comment's content.
*
- * The content built for the comment (field values, comments, file attachments or
- * other comment components) will vary depending on the $view_mode parameter.
+ * The content built for the comment (field values, comments, file attachments
+ * or other comment components) will vary depending on the $view_mode parameter.
*
* @param $comment
* A comment object.
@@ -1016,14 +1042,13 @@
}
/**
- * Helper function, build links for an individual comment.
- *
- * Adds reply, edit, delete etc. depending on the current user permissions.
+ * Adds reply, edit, delete, etc. links, depending on user permissions.
*
* @param $comment
* The comment object.
* @param $node
* The node the comment is attached to.
+ *
* @return
* A structured array of links.
*/
@@ -1078,7 +1103,7 @@
}
/**
- * Construct a drupal_render() style array from an array of loaded comments.
+ * Constructs render array from an array of loaded comments.
*
* @param $comments
* An array of comments as returned by comment_load_multiple().
@@ -1094,6 +1119,8 @@
*
* @return
* An array in the format expected by drupal_render().
+ *
+ * @see drupal_render()
*/
function comment_view_multiple($comments, $node, $view_mode = 'full', $weight = 0, $langcode = NULL) {
field_attach_prepare_view('comment', $comments, $view_mode, $langcode);
@@ -1421,6 +1448,7 @@
* recognized now.
* @param $comment
* The comment object.
+ *
* @return
* TRUE if the current user has acces to the comment, FALSE otherwise.
*/
@@ -1443,20 +1471,20 @@
}
/**
- * Delete a comment and all its replies.
+ * Deletes a comment and all its replies.
*
* @param $cid
- * The comment to delete.
+ * The ID of the comment to delete.
*/
function comment_delete($cid) {
comment_delete_multiple(array($cid));
}
/**
- * Delete comments and all their replies.
+ * Deletes comments and all their replies.
*
* @param $cids
- * The comment to delete.
+ * The IDs of the comments to delete.
*
* @see hook_comment_predelete()
* @see hook_comment_delete()
@@ -1466,7 +1494,7 @@
}
/**
- * Load comments from the database.
+ * Loads comments from the database.
*
* @param $cids
* An array of comment IDs.
@@ -1483,20 +1511,20 @@
* @return
* An array of comment objects, indexed by comment ID.
*
+ * @todo Remove $conditions in Drupal 8.
+ *
* @see entity_load()
* @see EntityFieldQuery
- *
- * @todo Remove $conditions in Drupal 8.
*/
function comment_load_multiple($cids = array(), $conditions = array(), $reset = FALSE) {
return entity_load('comment', $cids, $conditions, $reset);
}
/**
- * Load the entire comment by cid.
+ * Loads the entire comment by comment ID.
*
* @param $cid
- * The identifying comment id.
+ * The ID of the comment to be loaded.
* @param $reset
* Whether to reset the internal static entity cache. Note that the static
* cache is disabled in comment_entity_info() by default.
@@ -1510,14 +1538,16 @@
}
/**
- * Get number of new comments for current user and specified node.
+ * Gets the number of new comments for the current user and the specified node.
*
* @param $nid
- * Node-id to count comments for.
+ * Node ID to count comments for.
* @param $timestamp
* Time to count from (defaults to time of last user access
* to node).
- * @return The result or FALSE on error.
+ *
+ * @return
+ * The number of new comments or FALSE if the user is not logged in.
*/
function comment_num_new($nid, $timestamp = 0) {
global $user;
@@ -1543,7 +1573,7 @@
}
/**
- * Get the display ordinal for a comment, starting from 0.
+ * Gets the display ordinal for a comment, starting from 0.
*
* Count the number of comments which appear before the comment we want to
* display, taking into account display settings and threading.
@@ -1552,8 +1582,10 @@
* The comment ID.
* @param $node_type
* The node type of the comment's parent.
+ *
* @return
* The display ordinal for the comment.
+ *
* @see comment_get_display_page()
*/
function comment_get_display_ordinal($cid, $node_type) {
@@ -1585,7 +1617,7 @@
}
/**
- * Return the page number for a comment.
+ * Returns the page number for a comment.
*
* Finds the correct page number for a comment taking into account display
* and paging settings.
@@ -1594,6 +1626,7 @@
* The comment ID.
* @param $node_type
* The node type the comment is attached to.
+ *
* @return
* The page number.
*/
@@ -1604,7 +1637,14 @@
}
/**
- * Page callback for comment editing.
+ * Page callback: Displays the comment editing form.
+ *
+ * Path: comment/%comment/edit
+ *
+ * @param $comment
+ * The comment object representing the comment to be edited.
+ *
+ * @see comment_menu()
*/
function comment_edit_page($comment) {
drupal_set_title(t('Edit comment %comment', array('%comment' => $comment->subject)), PASS_THROUGH);
@@ -1624,11 +1664,11 @@
}
/**
- * Generate the basic commenting form, for appending to a node or display on a separate page.
+ * Form constructor for the basic commenting form.
*
* @see comment_form_validate()
* @see comment_form_submit()
- *
+ * @see comment_form_build_preview()
* @ingroup forms
*/
function comment_form($form, &$form_state, $comment) {
@@ -1823,7 +1863,7 @@
}
/**
- * Build a preview from submitted form values.
+ * Form submission handler for the 'preview' button in comment_form().
*/
function comment_form_build_preview($form, &$form_state) {
$comment = comment_form_submit_build_comment($form, $form_state);
@@ -1832,7 +1872,9 @@
}
/**
- * Generate a comment preview.
+ * Generates a comment preview.
+ *
+ * @see comment_form_build_preview()
*/
function comment_preview($comment) {
global $user;
@@ -1886,7 +1928,9 @@
}
/**
- * Validate comment form submissions.
+ * Form validation handler for comment_form().
+ *
+ * @see comment_form_submit()
*/
function comment_form_validate($form, &$form_state) {
global $user;
@@ -1975,7 +2019,7 @@
}
/**
- * Updates the form state's comment entity by processing this submission's values.
+ * Updates the comment entity by processing the submission's values.
*
* This is the default builder function for the comment form. It is called
* during the "Save" and "Preview" submit handlers to retrieve the entity to
@@ -1984,6 +2028,8 @@
* before proceeding to the next step.
*
* @see comment_form()
+ * @see comment_form_preview()
+ * @see comment_form_submit()
*/
function comment_form_submit_build_comment($form, &$form_state) {
$comment = $form_state['comment'];
@@ -1993,7 +2039,10 @@
}
/**
- * Process comment form submissions; prepare the comment, store it, and set a redirection target.
+ * Form submission handler for comment_form().
+ *
+ * @see comment_form_validate()
+ * @see comment_form_submit_build_comment()
*/
function comment_form_submit($form, &$form_state) {
$node = node_load($form_state['values']['nid']);
@@ -2041,7 +2090,7 @@
}
/**
- * Process variables for comment.tpl.php.
+ * Preprocesses variables for comment.tpl.php.
*
* @see comment.tpl.php
*/
@@ -2149,7 +2198,7 @@
}
/**
- * Process variables for comment-wrapper.tpl.php.
+ * Preprocesses variables for comment-wrapper.tpl.php.
*
* @see comment-wrapper.tpl.php
* @see theme_comment_wrapper()
@@ -2163,10 +2212,10 @@
}
/**
- * Return an array of viewing modes for comment listings.
+ * Returns an array of viewing modes for comment listings.
*
* We can't use a global variable array because the locale system
- * is not initialized yet when the comment module is loaded.
+ * is not initialized yet when the Comment module is loaded.
*/
function _comment_get_modes() {
return array(
@@ -2176,15 +2225,14 @@
}
/**
- * Return an array of "comments per page" settings from which the user
- * can choose.
+ * Returns an array of "comments per page" values that users can select from.
*/
function _comment_per_page() {
return drupal_map_assoc(array(10, 30, 50, 70, 90, 150, 200, 250, 300));
}
/**
- * Generate sorting code.
+ * Generates a sorting code.
*
* Consists of a leading character indicating length, followed by N digits
* with a numerical value in base 36 (alphadecimal). These codes can be sorted
@@ -2204,7 +2252,7 @@
}
/**
- * Decode sorting code back to an integer.
+ * Decodes a sorting code back to an integer.
*
* @see comment_int_to_alphadecimal()
*/
@@ -2213,7 +2261,7 @@
}
/**
- * Increment a sorting code to the next value.
+ * Increments a sorting code to the next value.
*
* @see comment_int_to_alphadecimal()
*/
@@ -2336,7 +2384,7 @@
}
/**
- * Form builder; Prepare a form for blacklisted keywords.
+ * Form constructor for the blacklisted keywords form.
*
* @ingroup forms
* @see comment_unpublish_by_keyword_action()
@@ -2354,7 +2402,7 @@
}
/**
- * Process comment_unpublish_by_keyword_action_form form submissions.
+ * Form submission handler for comment_unpublish_by_keyword_action_form().
*
* @see comment_unpublish_by_keyword_action()
*/
diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc
index de8129d..5e3d9de 100644
--- a/core/modules/comment/comment.pages.inc
+++ b/core/modules/comment/comment.pages.inc
@@ -2,11 +2,12 @@
/**
* @file
- * User page callbacks for the comment module.
+ * User page callbacks for the Comment module.
*/
/**
- * This function is responsible for generating a comment reply form.
+ * Form constructor for the comment reply form.
+ *
* There are several cases that have to be handled, including:
* - replies to comments
* - replies to nodes
@@ -18,10 +19,9 @@
*
* @param $node
* Every comment belongs to a node. This is that node.
- *
* @param $pid
- * Some comments are replies to other comments. In those cases, $pid is the parent
- * comment's cid.
+ * (optional) Some comments are replies to other comments. In those cases,
+ * $pid is the parent comment's comment ID. Defaults to NULL.
*
* @return
* The rendered parent node or comment plus the new comment form.
@@ -100,10 +100,14 @@
}
/**
- * Menu callback; publish specified comment.
+ * Page callback: Publishes the specified comment.
+ *
+ * Path: comment/%/approve
*
* @param $cid
* A comment identifier.
+ *
+ * @see comment_menu()
*/
function comment_approve($cid) {
if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], "comment/$cid/approve")) {
diff --git a/core/modules/comment/comment.test b/core/modules/comment/comment.test
index 2771bc4..3911a29 100644
--- a/core/modules/comment/comment.test
+++ b/core/modules/comment/comment.test
@@ -2,7 +2,7 @@
/**
* @file
- * Tests for comment.module.
+ * Tests for the Comment module.
*/
class CommentHelperCase extends DrupalWebTestCase {
@@ -19,7 +19,7 @@
}
/**
- * Post comment.
+ * Posts a comment.
*
* @param $node
* Node to post comment on.
@@ -94,9 +94,13 @@
/**
* Checks current page for specified comment.
*
- * @param object $comment Comment object.
- * @param boolean $reply The comment is a reply to another comment.
- * @return boolean Comment found.
+ * @param object $comment
+ * The comment object.
+ * @param boolean $reply
+ * Boolean indicating whether the comment is a reply to another comment.
+ *
+ * @return boolean
+ * Boolean indicating whether the comment was found.
*/
function commentExists($comment, $reply = FALSE) {
if ($comment && is_object($comment)) {
@@ -115,7 +119,7 @@
}
/**
- * Delete comment.
+ * Deletes a comment.
*
* @param object $comment
* Comment to delete.
@@ -126,20 +130,20 @@
}
/**
- * Set comment subject setting.
+ * Sets the value governing whether the subject field should be enabled.
*
* @param boolean $enabled
- * Subject value.
+ * Boolean specifying whether the subject field should be enabled.
*/
function setCommentSubject($enabled) {
$this->setCommentSettings('comment_subject_field', ($enabled ? '1' : '0'), 'Comment subject ' . ($enabled ? 'enabled' : 'disabled') . '.');
}
/**
- * Set comment preview setting.
+ * Sets the value governing the previewing mode for the comment form.
*
* @param int $mode
- * Preview value.
+ * The preview mode: DRUPAL_DISABLED, DRUPAL_OPTIONAL or DRUPAL_REQUIRED.
*/
function setCommentPreview($mode) {
switch ($mode) {
@@ -159,27 +163,31 @@
}
/**
- * Set comment form location setting.
+ * Sets the value governing whether the comment form is on its own page.
*
* @param boolean $enabled
- * Form value.
+ * TRUE if the comment form should be displayed on the same page as the
+ * comments; FALSE if it should be displayed on its own page.
*/
function setCommentForm($enabled) {
$this->setCommentSettings('comment_form_location', ($enabled ? COMMENT_FORM_BELOW : COMMENT_FORM_SEPARATE_PAGE), 'Comment controls ' . ($enabled ? 'enabled' : 'disabled') . '.');
}
/**
- * Set comment anonymous level setting.
+ * Sets the value governing restrictions on anonymous comments.
*
* @param integer $level
- * Anonymous level.
+ * The level of the contact information allowed for anonymous comments:
+ * - 0: No contact information allowed.
+ * - 1: Contact information allowed but not required.
+ * - 2: Contact information required.
*/
function setCommentAnonymous($level) {
$this->setCommentSettings('comment_anonymous', $level, 'Anonymous commenting set to level ' . $level . '.');
}
/**
- * Set the default number of comments per page.
+ * Sets the value specifying the default number of comments per page.
*
* @param integer $comments
* Comments per page value.
@@ -189,7 +197,7 @@
}
/**
- * Set comment setting for article content type.
+ * Sets a comment settings variable for the article content type.
*
* @param string $name
* Name of variable.
@@ -204,16 +212,17 @@
}
/**
- * Check for contact info.
+ * Checks whether the commenter's contact information is displayed.
*
- * @return boolean Contact info is available.
+ * @return boolean
+ * Contact info is available.
*/
function commentContactInfoAvailable() {
return preg_match('/(input).*?(name="name").*?(input).*?(name="mail").*?(input).*?(name="homepage")/s', $this->drupalGetContent());
}
/**
- * Perform the specified operation on the specified comment.
+ * Performs the specified operation on the specified comment.
*
* @param object $comment
* Comment to perform operation on.
@@ -238,10 +247,11 @@
}
/**
- * Get the comment ID for an unapproved comment.
+ * Gets the comment ID for an unapproved comment.
*
* @param string $subject
* Comment subject to find.
+ *
* @return integer
* Comment id.
*/
@@ -313,7 +323,7 @@
}
/**
- * Test comment interface.
+ * Tests the comment interface.
*/
function testCommentInterface() {
$langcode = LANGUAGE_NONE;
@@ -735,7 +745,7 @@
}
/**
- * Asserts that comment links appear according to the passed environment setup.
+ * Asserts that comment links appear according to the passed environment.
*
* @param $info
* An associative array describing the environment to pass to
@@ -831,7 +841,7 @@
}
/**
- * Test previewing comments.
+ * Tests previewing comments.
*/
class CommentPreviewTest extends CommentHelperCase {
public static function getInfo() {
@@ -843,7 +853,7 @@
}
/**
- * Test comment preview.
+ * Tests comment preview.
*/
function testCommentPreview() {
$langcode = LANGUAGE_NONE;
@@ -874,7 +884,7 @@
}
/**
- * Test comment edit, preview, and save.
+ * Tests comment edit, preview, and save.
*/
function testCommentEditPreviewSave() {
$langcode = LANGUAGE_NONE;
@@ -938,7 +948,9 @@
}
}
-
+/**
+ * Tests anonymous commenting.
+ */
class CommentAnonymous extends CommentHelperCase {
public static function getInfo() {
return array(
@@ -954,7 +966,7 @@
}
/**
- * Test anonymous comment functionality.
+ * Tests anonymous comment functionality.
*/
function testAnonymous() {
$this->drupalLogin($this->admin_user);
@@ -1092,7 +1104,7 @@
}
/**
- * Verify pagination of comments.
+ * Verifies pagination of comments.
*/
class CommentPagerTest extends CommentHelperCase {
@@ -1105,7 +1117,7 @@
}
/**
- * Confirm comment paging works correctly with flat and threaded comments.
+ * Confirms comment paging works correctly with flat and threaded comments.
*/
function testCommentPaging() {
$this->drupalLogin($this->admin_user);
@@ -1178,7 +1190,7 @@
}
/**
- * Test comment ordering and threading.
+ * Tests comment ordering and threading.
*/
function testCommentOrderingThreading() {
$this->drupalLogin($this->admin_user);
@@ -1253,7 +1265,7 @@
}
/**
- * Helper function: assert that the comments are displayed in the correct order.
+ * Asserts that the comments are displayed in the correct order.
*
* @param $comments
* And array of comments.
@@ -1278,7 +1290,7 @@
}
/**
- * Test comment_new_page_count().
+ * Tests comment_new_page_count().
*/
function testCommentNewPageIndicator() {
$this->drupalLogin($this->admin_user);
@@ -1425,7 +1437,9 @@
$this->assertText($reply_subject);
}
}
-
+/**
+ * Tests comment approval functionality.
+ */
class CommentApprovalTest extends CommentHelperCase {
public static function getInfo() {
return array(
@@ -1505,7 +1519,7 @@
}
/**
- * Test comment approval functionality through node interface.
+ * Tests comment approval functionality through the node interface.
*/
function testApprovalNodeInterface() {
// Set anonymous comments to require approval.
@@ -1548,7 +1562,7 @@
}
/**
- * Functional tests for the comment module blocks.
+ * Tests the Comment module blocks.
*/
class CommentBlockFunctionalTest extends CommentHelperCase {
public static function getInfo() {
@@ -1560,7 +1574,7 @@
}
/**
- * Test the recent comments block.
+ * Tests the recent comments block.
*/
function testRecentCommentBlock() {
$this->drupalLogin($this->admin_user);
@@ -1643,7 +1657,7 @@
}
/**
- * Unit tests for comment module integration with RSS feeds.
+ * Unit tests for Comment module integration with RSS feeds.
*/
class CommentRSSUnitTest extends CommentHelperCase {
public static function getInfo() {
@@ -1655,7 +1669,7 @@
}
/**
- * Test comments as part of an RSS feed.
+ * Tests comments as part of an RSS feed.
*/
function testCommentRSS() {
// Find comment in RSS feed.
@@ -1675,7 +1689,7 @@
/**
- * Test to make sure comment content is rebuilt.
+ * Tests comment content rebuilding.
*/
class CommentContentRebuild extends CommentHelperCase {
public static function getInfo() {
@@ -1687,8 +1701,7 @@
}
/**
- * Test to ensure that the comment's content array is rebuilt for every
- * call to comment_view().
+ * Tests the rebuilding of comment's content arrays on calling comment_view().
*/
function testCommentRebuild() {
// Update the comment settings so preview isn't required.
@@ -1715,7 +1728,7 @@
}
/**
- * Test comment token replacement in strings.
+ * Tests comment token replacement in strings.
*/
class CommentTokenReplaceTestCase extends CommentHelperCase {
public static function getInfo() {
@@ -1815,7 +1828,7 @@
}
/**
- * Test actions provided by the comment module.
+ * Tests actions provided by the Comment module.
*/
class CommentActionsTestCase extends CommentHelperCase {
public static function getInfo() {
@@ -1827,7 +1840,7 @@
}
/**
- * Test comment publish and unpublish actions.
+ * Tests comment publish and unpublish actions.
*/
function testCommentPublishUnpublishActions() {
$this->drupalLogin($this->web_user);
@@ -1861,7 +1874,7 @@
}
/**
- * Verify that a watchdog message has been entered.
+ * Verifies that a watchdog message has been entered.
*
* @param $watchdog_message
* The watchdog message.
@@ -1876,7 +1889,7 @@
}
/**
- * Helper function: clear the watchdog.
+ * Clears watchdog.
*/
function clearWatchdog() {
db_truncate('watchdog')->execute();
@@ -1884,7 +1897,7 @@
}
/**
- * Test fields on comments.
+ * Tests fields on comments.
*/
class CommentFieldsTest extends CommentHelperCase {
public static function getInfo() {
@@ -1929,7 +1942,7 @@
}
/**
- * Test that comment module works when enabled after a content module.
+ * Tests that comment module works when enabled after a content module.
*/
function testCommentEnable() {
// Create a user to do module administration.
@@ -1973,7 +1986,7 @@
}
/**
- * Test that comment module works correctly with plain text format.
+ * Tests that comment module works correctly with plain text format.
*/
function testCommentFormat() {
// Disable text processing for comments.
diff --git a/core/modules/comment/comment.tpl.php b/core/modules/comment/comment.tpl.php
index 8ba46d8..678f798 100644
--- a/core/modules/comment/comment.tpl.php
+++ b/core/modules/comment/comment.tpl.php
@@ -6,8 +6,8 @@
*
* Available variables:
* - $author: Comment author. Can be link or plain text.
- * - $content: An array of comment items. Use render($content) to print them all, or
- * print a subset such as render($content['field_example']). Use
+ * - $content: An array of comment items. Use render($content) to print them
+ * all, or print a subset such as render($content['field_example']). Use
* hide($content['field_example']) to temporarily suppress the printing of a
* given element.
* - $created: Formatted date and time for when the comment was created.
@@ -27,13 +27,15 @@
* - $title: Linked title.
* - $classes: String of classes that can be used to style contextually through
* CSS. It can be manipulated through the variable $classes_array from
- * preprocess functions. The default values can be one or more of the following:
+ * preprocess functions. The default values can be one or more of the
+ * following:
* - comment: The current template type, i.e., "theming hook".
* - comment-by-anonymous: Comment by an unregistered user.
* - comment-by-node-author: Comment by the author of the parent node.
* - comment-preview: When previewing a new or edited comment.
* The following applies only to viewers who are registered users:
- * - comment-unpublished: An unpublished comment visible only to administrators.
+ * - comment-unpublished: An unpublished comment visible only to
+ * administrators.
* - comment-by-viewer: Comment by the user currently viewing the page.
* - comment-new: New comment since last the visit.
* - $title_prefix (array): An array containing additional output populated by
diff --git a/core/modules/contextual/contextual.css b/core/modules/contextual/contextual.css
index 3829328..cdb85ec 100644
--- a/core/modules/contextual/contextual.css
+++ b/core/modules/contextual/contextual.css
@@ -39,7 +39,6 @@
text-indent: 34px; /* LTR */
width: 28px;
overflow: hidden;
- -khtml-border-radius: 4px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
diff --git a/core/modules/entity/tests/entity_query.test b/core/modules/entity/tests/entity_query.test
index 49cf7b8..29642bc 100644
--- a/core/modules/entity/tests/entity_query.test
+++ b/core/modules/entity/tests/entity_query.test
@@ -21,10 +21,10 @@
function setUp() {
parent::setUp(array('field_test'));
- field_attach_create_bundle('test_entity_bundle_key', 'bundle1');
- field_attach_create_bundle('test_entity_bundle_key', 'bundle2');
- field_attach_create_bundle('test_entity', 'test_bundles');
- field_attach_create_bundle('test_entity_bundle', 'test_entity_bundle');
+ field_test_create_bundle('bundle1');
+ field_test_create_bundle('bundle2');
+ field_test_create_bundle('test_bundle');
+ field_test_create_bundle('test_entity_bundle');
$instances = array();
$this->fields = array();
@@ -1058,7 +1058,6 @@
$this->fields[0]['cardinality'] = 1;
field_update_field($this->fields[0]);
field_test_entity_info_translatable('test_entity', TRUE);
- drupal_static_reset('field_available_languages');
// Create more items with different languages.
$entity = new stdClass();
@@ -1096,7 +1095,6 @@
$this->fields[0]['translatable'] = TRUE;
field_update_field($this->fields[0]);
field_test_entity_info_translatable('test_entity', TRUE);
- drupal_static_reset('field_available_languages');
// Create more items with different languages.
$entity = new stdClass();
diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php
index 4b71248..329cf16 100644
--- a/core/modules/field/field.api.php
+++ b/core/modules/field/field.api.php
@@ -116,7 +116,8 @@
* A third kind of pluggable handlers, storage backends, is defined by the
* @link field_storage Field Storage API @endlink.
*
- * @see field
+ * See @link field Field API @endlink for information about the other parts of
+ * the Field API.
*/
/**
@@ -704,6 +705,7 @@
* @see hook_field_widget_form_alter()
* @see hook_field_widget_WIDGET_TYPE_form_alter()
* @see hook_field_widget_error()
+ * @see hook_field_widget_settings_form()
*/
function hook_field_widget_info() {
return array(
diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc
index 482659e..9291725 100644
--- a/core/modules/field/field.attach.inc
+++ b/core/modules/field/field.attach.inc
@@ -45,7 +45,8 @@
* Each field defines which storage backend it uses. The Drupal system variable
* 'field_storage_default' identifies the storage backend used by default.
*
- * @see field
+ * See @link field Field API @endlink for information about the other parts of
+ * the Field API.
*/
/**
@@ -120,7 +121,11 @@
* Field Storage API is essentially the "fallback mechanism" for any fields
* that aren't being intercepted explicitly by pre-operation hooks.
*
- * @see field
+ * @link field_language Field language API @endlink provides information about
+ * the structure of field objects.
+ *
+ * See @link field Field API @endlink for information about the other parts of
+ * the Field API.
*/
/**
@@ -638,7 +643,7 @@
foreach ($entities as $id => $entity) {
$cids[] = "field:$entity_type:$id";
}
- $cache = cache_get_multiple($cids, 'cache_field');
+ $cache = cache('field')->getMultiple($cids);
// Put the cached field values back into the entities and remove them from
// the list of entities to query.
foreach ($entities as $id => $entity) {
@@ -1311,6 +1316,7 @@
// Clear the cache.
field_cache_clear();
+ entity_info_cache_clear();
// Update bundle settings.
$settings = variable_get('field_bundle_settings_' . $entity_type . '__' . $bundle_old, array());
diff --git a/core/modules/field/field.crud.inc b/core/modules/field/field.crud.inc
index ff39f22..6df3235 100644
--- a/core/modules/field/field.crud.inc
+++ b/core/modules/field/field.crud.inc
@@ -16,7 +16,8 @@
* The Field CRUD API uses
* @link field Field API data structures @endlink.
*
- * @see field
+ * See @link field Field API @endlink for information about the other parts of
+ * the Field API.
*/
/**
@@ -827,7 +828,8 @@
* );
* @endcode
*
- * @see field
+ * See @link field Field API @endlink for information about the other parts of
+ * the Field API.
*/
/**
diff --git a/core/modules/field/field.info.inc b/core/modules/field/field.info.inc
index dda7f2f..5a99034 100644
--- a/core/modules/field/field.info.inc
+++ b/core/modules/field/field.info.inc
@@ -14,7 +14,8 @@
* instances, bundles, widget types, display formatters, behaviors,
* and settings defined by or with the Field API.
*
- * @see field
+ * See @link field Field API @endlink for information about the other parts of
+ * the Field API.
*/
/**
@@ -26,6 +27,7 @@
*/
function field_info_cache_clear() {
drupal_static_reset('field_view_mode_settings');
+ drupal_static_reset('field_available_languages');
// @todo: Remove this when field_attach_*_bundle() bundle management
// functions are moved to the entity API.
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 5c492c0..2d31efa 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -372,17 +372,6 @@
}
/**
- * Implements hook_modules_uninstalled().
- */
-function field_modules_uninstalled($modules) {
- module_load_include('inc', 'field', 'field.crud');
- foreach ($modules as $module) {
- // TODO D7: field_module_delete is not yet implemented
- // field_module_delete($module);
- }
-}
-
-/**
* Implements hook_system_info_alter().
*
* Goes through a list of all modules that provide a field type, and makes them
diff --git a/core/modules/field/field.multilingual.inc b/core/modules/field/field.multilingual.inc
index 9841c7a..747d81c 100644
--- a/core/modules/field/field.multilingual.inc
+++ b/core/modules/field/field.multilingual.inc
@@ -58,27 +58,28 @@
* it possible to choose the first approach. The display language for each
* field is returned by field_language().
*
- * @see field
+ * See @link field Field API @endlink for information about the other parts of
+ * the Field API.
*/
/**
- * Implements hook_locale_language_insert().
+ * Implements hook_language_insert().
*/
-function field_locale_language_insert() {
+function field_language_insert() {
field_info_cache_clear();
}
/**
- * Implements hook_locale_language_update().
+ * Implements hook_language_update().
*/
-function field_locale_language_update() {
+function field_language_update() {
field_info_cache_clear();
}
/**
- * Implements hook_locale_language_delete().
+ * Implements hook_language_delete().
*/
-function field_locale_language_delete() {
+function field_language_delete() {
field_info_cache_clear();
}
diff --git a/core/modules/field/tests/field.test b/core/modules/field/tests/field.test
index 214eab4..d628003 100644
--- a/core/modules/field/tests/field.test
+++ b/core/modules/field/tests/field.test
@@ -72,12 +72,13 @@
}
class FieldAttachTestCase extends FieldTestCase {
- function setUp($modules = array()) {
+ function setUp() {
// Since this is a base class for many test cases, support the same
// flexibility that DrupalWebTestCase::setUp() has for the modules to be
// passed in as either an array or a variable number of string arguments.
- if (!is_array($modules)) {
- $modules = func_get_args();
+ $modules = func_get_args();
+ if (isset($modules[0]) && is_array($modules[0])) {
+ $modules = $modules[0];
}
if (!in_array('field_test', $modules)) {
$modules[] = 'field_test';
@@ -2648,7 +2649,7 @@
'language' => 'l' . $i,
'name' => $this->randomString(),
);
- locale_language_save($language);
+ language_save($language);
}
}
@@ -2678,7 +2679,7 @@
// Test field_available_languages() behavior for untranslatable fields.
$this->field['translatable'] = FALSE;
- $this->field_name = $this->field['field_name'] = $this->instance['field_name'] = drupal_strtolower($this->randomName() . '_field_name');
+ field_update_field($this->field);
$available_languages = field_available_languages($this->entity_type, $this->field);
$this->assertTrue(count($available_languages) == 1 && $available_languages[0] === LANGUAGE_NONE, t('For untranslatable fields only LANGUAGE_NONE is available.'));
}
diff --git a/core/modules/field/tests/field_test.entity.inc b/core/modules/field/tests/field_test.entity.inc
index b7c70a6..52ed3fc 100644
--- a/core/modules/field/tests/field_test.entity.inc
+++ b/core/modules/field/tests/field_test.entity.inc
@@ -58,7 +58,7 @@
'id' => 'ftid',
'bundle' => 'fttype',
),
- 'bundles' => array('bundle1' => array('label' => 'Bundle1'), 'bundle2' => array('label' => 'Bundle2')),
+ 'bundles' => array('bundle1' => array('label' => 'Bundle1'), 'bundle2' => array('label' => 'Bundle2')) + $bundles,
'view modes' => $test_entity_modes,
),
// In this case, the bundle key is not stored in the database.
@@ -72,7 +72,7 @@
'id' => 'ftid',
'bundle' => 'fttype',
),
- 'bundles' => array('test_entity_2' => array('label' => 'Test entity 2')),
+ 'bundles' => array('test_entity_2' => array('label' => 'Test entity 2')) + $bundles,
'view modes' => $test_entity_modes,
),
// @see EntityPropertiesTestCase::testEntityLabel()
diff --git a/core/modules/field/tests/field_test.field.inc b/core/modules/field/tests/field_test.field.inc
index b8a2939..6d03855 100644
--- a/core/modules/field/tests/field_test.field.inc
+++ b/core/modules/field/tests/field_test.field.inc
@@ -350,11 +350,13 @@
break;
case 'field_test_multiple':
- $array = array();
- foreach ($items as $delta => $item) {
- $array[] = $delta . ':' . $item['value'];
+ if (!empty($items)) {
+ $array = array();
+ foreach ($items as $delta => $item) {
+ $array[] = $delta . ':' . $item['value'];
+ }
+ $element[0] = array('#markup' => $settings['test_formatter_setting_multiple'] . '|' . implode('|', $array));
}
- $element[0] = array('#markup' => $settings['test_formatter_setting_multiple'] . '|' . implode('|', $array));
break;
}
diff --git a/core/modules/field_ui/field_ui-rtl.css b/core/modules/field_ui/field_ui-rtl.css
index 11b9933..1066baa 100644
--- a/core/modules/field_ui/field_ui-rtl.css
+++ b/core/modules/field_ui/field_ui-rtl.css
@@ -1,6 +1,6 @@
/**
* @file
- * Right-to-left specific stylesheet for the Field UI module.
+ * Right-to-left specific stylesheet for the Field UI module.
*/
/* 'Manage fields' overview */
diff --git a/core/modules/field_ui/field_ui.admin.inc b/core/modules/field_ui/field_ui.admin.inc
index 73b1492..24a99e1 100644
--- a/core/modules/field_ui/field_ui.admin.inc
+++ b/core/modules/field_ui/field_ui.admin.inc
@@ -553,8 +553,19 @@
}
// Additional row: add existing field.
- $existing_field_options = field_ui_existing_field_options($entity_type, $bundle);
- if ($existing_field_options && $widget_type_options) {
+ $existing_fields = field_ui_existing_field_options($entity_type, $bundle);
+ if ($existing_fields && $widget_type_options) {
+ // Build list of options.
+ $existing_field_options = array();
+ foreach ($existing_fields as $field_name => $info) {
+ $text = t('@type: @field (@label)', array(
+ '@type' => $info['type_label'],
+ '@label' => $info['label'],
+ '@field' => $info['field'],
+ ));
+ $existing_field_options[$field_name] = truncate_utf8($text, 80, FALSE, TRUE);
+ }
+ asort($existing_field_options);
$name = '_add_existing_field';
$table[$name] = array(
'#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'add-new')),
@@ -630,10 +641,8 @@
// Add settings for the update selects behavior.
$js_fields = array();
- foreach ($existing_field_options as $field_name => $fields) {
- $field = field_info_field($field_name);
- $instance = field_info_instance($form['#entity_type'], $field_name, $form['#bundle']);
- $js_fields[$field_name] = array('label' => $instance['label'], 'type' => $field['type'], 'widget' => $instance['widget']['type']);
+ foreach ($existing_fields as $field_name => $info) {
+ $js_fields[$field_name] = array('label' => $info['label'], 'type' => $info['type'], 'widget' => $info['widget_type']);
}
$form['#attached']['js'][] = array(
@@ -1522,7 +1531,7 @@
* Returns an array of existing fields to be added to a bundle.
*/
function field_ui_existing_field_options($entity_type, $bundle) {
- $options = array();
+ $info = array();
$field_types = field_info_field_types();
foreach (field_info_instances() as $existing_entity_type => $bundles) {
@@ -1541,19 +1550,19 @@
&& !field_info_instance($entity_type, $field['field_name'], $bundle)
&& (empty($field['entity_types']) || in_array($entity_type, $field['entity_types']))
&& empty($field_types[$field['type']]['no_ui'])) {
- $text = t('@type: @field (@label)', array(
- '@type' => $field_types[$field['type']]['label'],
- '@label' => t($instance['label']), '@field' => $instance['field_name'],
- ));
- $options[$instance['field_name']] = (drupal_strlen($text) > 80 ? truncate_utf8($text, 77) . '...' : $text);
+ $info[$instance['field_name']] = array(
+ 'type' => $field['type'],
+ 'type_label' => $field_types[$field['type']]['label'],
+ 'field' => $field['field_name'],
+ 'label' => t($instance['label']),
+ 'widget_type' => $instance['widget']['type'],
+ );
}
}
}
}
}
- // Sort the list by field name.
- asort($options);
- return $options;
+ return $info;
}
/**
diff --git a/core/modules/field_ui/field_ui.js b/core/modules/field_ui/field_ui.js
index a80f0a1..aa9527a 100644
--- a/core/modules/field_ui/field_ui.js
+++ b/core/modules/field_ui/field_ui.js
@@ -45,6 +45,11 @@
$('.field-select', table).each(function () {
this.targetSelect = $('.widget-type-select', $(this).parents('tr').eq(0));
this.targetTextfield = $('.label-textfield', $(this).parents('tr').eq(0));
+ this.targetTextfield
+ .data('field_ui_edited', false)
+ .bind('keyup', function (e) {
+ $(this).data('field_ui_edited', $(this).val() != '');
+ });
$(this).bind('change keyup', function (e, updateText) {
var updateText = (typeof updateText == 'undefined' ? true : updateText);
@@ -54,8 +59,10 @@
var options = (selectedFieldType && (selectedFieldType in widgetTypes) ? widgetTypes[selectedFieldType] : []);
this.targetSelect.fieldUIPopulateOptions(options, selectedFieldWidget);
- if (updateText) {
- $(this.targetTextfield).attr('value', (selectedField in fields ? fields[selectedField].label : ''));
+ // Only overwrite the "Label" input if it has not been manually
+ // changed, or if it is empty.
+ if (updateText && !this.targetTextfield.data('field_ui_edited')) {
+ this.targetTextfield.val(selectedField in fields ? fields[selectedField].label : '');
}
});
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 776b965..ab807dc 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -51,9 +51,7 @@
*/
function field_ui_field_attach_rename_bundle($entity_type, $bundle_old, $bundle_new) {
// The Field UI relies on entity_get_info() to build menu items for entity
- // field administration pages. Clear the entity info cache and ensure that
- // the menu is rebuilt.
- entity_info_cache_clear();
+ // field administration pages. Ensure that the menu is rebuilt.
menu_rebuild();
}
diff --git a/core/modules/field_ui/field_ui.test b/core/modules/field_ui/field_ui.test
index 4bb7da9..c2e3a98 100644
--- a/core/modules/field_ui/field_ui.test
+++ b/core/modules/field_ui/field_ui.test
@@ -18,7 +18,10 @@
if (isset($modules[0]) && is_array($modules[0])) {
$modules = $modules[0];
}
+ $modules[] = 'node';
+ $modules[] = 'field_ui';
$modules[] = 'field_test';
+ $modules[] = 'taxonomy';
parent::setUp($modules);
// Create test user.
@@ -134,6 +137,8 @@
* Tests the functionality of the 'Manage fields' screen.
*/
class FieldUIManageFieldsTestCase extends FieldUITestCase {
+ protected $profile = 'testing';
+
public static function getInfo() {
return array(
'name' => 'Manage fields',
@@ -149,6 +154,31 @@
$this->field_label = $this->randomName(8);
$this->field_name_input = strtolower($this->randomName(8));
$this->field_name = 'field_'. $this->field_name_input;
+
+ // Create Basic page and Article node types.
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+ $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+
+ // Create a vocabulary named "Tags".
+ $vocabulary = (object) array(
+ 'name' => 'Tags',
+ 'machine_name' => 'tags',
+ );
+ taxonomy_vocabulary_save($vocabulary);
+
+ $field = array(
+ 'field_name' => 'field_' . $vocabulary->machine_name,
+ 'type' => 'taxonomy_term_reference',
+ );
+ field_create_field($field);
+
+ $instance = array(
+ 'field_name' => 'field_' . $vocabulary->machine_name,
+ 'entity_type' => 'node',
+ 'label' => 'Tags',
+ 'bundle' => 'article',
+ );
+ field_create_instance($instance);
}
/**
diff --git a/core/modules/file/file.admin.css b/core/modules/file/file.admin.css
index 0bfcb77..c299bc0 100644
--- a/core/modules/file/file.admin.css
+++ b/core/modules/file/file.admin.css
@@ -15,12 +15,6 @@
display: inline;
float: none;
}
-.form-managed-file div.ajax-progress,
-.form-managed-file div.throbber {
- display: inline;
- float: none;
- padding: 1px 5px 2px 5px;
-}
.form-managed-file div.ajax-progress-bar {
display: none;
margin-top: 4px;
diff --git a/core/modules/file/file.field.inc b/core/modules/file/file.field.inc
index f0d978a..a46ed1a 100644
--- a/core/modules/file/file.field.inc
+++ b/core/modules/file/file.field.inc
@@ -993,11 +993,13 @@
break;
case 'file_table':
- // Display all values in a single element..
- $element[0] = array(
- '#theme' => 'file_formatter_table',
- '#items' => $items,
- );
+ if (!empty($items)) {
+ // Display all values in a single element..
+ $element[0] = array(
+ '#theme' => 'file_formatter_table',
+ '#items' => $items,
+ );
+ }
break;
}
diff --git a/core/modules/file/tests/file.test b/core/modules/file/tests/file.test
index bad8f99..7ff738a 100644
--- a/core/modules/file/tests/file.test
+++ b/core/modules/file/tests/file.test
@@ -760,6 +760,19 @@
$field = field_info_field($field_name);
$instance = field_info_instance('node', $field_name, $type_name);
+ // Create a new node *without* the file field set, and check that the field
+ // is not shown for each node display.
+ $node = $this->drupalCreateNode(array('type' => $type_name));
+ $file_formatters = array('file_default', 'file_table', 'file_url_plain', 'hidden');
+ foreach ($file_formatters as $formatter) {
+ $edit = array(
+ "fields[$field_name][type]" => $formatter,
+ );
+ $this->drupalPost("admin/structure/types/manage/$type_name/display", $edit, t('Save'));
+ $this->drupalGet('node/' . $node->nid);
+ $this->assertNoText($field_name, t('Field label is hidden when no file attached for formatter %formatter', array('%formatter' => $formatter)));
+ }
+
$test_file = $this->getTestFile('text');
// Create a new node with the uploaded file.
diff --git a/core/modules/forum/forum.info b/core/modules/forum/forum.info
index cb6e3e7..f202f9e 100644
--- a/core/modules/forum/forum.info
+++ b/core/modules/forum/forum.info
@@ -1,5 +1,6 @@
name = Forum
description = Provides discussion forums.
+dependencies[] = node
dependencies[] = taxonomy
dependencies[] = comment
package = Core
diff --git a/core/modules/help/help.module b/core/modules/help/help.module
index 773a52d..6f7322e 100644
--- a/core/modules/help/help.module
+++ b/core/modules/help/help.module
@@ -43,7 +43,10 @@
$output .= '
' . t('Configure your website Once logged in, visit the administration section, where you can customize and configure all aspects of your website.', array('@admin' => url('admin'), '@config' => url('admin/config'))) . '
';
$output .= '
' . t('Enable additional functionality Next, visit the module list and enable features which suit your specific needs. You can find additional modules in the Drupal modules download section.', array('@modules' => url('admin/modules'), '@download_modules' => 'http://drupal.org/project/modules')) . '
';
$output .= '
' . t('Customize your website design To change the "look and feel" of your website, visit the themes section. You may choose from one of the included themes or download additional themes from the Drupal themes download section.', array('@themes' => url('admin/appearance'), '@download_themes' => 'http://drupal.org/project/themes')) . '
';
- $output .= '
' . t('Start posting content Finally, you can add new content for your website.', array('@content' => url('node/add'))) . '
';
+ // Display a link to the create content page if Node module is enabled.
+ if (module_exists('node')) {
+ $output .= '
' . t('Start posting content Finally, you can add new content for your website.', array('@content' => url('node/add'))) . '
';
+ }
$output .= '';
$output .= '
' . t('For more information, refer to the specific topics listed in the next section or to the online Drupal handbooks. You may also post at the Drupal forum or view the wide range of other support options available.', array('@help' => url('admin/help'), '@handbook' => 'http://drupal.org/handbooks', '@forum' => 'http://drupal.org/forum', '@support' => 'http://drupal.org/support')) . '
';
return $output;
diff --git a/core/modules/image/image.field.inc b/core/modules/image/image.field.inc
index 7a38df4..aef6be7 100644
--- a/core/modules/image/image.field.inc
+++ b/core/modules/image/image.field.inc
@@ -404,7 +404,7 @@
'#default_value' => isset($item['alt']) ? $item['alt'] : '',
'#description' => t('This text will be used by screen readers, search engines, or when the image cannot be loaded.'),
// @see http://www.gawds.org/show.php?contentid=28
- '#maxlength' => 128,
+ '#maxlength' => 512,
'#weight' => -2,
'#access' => (bool) $item['fid'] && $settings['alt_field'],
);
@@ -413,7 +413,7 @@
'#title' => t('Title'),
'#default_value' => isset($item['title']) ? $item['title'] : '',
'#description' => t('The title is used as a tool tip when the user hovers the mouse over the image.'),
- '#maxlength' => 128,
+ '#maxlength' => 1024,
'#weight' => -1,
'#access' => (bool) $item['fid'] && $settings['title_field'],
);
diff --git a/core/modules/image/image.install b/core/modules/image/image.install
index 4d4399c..02be57c 100644
--- a/core/modules/image/image.install
+++ b/core/modules/image/image.install
@@ -118,13 +118,13 @@
'alt' => array(
'description' => "Alternative image text, for the image's 'alt' attribute.",
'type' => 'varchar',
- 'length' => 128,
+ 'length' => 512,
'not null' => FALSE,
),
'title' => array(
'description' => "Image title text, for the image's 'title' attribute.",
'type' => 'varchar',
- 'length' => 128,
+ 'length' => 1024,
'not null' => FALSE,
),
'width' => array(
diff --git a/core/modules/image/image.test b/core/modules/image/image.test
index 6fa015e..0fc2a4c 100644
--- a/core/modules/image/image.test
+++ b/core/modules/image/image.test
@@ -746,7 +746,10 @@
$widget_settings = array(
'preview_image_style' => 'medium',
);
- $this->createImageField($field_name, 'article', array(), $instance_settings, $widget_settings);
+ $field = $this->createImageField($field_name, 'article', array(), $instance_settings, $widget_settings);
+ $field['deleted'] = 0;
+ $table = _field_sql_storage_tablename($field);
+ $schema = drupal_get_schema($table, TRUE);
$instance = field_info_instance('node', $field_name, 'article');
$this->drupalGet('node/add/article');
@@ -789,18 +792,17 @@
// Verify that alt/title longer than allowed results in a validation error.
$test_size = 2000;
- $max_size = 128;
$edit = array(
$field_name . '[' . LANGUAGE_NONE . '][0][alt]' => $this->randomName($test_size),
$field_name . '[' . LANGUAGE_NONE . '][0][title]' => $this->randomName($test_size),
);
$this->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
$this->assertRaw(t('Alternate text cannot be longer than %max characters but is currently %length characters long.', array(
- '%max' => $max_size,
+ '%max' => $schema['fields'][$field_name .'_alt']['length'],
'%length' => $test_size,
)));
$this->assertRaw(t('Title cannot be longer than %max characters but is currently %length characters long.', array(
- '%max' => $max_size,
+ '%max' => $schema['fields'][$field_name .'_title']['length'],
'%length' => $test_size,
)));
}
diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc
new file mode 100644
index 0000000..a6a767f
--- /dev/null
+++ b/core/modules/language/language.admin.inc
@@ -0,0 +1,438 @@
+ $languages,
+ '#language_default' => $default,
+ '#tree' => TRUE,
+ '#header' => array(
+ t('Name'),
+ t('Enabled'),
+ t('Default'),
+ t('Weight'),
+ t('Operations'),
+ ),
+ '#theme' => 'language_admin_overview_form_table',
+ );
+
+ foreach ($languages as $langcode => $language) {
+ $form['languages'][$langcode]['#weight'] = $language->weight;
+ $form['languages'][$langcode]['name'] = array(
+ '#markup' => check_plain($language->name),
+ );
+ $form['languages'][$langcode]['enabled'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Enable @title', array('@title' => $language->name)),
+ '#title_display' => 'invisible',
+ '#default_value' => (int) $language->enabled,
+ '#disabled' => $langcode == $default->language,
+ );
+ $form['languages'][$langcode]['default'] = array(
+ '#type' => 'radio',
+ '#parents' => array('site_default'),
+ '#title' => t('Set @title as default', array('@title' => $language->name)),
+ '#title_display' => 'invisible',
+ '#return_value' => $langcode,
+ '#default_value' => ($langcode == $default->language ? $langcode : NULL),
+ '#id' => 'edit-site-default-' . $langcode,
+ );
+ $form['languages'][$langcode]['weight'] = array(
+ '#type' => 'weight',
+ '#title' => t('Weight for @title', array('@title' => $language->name)),
+ '#title_display' => 'invisible',
+ '#default_value' => $language->weight,
+ '#attributes' => array(
+ 'class' => array('language-order-weight'),
+ ),
+ );
+ $form['languages'][$langcode]['operations'] = array(
+ '#theme_wrappers' => array('language_admin_operations'),
+ '#weight' => 100,
+ );
+ $form['languages'][$langcode]['operations']['edit'] = array(
+ '#type' => 'link',
+ '#title' => t('edit'),
+ '#href' => 'admin/config/regional/language/edit/' . $langcode,
+ );
+ $form['languages'][$langcode]['operations']['delete'] = array(
+ '#type' => 'link',
+ '#title' => t('delete'),
+ '#href' => 'admin/config/regional/language/delete/' . $langcode,
+ '#access' => $langcode != $default->language,
+ );
+ }
+
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save configuration'),
+ );
+
+ return $form;
+}
+
+/**
+ * Returns HTML for operation links in language_admin_overview_form() table.
+ *
+ * @todo Introduce #type '[table_]operations' or just simply #type 'links'.
+ */
+function theme_language_admin_operations($variables) {
+ $links = array();
+ foreach (element_children($variables['elements']) as $key) {
+ // Children are only rendered if the current user has access.
+ if (isset($variables['elements'][$key]['#children'])) {
+ $links[$key] = $variables['elements'][$key]['#children'];
+ }
+ }
+ // If there are links, render a link list.
+ if (!empty($links)) {
+ return theme('item_list__operations', array(
+ 'items' => $links,
+ 'attributes' => array('class' => array('links', 'inline')),
+ ));
+ }
+ // Otherwise, ensure to produce no output.
+ return '';
+}
+
+/**
+ * Returns HTML for the language overview form.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - form: A render element representing the form.
+ *
+ * @ingroup themeable
+ */
+function theme_language_admin_overview_form_table($variables) {
+ $form = $variables['form'];
+
+ $rows = array();
+ foreach (element_children($form, TRUE) as $langcode) {
+ $element = &$form[$langcode];
+ $row = array(
+ 'class' => array('draggable'),
+ );
+ foreach (element_children($element, TRUE) as $column) {
+ $cell = &$element[$column];
+ $row['data'][] = drupal_render($cell);
+ }
+ $rows[] = $row;
+ }
+
+ $output = theme('table', array(
+ 'header' => $form['#header'],
+ 'rows' => $rows,
+ 'attributes' => array('id' => 'language-order'),
+ ));
+ $output .= drupal_render_children($form);
+
+ drupal_add_tabledrag('language-order', 'order', 'sibling', 'language-order-weight');
+
+ return $output;
+}
+
+/**
+ * Process language overview form submissions, updating existing languages.
+ */
+function language_admin_overview_form_submit($form, &$form_state) {
+ $languages = language_list();
+ $old_default = language_default();
+
+ foreach ($languages as $langcode => $language) {
+ $language->default = ($form_state['values']['site_default'] == $langcode);
+ $language->weight = $form_state['values']['languages'][$langcode]['weight'];
+
+ if ($language->default || $old_default->language == $langcode) {
+ // Automatically enable the default language and the language
+ // which was default previously (because we will not get the
+ // value from that disabled checkbox).
+ $form_state['values']['languages'][$langcode]['enabled'] = 1;
+ }
+ $language->enabled = (int) !empty($form_state['values']['languages'][$langcode]['enabled']);
+
+ language_save($language);
+ }
+
+ drupal_set_message(t('Configuration saved.'));
+}
+
+/**
+ * User interface for the language addition screen.
+ */
+function language_admin_add_form($form, &$form_state) {
+ $predefined_languages = language_admin_predefined_list();
+ $predefined_languages['custom'] = t('Custom language...');
+ $predefined_default = !empty($form_state['values']['predefined_langcode']) ? $form_state['values']['predefined_langcode'] : key($predefined_languages);
+ $form['predefined_langcode'] = array(
+ '#type' => 'select',
+ '#title' => t('Language name'),
+ '#default_value' => $predefined_default,
+ '#options' => $predefined_languages,
+ );
+ $form['predefined_submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Add language'),
+ '#limit_validation_errors' => array(array('predefined_langcode'), array('predefined_submit')),
+ '#states' => array(
+ 'invisible' => array(
+ 'select#edit-predefined-langcode' => array('value' => 'custom'),
+ ),
+ ),
+ '#validate' => array('language_admin_add_predefined_form_validate'),
+ '#submit' => array('language_admin_add_predefined_form_submit'),
+ );
+
+ $form['custom_language'] = array(
+ '#type' => 'container',
+ '#states' => array(
+ 'visible' => array(
+ 'select#edit-predefined-langcode' => array('value' => 'custom'),
+ ),
+ ),
+ );
+ _language_admin_common_controls($form['custom_language']);
+ $form['custom_language']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Add custom language'),
+ '#validate' => array('language_admin_add_custom_form_validate'),
+ '#submit' => array('language_admin_add_custom_form_submit'),
+ );
+
+ return $form;
+}
+
+/**
+ * Editing screen for a particular language.
+ *
+ * @param $langcode
+ * Language code of the language to edit.
+ */
+function language_admin_edit_form($form, &$form_state, $language) {
+ _language_admin_common_controls($form, $language);
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save language')
+ );
+ $form['#submit'][] = 'language_admin_edit_form_submit';
+ $form['#validate'][] = 'language_admin_edit_form_validate';
+ return $form;
+}
+
+/**
+ * Common elements of the language addition and editing form.
+ *
+ * @param $form
+ * A parent form item (or empty array) to add items below.
+ * @param $language
+ * Language object to edit.
+ */
+function _language_admin_common_controls(&$form, $language = NULL) {
+ if (!is_object($language)) {
+ $language = new stdClass();
+ }
+ if (isset($language->language)) {
+ $form['langcode_view'] = array(
+ '#type' => 'item',
+ '#title' => t('Language code'),
+ '#markup' => $language->language
+ );
+ $form['langcode'] = array(
+ '#type' => 'value',
+ '#value' => $language->language
+ );
+ }
+ else {
+ $form['langcode'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Language code'),
+ '#maxlength' => 12,
+ '#required' => TRUE,
+ '#default_value' => @$language->language,
+ '#disabled' => (isset($language->language)),
+ '#description' => t('Use language codes as defined by the W3C for interoperability. Examples: "en", "en-gb" and "zh-hant".', array('@w3ctags' => 'http://www.w3.org/International/articles/language-tags/')),
+ );
+ }
+ $form['name'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Language name'),
+ '#maxlength' => 64,
+ '#default_value' => @$language->name,
+ '#required' => TRUE,
+ );
+ $form['direction'] = array(
+ '#type' => 'radios',
+ '#title' => t('Direction'),
+ '#required' => TRUE,
+ '#description' => t('Direction that text in this language is presented.'),
+ '#default_value' => @$language->direction,
+ '#options' => array(LANGUAGE_LTR => t('Left to right'), LANGUAGE_RTL => t('Right to left'))
+ );
+ return $form;
+}
+
+/**
+ * Element specific validator for the Add language button.
+ */
+function language_admin_add_predefined_form_validate($form, &$form_state) {
+ $langcode = $form_state['values']['predefined_langcode'];
+ if ($langcode == 'custom') {
+ form_set_error('predefined_langcode', t('Fill in the language details and save the language with Add custom language.'));
+ }
+ else {
+ if (language_load($langcode)) {
+ form_set_error('predefined_langcode', t('The language %language (%langcode) already exists.', array('%language' => $languages[$langcode]->name, '%langcode' => $langcode)));
+ }
+ }
+}
+
+/**
+ * Validate the language addition form on custom language button.
+ */
+function language_admin_add_custom_form_validate($form, &$form_state) {
+ if ($form_state['values']['predefined_langcode'] == 'custom') {
+ $langcode = $form_state['values']['langcode'];
+ // Reuse the editing form validation routine if we add a custom language.
+ language_admin_edit_form_validate($form, $form_state);
+
+ $languages = language_list();
+ if (isset($languages[$langcode])) {
+ form_set_error('langcode', t('The language %language (%langcode) already exists.', array('%language' => $languages[$langcode]->name, '%langcode' => $langcode)));
+ }
+ }
+ else {
+ form_set_error('predefined_langcode', t('Use the Add language button to save a predefined language.'));
+ }
+}
+
+/**
+ * Process the custom language addition form submission.
+ */
+function language_admin_add_custom_form_submit($form, &$form_state) {
+ $langcode = $form_state['values']['langcode'];
+ // Custom language form.
+ $language = (object) array(
+ 'language' => $langcode,
+ 'name' => $form_state['values']['name'],
+ 'direction' => $form_state['values']['direction'],
+ );
+ language_save($language);
+ drupal_set_message(t('The language %language has been created and can now be used.', array('%language' => $form_state['values']['name'])));
+ $form_state['redirect'] = 'admin/config/regional/language';
+}
+
+/**
+ * Process the predefined language addition form submission.
+ */
+function language_admin_add_predefined_form_submit($form, &$form_state) {
+ // Predefined language selection.
+ $langcode = $form_state['values']['predefined_langcode'];
+ include_once DRUPAL_ROOT . '/core/includes/standard.inc';
+ $predefined = standard_language_list();
+ $language = (object) array(
+ 'language' => $langcode,
+ );
+ language_save($language);
+ drupal_set_message(t('The language %language has been created and can now be used.', array('%language' => t($predefined[$langcode][0]))));
+ $form_state['redirect'] = 'admin/config/regional/language';
+}
+
+/**
+ * Validate the language editing form. Reused for custom language addition too.
+ */
+function language_admin_edit_form_validate($form, &$form_state) {
+ // Ensure sane field values for langcode and name.
+ if (!isset($form['langcode_view']) && preg_match('@[^a-zA-Z_-]@', $form_state['values']['langcode'])) {
+ form_set_error('langcode', t('%field may only contain characters a-z, underscores, or hyphens.', array('%field' => $form['langcode']['#title'])));
+ }
+ if ($form_state['values']['name'] != check_plain($form_state['values']['name'])) {
+ form_set_error('name', t('%field cannot contain any markup.', array('%field' => $form['name']['#title'])));
+ }
+}
+
+/**
+ * Process the language editing form submission.
+ */
+function language_admin_edit_form_submit($form, &$form_state) {
+ // Prepare a language object for saving
+ $languages = language_list();
+ $langcode = $form_state['values']['langcode'];
+ $language = $languages[$langcode];
+ $language->name = $form_state['values']['name'];
+ $language->direction = $form_state['values']['direction'];
+ language_save($language);
+ $form_state['redirect'] = 'admin/config/regional/language';
+}
+
+/**
+ * User interface for the language deletion confirmation screen.
+ */
+function language_admin_delete_form($form, &$form_state, $language) {
+ $langcode = $language->language;
+
+ if (language_default()->language == $langcode) {
+ drupal_set_message(t('The default language cannot be deleted.'));
+ drupal_goto('admin/config/regional/language');
+ }
+
+ // For other languages, warn user that data loss is ahead.
+ $languages = language_list();
+
+ if (!isset($languages[$langcode])) {
+ drupal_not_found();
+ drupal_exit();
+ }
+ else {
+ $form['langcode'] = array('#type' => 'value', '#value' => $langcode);
+ return confirm_form($form, t('Are you sure you want to delete the language %language?', array('%language' => $languages[$langcode]->name)), 'admin/config/regional/language', t('Deleting a language will remove all interface translations associated with it, and posts in this language will be set to be language neutral. This action cannot be undone.'), t('Delete'), t('Cancel'));
+ }
+}
+
+/**
+ * Process language deletion submissions.
+ */
+function language_admin_delete_form_submit($form, &$form_state) {
+ $langcode = $form_state['values']['langcode'];
+ $languages = language_list();
+ $language = $languages[$langcode];
+
+ $success = language_delete($langcode);
+
+ if ($success) {
+ $t_args = array('%language' => $language->name, '%langcode' => $language->language);
+ drupal_set_message(t('The %language (%langcode) language has been removed.', $t_args));
+ }
+
+ $form_state['redirect'] = 'admin/config/regional/language';
+}
+
+/**
+ * Prepare a language code list for unused predefined languages.
+ */
+function language_admin_predefined_list() {
+ include_once DRUPAL_ROOT . '/core/includes/standard.inc';
+ $languages = language_list();
+ $predefined = standard_language_list();
+ foreach ($predefined as $key => $value) {
+ if (isset($languages[$key])) {
+ unset($predefined[$key]);
+ continue;
+ }
+ $predefined[$key] = t($value[0]);
+ }
+ asort($predefined);
+ return $predefined;
+}
diff --git a/core/modules/language/language.api.php b/core/modules/language/language.api.php
new file mode 100644
index 0000000..a1ed10d
--- /dev/null
+++ b/core/modules/language/language.api.php
@@ -0,0 +1,62 @@
+default) {
+ // React to a new default language.
+ example_new_default_language($language);
+ }
+}
+
+/**
+ * React to a language that was just added to the system.
+ *
+ * @param $language
+ * A language object.
+ */
+function hook_language_insert($language) {
+ example_refresh_permissions();
+}
+
+/**
+ * React to a language that was just updated in the system.
+ *
+ * @param $language
+ * A language object.
+ */
+function hook_language_update($language) {
+ example_refresh_permissions();
+}
+
+/**
+ * Allow modules to react before the deletion of a language.
+ *
+ * @param $language
+ * The language object of the language that is about to be deleted.
+ */
+function hook_language_delete($language) {
+ // On nodes with this language, unset the language
+ db_update('node')
+ ->fields(array('language' => ''))
+ ->condition('language', $language->language)
+ ->execute();
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */
diff --git a/core/modules/language/language.info b/core/modules/language/language.info
new file mode 100644
index 0000000..699b283
--- /dev/null
+++ b/core/modules/language/language.info
@@ -0,0 +1,7 @@
+name = Language
+description = Lets you configure a number of languages to be used on your website.
+package = Core
+version = VERSION
+core = 8.x
+configure = admin/config/regional/language
+files[] = language.test
diff --git a/core/modules/language/language.install b/core/modules/language/language.install
new file mode 100644
index 0000000..4ba83d6
--- /dev/null
+++ b/core/modules/language/language.install
@@ -0,0 +1,75 @@
+ 'List of all available languages in the system.',
+ 'fields' => array(
+ 'language' => array(
+ 'type' => 'varchar',
+ 'length' => 12,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => "Language code, e.g. 'de' or 'en-US'.",
+ ),
+ 'name' => array(
+ 'type' => 'varchar',
+ 'length' => 64,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'Language name.',
+ ),
+ 'direction' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'default' => 0,
+ 'description' => 'Direction of language (Left-to-Right = 0, Right-to-Left = 1).',
+ ),
+ 'enabled' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'default' => 0,
+ 'description' => 'Enabled flag (1 = Enabled, 0 = Disabled).',
+ ),
+ 'weight' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'default' => 0,
+ 'description' => 'Weight, used in lists of languages.',
+ ),
+ ),
+ 'primary key' => array('language'),
+ 'indexes' => array(
+ 'list' => array('weight', 'name'),
+ ),
+ );
+ return $schema;
+}
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
new file mode 100644
index 0000000..4bf890b
--- /dev/null
+++ b/core/modules/language/language.module
@@ -0,0 +1,200 @@
+' . t('About') . '';
+ $output .= '
' . t('The Language module allows you to maintain a list of languages used on your Drupal site for providing language information for content and for interface translation (using the Locale module). For more information, see the online handbook entry for Language module.', array('@language' => 'http://drupal.org/handbook/modules/language/')) . '
';
+ $output .= '
' . t('Uses') . '
';
+ $output .= '
';
+ $output .= '
' . t('Configuring the list of languages') . '
';
+ $output .= '
' . t('Configure the list of languages either using the built-in language list or providing any custom languages you wish.', array('@configure-languages' => url('admin/config/regional/language'))) . '
' . t('With multiple languages enabled, registered users may select their preferred language and authors can assign a specific language to content.') . '
';
+
+ case 'admin/config/regional/language/add':
+ return '
' . t('Add a language to be supported by your site. If your desired language is not available, pick Custom language... at the end and provide a language code and other details manually.') . '
';
+ }
+}
+
+/**
+ * Implements hook_menu().
+ */
+function language_menu() {
+ $items['admin/config/regional/language'] = array(
+ 'title' => 'Languages',
+ 'description' => 'Configure languages for content and the user interface.',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('language_admin_overview_form'),
+ 'access arguments' => array('administer languages'),
+ 'file' => 'language.admin.inc',
+ 'weight' => -10,
+ );
+ $items['admin/config/regional/language/list'] = array(
+ 'title' => 'List',
+ 'weight' => 0,
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ );
+ $items['admin/config/regional/language/add'] = array(
+ 'title' => 'Add language',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('language_admin_add_form'),
+ 'access arguments' => array('administer languages'),
+ 'weight' => 5,
+ 'type' => MENU_LOCAL_ACTION,
+ 'file' => 'language.admin.inc',
+ );
+ $items['admin/config/regional/language/edit/%language'] = array(
+ 'title' => 'Edit language',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('language_admin_edit_form', 5),
+ 'access arguments' => array('administer languages'),
+ 'file' => 'language.admin.inc',
+ );
+ $items['admin/config/regional/language/delete/%language'] = array(
+ 'title' => 'Confirm delete',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('language_admin_delete_form', 5),
+ 'access arguments' => array('administer languages'),
+ 'file' => 'language.admin.inc',
+ );
+ return $items;
+}
+
+/**
+ * Implements hook_permission().
+ */
+function language_permission() {
+ return array(
+ 'administer languages' => array(
+ 'title' => t('Administer languages'),
+ ),
+ );
+}
+
+/**
+ * Implements hook_theme().
+ */
+function language_theme() {
+ return array(
+ 'language_admin_overview_form_table' => array(
+ 'render element' => 'form',
+ 'file' => 'language.admin.inc',
+ ),
+ 'language_admin_operations' => array(
+ 'render element' => 'elements',
+ 'file' => 'language.admin.inc',
+ ),
+ );
+}
+
+/**
+ * Loads a language object from the database.
+ *
+ * @param $langcode
+ * The language code.
+ *
+ * @return
+ * A fully-populated language object or FALSE.
+ */
+function language_load($langcode) {
+ $languages = language_list();
+ return isset($languages[$langcode]) ? $languages[$langcode] : FALSE;
+}
+
+/**
+ * API function to add or update a language.
+ *
+ * @param $language
+ * Language object with properties corresponding to 'language' table columns.
+ */
+function language_save($language) {
+ $language->is_new = !(bool) db_query_range('SELECT 1 FROM {language} WHERE language = :language', 0, 1, array(':language' => $language->language))->fetchField();
+
+ // If name was not set, we add a predefined language.
+ if (!isset($language->name)) {
+ include_once DRUPAL_ROOT . '/core/includes/standard.inc';
+ $predefined = standard_language_list();
+ $language->name = $predefined[$language->language][0];
+ $language->direction = isset($predefined[$language->language][2]) ? $predefined[$language->language][2] : LANGUAGE_LTR;
+ }
+
+ // Set to enabled for the default language and unless specified otherwise.
+ if (!empty($language->default) || !isset($language->enabled)) {
+ $language->enabled = TRUE;
+ }
+ // Let other modules modify $language before saved.
+ module_invoke_all('language_presave', $language);
+
+ // Save the record and inform others about the change.
+ $t_args = array('%language' => $language->name, '%langcode' => $language->language);
+ if ($language->is_new) {
+ drupal_write_record('language', $language);
+ module_invoke_all('language_insert', $language);
+ watchdog('language', 'The %language (%langcode) language has been created.', $t_args);
+ }
+ else {
+ drupal_write_record('language', $language, array('language'));
+ module_invoke_all('language_update', $language);
+ watchdog('language', 'The %language (%langcode) language has been updated.', $t_args);
+ }
+
+ if (!empty($language->default)) {
+ // Set the new version of this language as default in a variable.
+ $default_language = language_default();
+ variable_set('language_default', $language);
+ }
+
+ // Update language count based on enabled language count.
+ variable_set('language_count', db_query('SELECT COUNT(language) FROM {language} WHERE enabled = 1')->fetchField());
+
+ // Kill the static cache in language_list().
+ drupal_static_reset('language_list');
+
+ return $language;
+}
+
+/**
+ * Delete a language.
+ *
+ * @param $langcode
+ * Language code of the language to be deleted.
+ * @return
+ * TRUE if language is successfully deleted. Otherwise FALSE.
+ */
+function language_delete($langcode) {
+ $languages = language_list();
+ if (isset($languages[$langcode])) {
+ $language = $languages[$langcode];
+
+ module_invoke_all('language_delete', $language);
+
+ // Remove the language.
+ db_delete('language')
+ ->condition('language', $language->language)
+ ->execute();
+
+ if ($language->enabled) {
+ variable_set('language_count', variable_get('language_count', 1) - 1);
+ }
+
+ drupal_static_reset('language_list');
+
+ $t_args = array('%language' => $language->name, '%langcode' => $language->language);
+ watchdog('language', 'The %language (%langcode) language has been removed.', $t_args);
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/core/modules/language/language.test b/core/modules/language/language.test
new file mode 100644
index 0000000..435548d
--- /dev/null
+++ b/core/modules/language/language.test
@@ -0,0 +1,181 @@
+ 'Language list configuration',
+ 'description' => 'Adds a new language and tests changing its status and the default language.',
+ 'group' => 'Language',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('language');
+ }
+
+ /**
+ * Functional tests for adding, editing and deleting languages.
+ */
+ function testLanguageList() {
+ global $base_url;
+
+ // User to add and remove language.
+ $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
+ $this->drupalLogin($admin_user);
+
+ // Add predefined language.
+ $edit = array(
+ 'predefined_langcode' => 'fr',
+ );
+ $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+ $this->assertText('French', t('Language added successfully.'));
+ $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+
+ // Add custom language.
+ $langcode = 'xx';
+ $name = $this->randomName(16);
+ $edit = array(
+ 'predefined_langcode' => 'custom',
+ 'langcode' => $langcode,
+ 'name' => $name,
+ 'direction' => '0',
+ );
+ $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+ $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+ $this->assertRaw('"edit-site-default-' . $langcode .'"', t('Language code found.'));
+ $this->assertText(t($name), t('Test language added.'));
+
+ // Check if we can change the default language.
+ $path = 'admin/config/regional/language';
+ $this->drupalGet($path);
+ $this->assertFieldChecked('edit-site-default-en', t('English is the default language.'));
+ // Change the default language.
+ $edit = array(
+ 'site_default' => $langcode,
+ );
+ $this->drupalPost(NULL, $edit, t('Save configuration'));
+ $this->assertNoFieldChecked('edit-site-default-en', t('Default language updated.'));
+ $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+
+ // Ensure we can't delete the default language.
+ $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
+ $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+ $this->assertText(t('The default language cannot be deleted.'), t('Failed to delete the default language.'));
+
+ // Check if we can disable a language.
+ $edit = array(
+ 'languages[en][enabled]' => FALSE,
+ );
+ $this->drupalPost($path, $edit, t('Save configuration'));
+ $this->assertNoFieldChecked('edit-languages-en-enabled', t('Language disabled.'));
+
+ // Set disabled language to be the default and ensure it is re-enabled.
+ $edit = array(
+ 'site_default' => 'en',
+ );
+ $this->drupalPost(NULL, $edit, t('Save configuration'));
+ $this->assertFieldChecked('edit-languages-en-enabled', t('Default language re-enabled.'));
+
+ // Ensure 'edit' link works.
+ $this->clickLink(t('edit'));
+ $this->assertTitle(t('Edit language | Drupal'), t('Page title is "Edit language".'));
+ // Edit a language.
+ $name = $this->randomName(16);
+ $edit = array(
+ 'name' => $name,
+ );
+ $this->drupalPost('admin/config/regional/language/edit/' . $langcode, $edit, t('Save language'));
+ $this->assertRaw($name, t('The language has been updated.'));
+ $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+
+ // Ensure 'delete' link works.
+ $this->drupalGet('admin/config/regional/language');
+ $this->clickLink(t('delete'));
+ $this->assertText(t('Are you sure you want to delete the language'), t('"delete" link is correct.'));
+ // Delete an enabled language.
+ $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
+ // First test the 'cancel' link.
+ $this->clickLink(t('Cancel'));
+ $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+ $this->assertRaw($name, t('The language was not deleted.'));
+ // Delete the language for real. This a confirm form, we do not need any
+ // fields changed.
+ $this->drupalPost('admin/config/regional/language/delete/' . $langcode, array(), t('Delete'));
+ // We need raw here because %language and %langcode will add HTML.
+ $t_args = array('%language' => $name, '%langcode' => $langcode);
+ $this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args), t('The test language has been removed.'));
+ $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+ // Verify that language is no longer found.
+ $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
+ $this->assertResponse(404, t('Language no longer found.'));
+ // Make sure the "language_count" variable has been updated correctly.
+ drupal_static_reset('language_list');
+ $enabled = language_list('enabled');
+ $this->assertEqual(variable_get('language_count', 1), count($enabled[1]), t('Language count is correct.'));
+ // Delete a disabled language.
+ // Disable an enabled language.
+ $edit = array(
+ 'languages[fr][enabled]' => FALSE,
+ );
+ $this->drupalPost($path, $edit, t('Save configuration'));
+ $this->assertNoFieldChecked('edit-languages-fr-enabled', t('French language disabled.'));
+ // Get the count of enabled languages.
+ drupal_static_reset('language_list');
+ $enabled = language_list('enabled');
+ // Delete the disabled language.
+ $this->drupalPost('admin/config/regional/language/delete/fr', array(), t('Delete'));
+ // We need raw here because %language and %langcode will add HTML.
+ $t_args = array('%language' => 'French', '%langcode' => 'fr');
+ $this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args), t('Disabled language has been removed.'));
+ $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+ // Verify that language is no longer found.
+ $this->drupalGet('admin/config/regional/language/delete/fr');
+ $this->assertResponse(404, t('Language no longer found.'));
+ // Make sure the "language_count" variable has not changed.
+ $this->assertEqual(variable_get('language_count', 1), count($enabled[1]), t('Language count is correct.'));
+
+ // Ensure we can delete the English language. Right now English is the only
+ // language so we must add a new language and make it the default before
+ // deleting English.
+ $langcode = 'xx';
+ $name = $this->randomName(16);
+ $edit = array(
+ 'predefined_langcode' => 'custom',
+ 'langcode' => $langcode,
+ 'name' => $name,
+ 'direction' => '0',
+ );
+ $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+ $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+ $this->assertText($name, t('Name found.'));
+
+ // Check if we can change the default language.
+ $path = 'admin/config/regional/language';
+ $this->drupalGet($path);
+ $this->assertFieldChecked('edit-site-default-en', t('English is the default language.'));
+ // Change the default language.
+ $edit = array(
+ 'site_default' => $langcode,
+ );
+ $this->drupalPost(NULL, $edit, t('Save configuration'));
+ $this->assertNoFieldChecked('edit-site-default-en', t('Default language updated.'));
+ $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+
+ $this->drupalPost('admin/config/regional/language/delete/en', array(), t('Delete'));
+ // We need raw here because %language and %langcode will add HTML.
+ $t_args = array('%language' => 'English', '%langcode' => 'en');
+ $this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args), t('The English language has been removed.'));
+ }
+}
diff --git a/core/modules/locale/locale.admin.inc b/core/modules/locale/locale.admin.inc
index 5732697..775ba1b 100644
--- a/core/modules/locale/locale.admin.inc
+++ b/core/modules/locale/locale.admin.inc
@@ -6,444 +6,6 @@
*/
/**
- * @defgroup locale-language-administration Language administration interface
- * @{
- * Administration interface for languages.
- *
- * These functions provide the user interface to show, add, edit and
- * delete languages as well as providing options for language negotiation.
- */
-
-/**
- * User interface for the language overview screen.
- */
-function locale_language_overview_form($form, &$form_state) {
- drupal_static_reset('language');
- $languages = language_list('language');
- $default = language_default();
-
- $form['languages'] = array(
- '#languages' => $languages,
- '#language_default' => $default,
- '#tree' => TRUE,
- '#header' => array(
- t('Name'),
- t('Enabled'),
- t('Default'),
- t('Weight'),
- t('Operations'),
- ),
- '#theme' => 'locale_language_overview_form_table',
- );
-
- foreach ($languages as $langcode => $language) {
- $form['languages'][$langcode]['#weight'] = $language->weight;
- $form['languages'][$langcode]['name'] = array(
- '#markup' => check_plain($language->name),
- );
- $form['languages'][$langcode]['enabled'] = array(
- '#type' => 'checkbox',
- '#title' => t('Enable @title', array('@title' => $language->name)),
- '#title_display' => 'invisible',
- '#default_value' => (int) $language->enabled,
- '#disabled' => $langcode == $default->language,
- );
- $form['languages'][$langcode]['default'] = array(
- '#type' => 'radio',
- '#parents' => array('site_default'),
- '#title' => t('Set @title as default', array('@title' => $language->name)),
- '#title_display' => 'invisible',
- '#return_value' => $langcode,
- '#default_value' => ($langcode == $default->language ? $langcode : NULL),
- '#id' => 'edit-site-default-' . $langcode,
- );
- $form['languages'][$langcode]['weight'] = array(
- '#type' => 'weight',
- '#title' => t('Weight for @title', array('@title' => $language->name)),
- '#title_display' => 'invisible',
- '#default_value' => $language->weight,
- '#attributes' => array(
- 'class' => array('language-order-weight'),
- ),
- );
- $form['languages'][$langcode]['operations'] = array(
- '#theme_wrappers' => array('locale_language_operations'),
- '#weight' => 100,
- );
- $form['languages'][$langcode]['operations']['edit'] = array(
- '#type' => 'link',
- '#title' => t('edit'),
- '#href' => 'admin/config/regional/language/edit/' . $langcode,
- );
- $form['languages'][$langcode]['operations']['delete'] = array(
- '#type' => 'link',
- '#title' => t('delete'),
- '#href' => 'admin/config/regional/language/delete/' . $langcode,
- '#access' => $langcode != $default->language,
- );
- }
-
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Save configuration'),
- );
-
- return $form;
-}
-
-/**
- * Returns HTML for operation links in locale_language_overview_form() table.
- *
- * @todo Introduce #type '[table_]operations' or just simply #type 'links'.
- */
-function theme_locale_language_operations($variables) {
- $links = array();
- foreach (element_children($variables['elements']) as $key) {
- // Children are only rendered if the current user has access.
- if (isset($variables['elements'][$key]['#children'])) {
- $links[$key] = $variables['elements'][$key]['#children'];
- }
- }
- // If there are links, render a link list.
- if (!empty($links)) {
- return theme('item_list__operations', array(
- 'items' => $links,
- 'attributes' => array('class' => array('links', 'inline')),
- ));
- }
- // Otherwise, ensure to produce no output.
- return '';
-}
-
-/**
- * Returns HTML for the language overview form.
- *
- * @param $variables
- * An associative array containing:
- * - form: A render element representing the form.
- *
- * @ingroup themeable
- */
-function theme_locale_language_overview_form_table($variables) {
- $form = $variables['form'];
-
- $rows = array();
- foreach (element_children($form, TRUE) as $langcode) {
- $element = &$form[$langcode];
- $row = array(
- 'class' => array('draggable'),
- );
- foreach (element_children($element, TRUE) as $column) {
- $cell = &$element[$column];
- $row['data'][] = drupal_render($cell);
- }
- $rows[] = $row;
- }
-
- $output = theme('table', array(
- 'header' => $form['#header'],
- 'rows' => $rows,
- 'attributes' => array('id' => 'language-order'),
- ));
- $output .= drupal_render_children($form);
-
- drupal_add_tabledrag('language-order', 'order', 'sibling', 'language-order-weight');
-
- return $output;
-}
-
-/**
- * Process language overview form submissions, updating existing languages.
- */
-function locale_language_overview_form_submit($form, &$form_state) {
- $languages = language_list();
- $old_default = language_default();
- $url_prefixes = variable_get('locale_language_negotiation_url_part', LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX) == LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX;
-
- foreach ($languages as $langcode => $language) {
- $language->default = ($form_state['values']['site_default'] == $langcode);
- $language->weight = $form_state['values']['languages'][$langcode]['weight'];
-
- if ($language->default || $old_default->language == $langcode) {
- // Automatically enable the default language and the language
- // which was default previously (because we will not get the
- // value from that disabled checkbox).
- $form_state['values']['languages'][$langcode]['enabled'] = 1;
- }
- $language->enabled = (int) !empty($form_state['values']['languages'][$langcode]['enabled']);
-
- locale_language_save($language);
- }
-
- drupal_set_message(t('Configuration saved.'));
-}
-
-/**
- * User interface for the language addition screen.
- */
-function locale_languages_add_form($form, &$form_state) {
- $predefined_languages = _locale_prepare_predefined_list();
- $predefined_languages['custom'] = t('Custom language...');
- $predefined_default = !empty($form_state['values']['predefined_langcode']) ? $form_state['values']['predefined_langcode'] : key($predefined_languages);
- $form['predefined_langcode'] = array(
- '#type' => 'select',
- '#title' => t('Language name'),
- '#default_value' => $predefined_default,
- '#options' => $predefined_languages,
- );
- $form['predefined_submit'] = array(
- '#type' => 'submit',
- '#value' => t('Add language'),
- '#limit_validation_errors' => array(array('predefined_langcode'), array('predefined_submit')),
- '#states' => array(
- 'invisible' => array(
- 'select#edit-predefined-langcode' => array('value' => 'custom'),
- ),
- ),
- '#validate' => array('locale_languages_add_predefined_form_validate'),
- '#submit' => array('locale_languages_add_predefined_form_submit'),
- );
-
- $form['custom_language'] = array(
- '#type' => 'container',
- '#states' => array(
- 'visible' => array(
- 'select#edit-predefined-langcode' => array('value' => 'custom'),
- ),
- ),
- );
- _locale_languages_common_controls($form['custom_language']);
- $form['custom_language']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Add custom language'),
- '#validate' => array('locale_languages_add_custom_form_validate'),
- '#submit' => array('locale_languages_add_custom_form_submit'),
- );
-
- return $form;
-}
-
-/**
- * Editing screen for a particular language.
- *
- * @param $langcode
- * Language code of the language to edit.
- */
-function locale_languages_edit_form($form, &$form_state, $language) {
- _locale_languages_common_controls($form, $language);
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Save language')
- );
- $form['#submit'][] = 'locale_languages_edit_form_submit';
- $form['#validate'][] = 'locale_languages_edit_form_validate';
- return $form;
-}
-
-/**
- * Common elements of the language addition and editing form.
- *
- * @param $form
- * A parent form item (or empty array) to add items below.
- * @param $language
- * Language object to edit.
- */
-function _locale_languages_common_controls(&$form, $language = NULL) {
- if (!is_object($language)) {
- $language = new stdClass();
- }
- if (isset($language->language)) {
- $form['langcode_view'] = array(
- '#type' => 'item',
- '#title' => t('Language code'),
- '#markup' => $language->language
- );
- $form['langcode'] = array(
- '#type' => 'value',
- '#value' => $language->language
- );
- }
- else {
- $form['langcode'] = array(
- '#type' => 'textfield',
- '#title' => t('Language code'),
- '#maxlength' => 12,
- '#required' => TRUE,
- '#default_value' => @$language->language,
- '#disabled' => (isset($language->language)),
- '#description' => t('Use language codes as defined by the W3C for interoperability. Examples: "en", "en-gb" and "zh-hant".', array('@w3ctags' => 'http://www.w3.org/International/articles/language-tags/')),
- );
- }
- $form['name'] = array(
- '#type' => 'textfield',
- '#title' => t('Language name'),
- '#maxlength' => 64,
- '#default_value' => @$language->name,
- '#required' => TRUE,
- );
- $form['direction'] = array(
- '#type' => 'radios',
- '#title' => t('Direction'),
- '#required' => TRUE,
- '#description' => t('Direction that text in this language is presented.'),
- '#default_value' => @$language->direction,
- '#options' => array(LANGUAGE_LTR => t('Left to right'), LANGUAGE_RTL => t('Right to left'))
- );
- return $form;
-}
-
-/**
- * Element specific validator for the Add language button.
- */
-function locale_languages_add_predefined_form_validate($form, &$form_state) {
- $langcode = $form_state['values']['predefined_langcode'];
- if ($langcode == 'custom') {
- form_set_error('predefined_langcode', t('Fill in the language details and save the language with Add custom language.'));
- }
- else {
- if (language_load($langcode)) {
- form_set_error('predefined_langcode', t('The language %language (%code) already exists.', array('%language' => $languages[$langcode]->name, '%code' => $langcode)));
- }
- }
-}
-
-/**
- * Validate the language addition form on custom language button.
- */
-function locale_languages_add_custom_form_validate($form, &$form_state) {
- if ($form_state['values']['predefined_langcode'] == 'custom') {
- $langcode = $form_state['values']['langcode'];
- // Reuse the editing form validation routine if we add a custom language.
- locale_languages_edit_form_validate($form, $form_state);
-
- $languages = language_list();
- if (isset($languages[$langcode])) {
- form_set_error('langcode', t('The language %language (%code) already exists.', array('%language' => $languages[$langcode]->name, '%code' => $langcode)));
- }
- }
- else {
- form_set_error('predefined_langcode', t('Use the Add language button to save a predefined language.'));
- }
-}
-
-/**
- * Process the custom language addition form submission.
- */
-function locale_languages_add_custom_form_submit($form, &$form_state) {
- $langcode = $form_state['values']['langcode'];
- // Custom language form.
- $language = (object) array(
- 'language' => $langcode,
- 'name' => $form_state['values']['name'],
- 'direction' => $form_state['values']['direction'],
- );
- locale_language_save($language);
- drupal_set_message(t('The language %language has been created and can now be used. More information is available on the help screen.', array('%language' => $form_state['values']['name'], '@locale-help' => url('admin/help/locale'))));
- locale_languages_add_set_batch($langcode);
- $form_state['redirect'] = 'admin/config/regional/language';
-}
-
-/**
- * Process the predefined language addition form submission.
- */
-function locale_languages_add_predefined_form_submit($form, &$form_state) {
- // Predefined language selection.
- $langcode = $form_state['values']['predefined_langcode'];
- include_once DRUPAL_ROOT . '/core/includes/standard.inc';
- $predefined = standard_language_list();
- $language = (object) array(
- 'language' => $langcode,
- );
- locale_language_save($language);
- drupal_set_message(t('The language %language has been created and can now be used. More information is available on the help screen.', array('%language' => t($predefined[$langcode][0]), '@locale-help' => url('admin/help/locale'))));
- locale_languages_add_set_batch($langcode);
- $form_state['redirect'] = 'admin/config/regional/language';
-}
-
-/**
- * Set a batch for newly added language.
- */
-function locale_languages_add_set_batch($langcode) {
- // See if we have language files to import for the newly added
- // language, collect and import them.
- include_once drupal_get_path('module', 'locale') . '/locale.bulk.inc';
- if ($batch = locale_translate_batch_import_files($langcode, TRUE)) {
- batch_set($batch);
- }
-}
-
-/**
- * Validate the language editing form. Reused for custom language addition too.
- */
-function locale_languages_edit_form_validate($form, &$form_state) {
- // Ensure sane field values for langcode and name.
- if (!isset($form['langcode_view']) && preg_match('@[^a-zA-Z_-]@', $form_state['values']['langcode'])) {
- form_set_error('langcode', t('%field may only contain characters a-z, underscores, or hyphens.', array('%field' => $form['langcode']['#title'])));
- }
- if ($form_state['values']['name'] != check_plain($form_state['values']['name'])) {
- form_set_error('name', t('%field cannot contain any markup.', array('%field' => $form['name']['#title'])));
- }
-}
-
-/**
- * Process the language editing form submission.
- */
-function locale_languages_edit_form_submit($form, &$form_state) {
- // Prepare a language object for saving
- $languages = language_list();
- $langcode = $form_state['values']['langcode'];
- $language = $languages[$langcode];
- $language->name = $form_state['values']['name'];
- $language->direction = $form_state['values']['direction'];
- locale_language_save($language);
- $form_state['redirect'] = 'admin/config/regional/language';
-}
-
-/**
- * User interface for the language deletion confirmation screen.
- */
-function locale_languages_delete_form($form, &$form_state, $language) {
- $langcode = $language->language;
-
- if (language_default()->language == $langcode) {
- drupal_set_message(t('The default language cannot be deleted.'));
- drupal_goto('admin/config/regional/language');
- }
-
- // For other languages, warn user that data loss is ahead.
- $languages = language_list();
-
- if (!isset($languages[$langcode])) {
- drupal_not_found();
- drupal_exit();
- }
- else {
- $form['langcode'] = array('#type' => 'value', '#value' => $langcode);
- return confirm_form($form, t('Are you sure you want to delete the language %name?', array('%name' => $languages[$langcode]->name)), 'admin/config/regional/language', t('Deleting a language will remove all interface translations associated with it, and posts in this language will be set to be language neutral. This action cannot be undone.'), t('Delete'), t('Cancel'));
- }
-}
-
-/**
- * Process language deletion submissions.
- */
-function locale_languages_delete_form_submit($form, &$form_state) {
- $langcode = $form_state['values']['langcode'];
- $languages = language_list();
- $language = $languages[$langcode];
-
- $success = locale_language_delete($langcode);
-
- if ($success) {
- $variables = array('%locale' => $language->name);
- drupal_set_message(t('The language %locale has been removed.', $variables));
- }
-
- $form_state['redirect'] = 'admin/config/regional/language';
-}
-
-/**
* Setting for language negotiation options
*/
function locale_languages_configure_form() {
diff --git a/core/modules/locale/locale.bulk.inc b/core/modules/locale/locale.bulk.inc
index 4051674..0a4e779 100644
--- a/core/modules/locale/locale.bulk.inc
+++ b/core/modules/locale/locale.bulk.inc
@@ -10,7 +10,7 @@
/**
* User interface for the translation import screen.
*/
-function locale_translate_import_form($form) {
+function locale_translate_import_form($form, &$form_state) {
// Get all languages, except English
drupal_static_reset('language_list');
$names = locale_language_list('name');
@@ -18,14 +18,15 @@
unset($names['en']);
}
+ form_load_include($form_state, 'inc', 'language', 'language.admin');
if (!count($names)) {
- $languages = _locale_prepare_predefined_list();
+ $languages = language_admin_predefined_list();
$default = key($languages);
}
else {
$languages = array(
t('Already added languages') => $names,
- t('Languages not yet added') => _locale_prepare_predefined_list()
+ t('Languages not yet added') => language_admin_predefined_list()
);
$default = key($names);
}
@@ -75,7 +76,7 @@
$language = (object) array(
'language' => $langcode,
);
- locale_language_save($language);
+ language_save($language);
drupal_set_message(t('The language %language has been created.', array('%language' => t($predefined[$langcode][0]))));
}
@@ -167,6 +168,17 @@
}
/**
+ * Set a batch for newly added language.
+ */
+function locale_translate_add_language_set_batch($langcode) {
+ // See if we have language files to import for the newly added language,
+ // collect and import them.
+ if ($batch = locale_translate_batch_import_files($langcode, TRUE)) {
+ batch_set($batch);
+ }
+}
+
+/**
* Prepare a batch to import all translations.
*
* @param $langcode
diff --git a/core/modules/locale/locale.info b/core/modules/locale/locale.info
index 748d274..28bbd03 100644
--- a/core/modules/locale/locale.info
+++ b/core/modules/locale/locale.info
@@ -1,7 +1,7 @@
name = Locale
-description = Adds language handling functionality and enables the translation of the user interface to languages other than English.
+description = Provides language negotiation functionality and user interface translation to languages other than English.
package = Core
version = VERSION
core = 8.x
+dependencies[] = language
files[] = locale.test
-configure = admin/config/regional/language
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index 4ae03fc..50555ff 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -6,12 +6,30 @@
*/
/**
- * Implements hook_install().
+ * Fill in the path prefixes and domains when enabled.
+ *
+ * Language module might change the list of languages, so we need to sync our
+ * configuration for domains and paths with the current language list. This
+ * should run every time the module is enabled.
*/
-function locale_install() {
- // Add the default language to the database too.
- include_once DRUPAL_ROOT . '/core/includes/locale.inc';
- locale_language_save(language_default());
+function locale_enable() {
+ require_once DRUPAL_ROOT . '/core/includes/locale.inc';
+
+ $languages = language_list();
+ $prefixes_old = locale_language_negotiation_url_prefixes();
+ $domains_old = locale_language_negotiation_url_domains();
+
+ $prefixes = array();
+ $domains = array();
+ foreach ($languages as $langcode => $language) {
+ // Keep the old prefix or fill in based on whether the language is default.
+ $prefixes[$langcode] = empty($prefixes_old[$langcode]) ? (empty($language->default) ? $langcode : '') : $prefixes_old[$langcode];
+ // Keep the old domain or fill in empty value.
+ $domains[$langcode] = empty($domains_old[$langcode]) ? '' : $domains_old[$langcode];
+ }
+
+ locale_language_negotiation_url_prefixes_save($prefixes);
+ locale_language_negotiation_url_domains_save($domains);
}
/**
@@ -35,8 +53,6 @@
}
// Clear variables.
- variable_del('language_default');
- variable_del('language_count');
variable_del('language_types');
variable_del('locale_language_negotiation_url_part');
variable_del('locale_language_negotiation_url_prefixes');
@@ -57,63 +73,17 @@
variable_del("locale_language_providers_weight_$type");
}
- foreach (node_type_get_types() as $type => $content_type) {
- $setting = variable_del("language_content_type_$type");
- }
-
- // Switch back to English: with a $language->language value different from 'en'
- // successive calls of t() might result in calling locale(), which in turn might
- // try to query the unexisting {locales_source} and {locales_target} tables.
- drupal_language_initialize();
-
+ // Remove all node type language variables. Node module might have been
+ // enabled, but may be disabled, so use a wildcard delete.
+ db_delete('variable')
+ ->condition('name', db_like('language_content_type_') . '%', 'LIKE')
+ ->execute();
}
/**
* Implements hook_schema().
*/
function locale_schema() {
- $schema['languages'] = array(
- 'description' => 'List of all available languages in the system.',
- 'fields' => array(
- 'language' => array(
- 'type' => 'varchar',
- 'length' => 12,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => "Language code, e.g. 'de' or 'en-US'.",
- ),
- 'name' => array(
- 'type' => 'varchar',
- 'length' => 64,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'Language name.',
- ),
- 'direction' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'Direction of language (Left-to-Right = 0, Right-to-Left = 1).',
- ),
- 'enabled' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'Enabled flag (1 = Enabled, 0 = Disabled).',
- ),
- 'weight' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'Weight, used in lists of languages.',
- ),
- ),
- 'primary key' => array('language'),
- 'indexes' => array(
- 'list' => array('weight', 'name'),
- ),
- );
-
$schema['locales_source'] = array(
'description' => 'List of English source strings.',
'fields' => array(
@@ -175,7 +145,7 @@
'length' => 12,
'not null' => TRUE,
'default' => '',
- 'description' => 'Language code. References {languages}.language.',
+ 'description' => 'Language code. References {language}.language.',
),
'plid' => array(
'type' => 'int',
@@ -213,46 +183,13 @@
*/
/**
- * Remove the native language name column.
- */
-function locale_update_8000() {
- db_drop_field('languages', 'native');
-}
-
-/**
- * Decouple interface translation related data from language objects.
- */
-function locale_update_8001() {
- // Gather data from existing languages table and save in variables.
- $languages = db_select('languages', 'l')
- ->fields('l')
- ->execute();
- $plurals = array();
- $javascript = array();
- foreach ($languages as $language) {
- $plurals[$language->language] = array(
- 'plurals' => $language->plurals,
- 'formula' => $language->formula,
- );
- $javascript[$language->language] = $language->javascript;
- }
- variable_set('locale_translation_plurals', $plurals);
- variable_set('locale_translation_javascript', $javascript);
-
- // Drop now unneeded columns.
- db_drop_field('languages', 'plurals');
- db_drop_field('languages', 'formula');
- db_drop_field('languages', 'javascript');
-}
-
-/**
* Drop textgroup support.
*
* Update assumes i18n migrated this data before the update happened. Core
* never used textgroups for anything, so it is not our job to find place
* for the data elsewhere.
*/
-function locale_update_8002() {
+function locale_update_8000() {
$subquery = db_select('locales_source', 'ls')
->fields('ls', array('lid'))
->condition('ls.textgroup', 'default', '<>');
@@ -263,37 +200,6 @@
->condition('textgroup', 'default', '<>')
->execute();
db_drop_field('locales_source', 'textgroup');
-}
-
-/**
- * Removes the prefix and domain columns from the language table.
- *
- * Load all prefixes and domains from the languages table, save the values in
- * two new variables. Then remove the prefix and domain columns from the
- * languages table.
- */
-function locale_update_8003() {
-
- // Look up languages directly instead of using language_list().
- $languages = db_select('languages', 'l')
- ->fields('l')
- ->execute();
-
- // Collect all domains and prefixes.
- $prefixes = array();
- $domains = array();
- foreach ($languages as $language) {
- $prefixes[$language->language] = $language->prefix;
- $domains[$language->language] = $language->domain;
- }
-
- // Save the prefix and domain values in a variable.
- variable_set('locale_language_negotiation_url_prefixes', $prefixes);
- variable_set('locale_language_negotiation_url_domains', $domains);
-
- // Remove the prefix and domain columns.
- db_drop_field('languages', 'prefix');
- db_drop_field('languages', 'domain');
}
/**
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 5168a24..0a2e70e 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -38,11 +38,7 @@
return $output;
case 'admin/config/regional/language':
- $output = '
' . t('With multiple languages enabled, interface text can be translated, registered users may select their preferred language, and authors can assign a specific language to content. Download contributed translations from Drupal.org.', array('@translations' => 'http://localize.drupal.org')) . '
' . t('Add a language to be supported by your site. If your desired language is not available, pick Custom language... at the end and provide a language code and other details manually.') . '
';
+ return '
' . t('Interface text can be translated. Download contributed translations from Drupal.org.', array('@translations' => 'http://localize.drupal.org')) . '
';
case 'admin/config/regional/language/configure':
$output = '
' . t("Define how to decide which language is used to display page elements (primarily text provided by Drupal and modules, such as field labels and help text). This decision is made by evaluating a series of detection methods for languages; the first detection method that gets a result will determine which language is used for that type of text. Define the order of evaluation of language detection methods on this page.") . '
';
@@ -76,30 +72,7 @@
* Implements hook_menu().
*/
function locale_menu() {
- // Manage languages
- $items['admin/config/regional/language'] = array(
- 'title' => 'Languages',
- 'description' => 'Configure languages for content and the user interface.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('locale_language_overview_form'),
- 'access arguments' => array('administer languages'),
- 'file' => 'locale.admin.inc',
- 'weight' => -10,
- );
- $items['admin/config/regional/language/overview'] = array(
- 'title' => 'List',
- 'weight' => 0,
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['admin/config/regional/language/add'] = array(
- 'title' => 'Add language',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('locale_languages_add_form'),
- 'access arguments' => array('administer languages'),
- 'weight' => 5,
- 'type' => MENU_LOCAL_ACTION,
- 'file' => 'locale.admin.inc',
- );
+ // Language negotiation.
$items['admin/config/regional/language/configure'] = array(
'title' => 'Detection and selection',
'page callback' => 'drupal_get_form',
@@ -125,22 +98,8 @@
'file' => 'locale.admin.inc',
'type' => MENU_VISIBLE_IN_BREADCRUMB,
);
- $items['admin/config/regional/language/edit/%language'] = array(
- 'title' => 'Edit language',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('locale_languages_edit_form', 5),
- 'access arguments' => array('administer languages'),
- 'file' => 'locale.admin.inc',
- );
- $items['admin/config/regional/language/delete/%language'] = array(
- 'title' => 'Confirm',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('locale_languages_delete_form', 5),
- 'access arguments' => array('administer languages'),
- 'file' => 'locale.admin.inc',
- );
- // Translation functionality
+ // Translation functionality.
$items['admin/config/regional/translate'] = array(
'title' => 'User interface translation',
'description' => 'Translate the built-in user interface.',
@@ -246,27 +205,10 @@
*/
function locale_permission() {
return array(
- 'administer languages' => array(
- 'title' => t('Administer languages'),
- ),
'translate interface' => array(
'title' => t('Translate interface texts'),
),
);
-}
-
-/**
- * Loads a language object from the database.
- *
- * @param $langcode
- * The language code.
- *
- * @return
- * A fully-populated language object or FALSE.
- */
-function language_load($langcode) {
- $languages = language_list();
- return isset($languages[$langcode]) ? $languages[$langcode] : FALSE;
}
/**
@@ -336,7 +278,7 @@
*/
function locale_form_alter(&$form, &$form_state, $form_id) {
// Only alter user forms if there is more than one language.
- if (drupal_multilingual()) {
+ if (language_multilingual()) {
// Display language selector when either creating a user on the admin
// interface or editing a user account.
if ($form_id == 'user_register_form' || $form_id == 'user_profile_form') {
@@ -408,14 +350,6 @@
*/
function locale_theme() {
return array(
- 'locale_language_overview_form_table' => array(
- 'render element' => 'form',
- 'file' => 'locale.admin.inc',
- ),
- 'locale_language_operations' => array(
- 'render element' => 'elements',
- 'file' => 'locale.admin.inc',
- ),
'locale_languages_configure_form' => array(
'render element' => 'form',
),
@@ -608,9 +542,9 @@
}
/**
- * Implements hook_locale_language_insert().
+ * Implements hook_language_insert().
*/
-function locale_locale_language_insert($language) {
+function locale_language_insert($language) {
// Add new language to the list of language prefixes.
$prefixes = locale_language_negotiation_url_prefixes();
$prefixes[$language->language] = (empty($language->default) ? $language->language : '');
@@ -620,12 +554,18 @@
$domains = locale_language_negotiation_url_domains();
$domains[$language->language] = '';
locale_language_negotiation_url_domains_save($domains);
+
+ // @todo move these two cache clears out. See http://drupal.org/node/1293252
+ // Changing the language settings impacts the interface.
+ cache('page')->flush();
+ // Force JavaScript translation file re-creation for the new language.
+ _locale_invalidate_js($language->language);
}
/**
- * Implements hook_locale_language_update().
+ * Implements hook_language_update().
*/
-function locale_locale_language_update($language) {
+function locale_language_update($language) {
// If the language is the default, then ensure that no other languages have
// blank prefix codes.
@@ -639,12 +579,17 @@
locale_language_negotiation_url_prefixes_save($prefixes);
}
+ // @todo move these two cache clears out. See http://drupal.org/node/1293252
+ // Changing the language settings impacts the interface.
+ cache('page')->flush();
+ // Force JavaScript translation file re-creation for the modified language.
+ _locale_invalidate_js($language->language);
}
/**
- * Implements hook_locale_language_delete().
+ * Implements hook_language_delete().
*/
-function locale_locale_language_delete($language) {
+function locale_language_delete($language) {
// Remove language from language prefix list.
$prefixes = locale_language_negotiation_url_prefixes();
unset($prefixes[$language->language]);
@@ -654,6 +599,19 @@
$domains = locale_language_negotiation_url_domains();
unset($domains[$language->language]);
locale_language_negotiation_url_domains_save($domains);
+
+ // Remove translations.
+ db_delete('locales_target')
+ ->condition('language', $language->language)
+ ->execute();
+
+ _locale_invalidate_js($language->language);
+
+ // Changing the language settings impacts the interface:
+ cache('page')->flush();
+
+ // Clearing all locale cache from database
+ cache()->delete('locale:' . $language->language);
}
@@ -676,7 +634,14 @@
*/
function locale($string = NULL, $context = NULL, $langcode = NULL) {
global $language;
- $locale_t = &drupal_static(__FUNCTION__);
+
+ // Use the advanced drupal_static() pattern, since this is called very often.
+ static $drupal_static_fast;
+ if (!isset($drupal_static_fast)) {
+ $drupal_static_fast['locale'] = &drupal_static(__FUNCTION__);
+ }
+ $locale_t = &$drupal_static_fast['locale'];
+
if (!isset($string)) {
// Return all cached strings if no string was specified
@@ -830,51 +795,6 @@
$list[$language->language] = $language->$field;
}
return $list;
-}
-
-/**
- * Delete a language.
- *
- * @param $langcode
- * Language code of the language to be deleted.
- * @return
- * TRUE if language is successfully deleted. Otherwise FALSE.
- */
-function locale_language_delete($langcode) {
- $languages = language_list();
- if (isset($languages[$langcode])) {
- $language = $languages[$langcode];
-
- module_invoke_all('locale_language_delete', $language);
-
- // Remove translations first.
- db_delete('locales_target')
- ->condition('language', $language->language)
- ->execute();
-
- // Remove the language.
- db_delete('languages')
- ->condition('language', $language->language)
- ->execute();
-
- if ($language->enabled) {
- variable_set('language_count', variable_get('language_count', 1) - 1);
- }
-
- drupal_static_reset('language_list');
- _locale_invalidate_js($language->language);
-
- // Changing the language settings impacts the interface:
- cache('page')->flush();
-
- // Clearing all locale cache from database
- cache()->delete('locale:' . $language->language);
-
- $variables = array('%locale' => $language->name);
- watchdog('locale', 'The language %locale has been removed.', $variables);
- return TRUE;
- }
- return FALSE;
}
/**
@@ -1057,7 +977,7 @@
* Displays a language switcher. Only show if we have at least two languages.
*/
function locale_block_view($type) {
- if (drupal_multilingual()) {
+ if (language_multilingual()) {
$path = drupal_is_front_page() ? '' : $_GET['q'];
$links = language_negotiation_get_switch_links($type, $path);
@@ -1079,7 +999,7 @@
*/
function locale_url_outbound_alter(&$path, &$options, $original_path) {
// Only modify internal URLs.
- if (!$options['external'] && drupal_multilingual()) {
+ if (!$options['external'] && language_multilingual()) {
static $drupal_static_fast;
if (!isset($drupal_static_fast)) {
$drupal_static_fast['callbacks'] = &drupal_static(__FUNCTION__);
@@ -1133,9 +1053,9 @@
}
/**
- * Implements hook_form_FORM_ID_alter() for locale_language_overview_form().
+ * Implements hook_form_FORM_ID_alter() for language_admin_overview_form().
*/
-function locale_form_locale_language_overview_form_alter(&$form, &$form_state) {
+function locale_form_language_admin_overview_form_alter(&$form, &$form_state) {
$languages = $form['languages']['#languages'];
$total_strings = db_query("SELECT COUNT(*) FROM {locales_source}")->fetchField();
@@ -1179,23 +1099,46 @@
}
/**
- * Implements hook_form_FORM_ID_alter() for locale_languages_edit_form().
+ * Implements hook_form_FORM_ID_alter() for language_admin_add_form(().
*/
-function locale_form_locale_languages_edit_form_alter(&$form, &$form_state) {
+function locale_form_language_admin_add_form_alter(&$form, &$form_state) {
+ $form['predefined_submit']['#submit'][] = 'locale_form_language_admin_add_form_alter_submit';
+ $form['custom_language']['submit']['#submit'][] = 'locale_form_language_admin_add_form_alter_submit';
+}
+
+/**
+ * Set a batch for newly added language.
+ */
+function locale_form_language_admin_add_form_alter_submit($form, $form_state) {
+ if (empty($form_state['values']['predefined_langcode']) || $form_state['values']['predefined_langcode'] == 'custom') {
+ $langcode = $form_state['values']['langcode'];
+ }
+ else {
+ $langcode = $form_state['values']['predefined_langcode'];
+ }
+
+ include_once drupal_get_path('module', 'locale') . '/locale.bulk.inc';
+ locale_translate_add_language_set_batch($langcode);
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for language_admin_edit_form().
+ */
+function locale_form_language_admin_edit_form_alter(&$form, &$form_state) {
if ($form['langcode']['#type'] == 'value' && $form['langcode']['#value'] == 'en') {
$form['locale_translate_english'] = array(
'#title' => t('Enable interface translation to English'),
'#type' => 'checkbox',
'#default_value' => locale_translate_english(),
);
- $form['#submit'][] = 'locale_form_locale_languages_edit_form_alter_submit';
+ $form['#submit'][] = 'locale_form_language_admin_edit_form_alter_submit';
}
}
/**
* Submission handler to record our custom setting.
*/
-function locale_form_locale_languages_edit_form_alter_submit($form, $form_state) {
+function locale_form_language_admin_edit_form_alter_submit($form, $form_state) {
variable_set('locale_translate_english', $form_state['values']['locale_translate_english']);
}
diff --git a/core/modules/locale/locale.test b/core/modules/locale/locale.test
index 8ff85ed..842b8f5 100644
--- a/core/modules/locale/locale.test
+++ b/core/modules/locale/locale.test
@@ -22,13 +22,13 @@
/**
- * Functional tests for the language configuration forms.
+ * Functional tests for language configuration's effect on negotiation setup.
*/
class LocaleConfigurationTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
- 'name' => 'Language configuration',
- 'description' => 'Adds a new locale and tests changing its status and the default language.',
+ 'name' => 'Language negotiation autoconfiguration',
+ 'description' => 'Adds and configures languages to check negotiation changes.',
'group' => 'Locale',
);
}
@@ -47,6 +47,10 @@
$admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
$this->drupalLogin($admin_user);
+ // Check if the Default English language has no path prefix.
+ $this->drupalGet('admin/config/regional/language/configure/url');
+ $this->assertFieldByXPath('//input[@name="prefix[en]"]', '', t('Default English has no path prefix.'));
+
// Add predefined language.
$edit = array(
'predefined_langcode' => 'fr',
@@ -55,29 +59,19 @@
$this->assertText('fr', t('Language added successfully.'));
$this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
- // Add custom language.
- // Code for the language.
- $langcode = 'xx';
- // The English name for the language.
- $name = $this->randomName(16);
- $edit = array(
- 'predefined_langcode' => 'custom',
- 'langcode' => $langcode,
- 'name' => $name,
- 'direction' => '0',
- );
- $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
- $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
- $this->assertRaw('"edit-site-default-' . $langcode .'"', t('Language code found.'));
- $this->assertText(t($name), t('Test language added.'));
+ // Check if the Default English language has no path prefix.
+ $this->drupalGet('admin/config/regional/language/configure/url');
+ $this->assertFieldByXPath('//input[@name="prefix[en]"]', '', t('Default English has no path prefix.'));
+ // Check if French has a path prefix.
+ $this->drupalGet('admin/config/regional/language/configure/url');
+ $this->assertFieldByXPath('//input[@name="prefix[fr]"]', 'fr', t('French has a path prefix.'));
// Check if we can change the default language.
- $path = 'admin/config/regional/language';
- $this->drupalGet($path);
+ $this->drupalGet('admin/config/regional/language');
$this->assertFieldChecked('edit-site-default-en', t('English is the default language.'));
// Change the default language.
$edit = array(
- 'site_default' => $langcode,
+ 'site_default' => 'fr',
);
$this->drupalPost(NULL, $edit, t('Save configuration'));
$this->assertNoFieldChecked('edit-site-default-en', t('Default language updated.'));
@@ -87,114 +81,10 @@
// language.
$this->drupalGet('admin/config/regional/language/configure/url');
$this->assertFieldByXPath('//input[@name="prefix[en]"]', 'en', t('A valid path prefix has been added to the previous default language.'));
-
- // Ensure we can't delete the default language.
- $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
- $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
- $this->assertText(t('The default language cannot be deleted.'), t('Failed to delete the default language.'));
-
- // Check if we can disable a language.
- $edit = array(
- 'languages[en][enabled]' => FALSE,
- );
- $this->drupalPost($path, $edit, t('Save configuration'));
- $this->assertNoFieldChecked('edit-languages-en-enabled', t('Language disabled.'));
-
- // Set disabled language to be the default and ensure it is re-enabled.
- $edit = array(
- 'site_default' => 'en',
- );
- $this->drupalPost(NULL, $edit, t('Save configuration'));
- $this->assertFieldChecked('edit-languages-en-enabled', t('Default language re-enabled.'));
-
- // Ensure 'edit' link works.
- $this->clickLink(t('edit'));
- $this->assertTitle(t('Edit language | Drupal'), t('Page title is "Edit language".'));
- // Edit a language.
- $name = $this->randomName(16);
- $edit = array(
- 'name' => $name,
- );
- $this->drupalPost('admin/config/regional/language/edit/' . $langcode, $edit, t('Save language'));
- $this->assertRaw($name, t('The language has been updated.'));
- $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
-
- // Ensure 'delete' link works.
- $this->drupalGet('admin/config/regional/language');
- $this->clickLink(t('delete'));
- $this->assertText(t('Are you sure you want to delete the language'), t('"delete" link is correct.'));
- // Delete an enabled language.
- $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
- // First test the 'cancel' link.
- $this->clickLink(t('Cancel'));
- $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
- $this->assertRaw($name, t('The language was not deleted.'));
- // Delete the language for real. This a confirm form, we do not need any
- // fields changed.
- $this->drupalPost('admin/config/regional/language/delete/' . $langcode, array(), t('Delete'));
- // We need raw here because %locale will add HTML.
- $this->assertRaw(t('The language %locale has been removed.', array('%locale' => $name)), t('The test language has been removed.'));
- $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
- // Verify that language is no longer found.
- $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
- $this->assertResponse(404, t('Language no longer found.'));
- // Make sure the "language_count" variable has been updated correctly.
- drupal_static_reset('language_list');
- $enabled = language_list('enabled');
- $this->assertEqual(variable_get('language_count', 1), count($enabled[1]), t('Language count is correct.'));
- // Delete a disabled language.
- // Disable an enabled language.
- $edit = array(
- 'languages[fr][enabled]' => FALSE,
- );
- $this->drupalPost($path, $edit, t('Save configuration'));
- $this->assertNoFieldChecked('edit-languages-fr-enabled', t('French language disabled.'));
- // Get the count of enabled languages.
- drupal_static_reset('language_list');
- $enabled = language_list('enabled');
- // Delete the disabled language.
- $this->drupalPost('admin/config/regional/language/delete/fr', array(), t('Delete'));
- // We need raw here because %locale will add HTML.
- $this->assertRaw(t('The language %locale has been removed.', array('%locale' => 'French')), t('Disabled language has been removed.'));
- $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
- // Verify that language is no longer found.
- $this->drupalGet('admin/config/regional/language/delete/fr');
- $this->assertResponse(404, t('Language no longer found.'));
- // Make sure the "language_count" variable has not changed.
- $this->assertEqual(variable_get('language_count', 1), count($enabled[1]), t('Language count is correct.'));
-
- // Ensure we can delete the English language. Right now English is the only
- // language so we must add a new language and make it the default before
- // deleting English.
- $langcode = 'xx';
- $name = $this->randomName(16);
- $edit = array(
- 'predefined_langcode' => 'custom',
- 'langcode' => $langcode,
- 'name' => $name,
- 'direction' => '0',
- );
- $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
- $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
- $this->assertText($name, t('Name found.'));
-
- // Check if we can change the default language.
- $path = 'admin/config/regional/language';
- $this->drupalGet($path);
- $this->assertFieldChecked('edit-site-default-en', t('English is the default language.'));
- // Change the default language.
- $edit = array(
- 'site_default' => $langcode,
- );
- $this->drupalPost(NULL, $edit, t('Save configuration'));
- $this->assertNoFieldChecked('edit-site-default-en', t('Default language updated.'));
- $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
-
- $this->drupalPost('admin/config/regional/language/delete/en', array(), t('Delete'));
- // We need raw here because %locale will add HTML.
- $this->assertRaw(t('The language %locale has been removed.', array('%locale' => 'English')), t('The English language has been removed.'));
+ // Check if French still has a path prefix.
+ $this->drupalGet('admin/config/regional/language/configure/url');
+ $this->assertFieldByXPath('//input[@name="prefix[fr]"]', 'fr', t('French still has a path prefix.'));
}
-
}
/**
@@ -411,8 +301,9 @@
$path = 'admin/config/regional/language/delete/' . $langcode;
// This a confirm form, we do not need any fields changed.
$this->drupalPost($path, array(), t('Delete'));
- // We need raw here because %locale will add HTML.
- $this->assertRaw(t('The language %locale has been removed.', array('%locale' => $name)), t('The test language has been removed.'));
+ // We need raw here because %language and %langcode will add HTML.
+ $t_args = array('%language' => $name, '%langcode' => $langcode);
+ $this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args), t('The test language has been removed.'));
// Reload to remove $name.
$this->drupalGet($path);
// Verify that language is no longer found.
@@ -1196,7 +1087,7 @@
* Check if the values of the Locale variables are correct after uninstall.
*/
function testUninstallProcess() {
- $locale_module = array('locale');
+ $locale_module = array('locale', 'language');
// Add a new language and optionally set it as default.
require_once DRUPAL_ROOT . '/core/includes/locale.inc';
@@ -1206,7 +1097,7 @@
'name' => 'French',
'default' => $this->language == 'fr',
);
- locale_language_save($language);
+ language_save($language);
// Check the UI language.
drupal_language_initialize();
@@ -2131,11 +2022,11 @@
$language = (object) array(
'language' => $langcode_browser_fallback,
);
- locale_language_save($language);
+ language_save($language);
$language = (object) array(
'language' => $langcode,
);
- locale_language_save($language);
+ language_save($language);
// We will look for this string in the admin/config screen to see if the
// corresponding translated string is shown.
@@ -2288,7 +2179,7 @@
$language = (object) array(
'language' => $langcode_browser_fallback,
);
- locale_language_save($language);
+ language_save($language);
$languages = language_list();
// Enable the path prefix for the default language: this way any unprefixed
@@ -2437,7 +2328,7 @@
'language' => 'it',
'name' => 'Italian',
);
- locale_language_save($language);
+ language_save($language);
// Enable URL language detection and selection.
$edit = array('language[enabled][locale-url]' => '1');
diff --git a/core/modules/locale/tests/locale_test.js b/core/modules/locale/tests/locale_test.js
index 515bb34..0693bca 100644
--- a/core/modules/locale/tests/locale_test.js
+++ b/core/modules/locale/tests/locale_test.js
@@ -29,7 +29,7 @@
(
1,
"Whitespace Call plural",
-"Whitespace Call @count plural",
+"Whitespace Call @count plural"
)
;
diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module
index 1840cec..0b213c4 100644
--- a/core/modules/menu/menu.module
+++ b/core/modules/menu/menu.module
@@ -632,7 +632,7 @@
// menu_parent_options() is goofy and can actually handle either a menu link
// or a node type both as second argument. Pick based on whether there is
// a link already (menu_node_prepare() sets mlid default to 0).
- $options = menu_parent_options(menu_get_menus(), $link['mlid'] ? $link : $type);
+ $options = menu_parent_options(menu_get_menus(), $link['mlid'] ? $link : $type, $type);
// If no possible parent menu items were found, there is nothing to display.
if (empty($options)) {
return;
diff --git a/core/modules/menu/menu.test b/core/modules/menu/menu.test
index 437adc2..5fa27c7 100644
--- a/core/modules/menu/menu.test
+++ b/core/modules/menu/menu.test
@@ -698,6 +698,8 @@
// Assert that it is not possible to set the parent of the first node to itself or the second node.
$this->assertNoOption('edit-menu-parent', 'navigation:'. $item['mlid']);
$this->assertNoOption('edit-menu-parent', 'navigation:'. $child_item['mlid']);
+ // Assert that unallowed Management menu is not available in options.
+ $this->assertNoOption('edit-menu-parent', 'management:0');
}
/**
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 60d1789..c297818 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -579,6 +579,10 @@
* block access, return NODE_ACCESS_IGNORE or simply return nothing.
* Blindly returning FALSE will break other node access modules.
*
+ * Also note that this function isn't called for node listings (e.g., RSS feeds,
+ * the default home page at path 'node', a recent content block, etc.) See
+ * @link node_access Node access rights @endlink for a full explanation.
+ *
* @param object|string $node
* Either a node object or the machine name of the content type on which to
* perform the access check.
@@ -1237,9 +1241,12 @@
/**
* Display a node.
*
- * This is a hook used by node modules. It allows a module to define a
- * custom method of displaying its nodes, usually by displaying extra
- * information particular to that node type.
+ * This hook is invoked only on the module that defines the node's content type
+ * (use hook_node_view() to act on all node views).
+ *
+ * This hook is invoked during node viewing after the node is fully loaded,
+ * so that the node type module can define a custom method for display, or
+ * add to the default display.
*
* @param $node
* The node to be displayed, as returned by node_load().
@@ -1257,8 +1264,6 @@
* hook_node_view_alter(), so if you want to affect the final
* view of the node, you might consider implementing one of these hooks
* instead.
- *
- * For a detailed usage example, see node_example.module.
*
* @ingroup node_api_hooks
*/
diff --git a/core/modules/node/node.info b/core/modules/node/node.info
index 2e410ed..33b5dd2 100644
--- a/core/modules/node/node.info
+++ b/core/modules/node/node.info
@@ -5,7 +5,6 @@
core = 8.x
files[] = node.module
files[] = node.test
-required = TRUE
dependencies[] = entity
configure = admin/structure/types
stylesheets[all][] = node.css
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index a6d0b7a..d4e8cd0 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -33,7 +33,7 @@
'default' => '',
),
'language' => array(
- 'description' => 'The {languages}.language of this node.',
+ 'description' => 'The {language}.language of this node.',
'type' => 'varchar',
'length' => 12,
'not null' => TRUE,
@@ -444,6 +444,38 @@
}
/**
+ * Implements hook_uninstall().
+ */
+function node_uninstall() {
+ // Delete node type variables.
+ $types = db_query('SELECT type FROM {node_type}')->fetchCol();
+ foreach ($types as $type) {
+ db_delete('variable')
+ ->condition(db_or()
+ ->condition('name', 'node_preview_' . $type)
+ ->condition('name', 'node_options_' . $type)
+ ->condition('name', 'node_submitted_' . $type)
+ ->condition('name', 'node_permissions_' . $type)
+ )
+ ->execute();
+ }
+
+ // Delete node search ranking variables.
+ // @see node_ranking(), _node_rankings()
+ variable_del('node_rank_relevance');
+ variable_del('node_rank_sticky');
+ variable_del('node_rank_promote');
+ variable_del('node_rank_recent');
+
+ // Delete remaining general module variables.
+ variable_del('node_access_needs_rebuild');
+ variable_del('node_admin_theme');
+ variable_del('node_cron_last');
+ variable_del('node_recent_block_count');
+ variable_del('default_nodes_main');
+}
+
+/**
* Fetches node types directly from the database.
*
* @ingroup update-api-7.x-to-8.x
@@ -469,3 +501,30 @@
}
return $node_types;
}
+
+/**
+ * @addtogroup updates-7.x-to-8.x
+ * @{
+ */
+
+/**
+ * Set 'node' as front page path if it implicitly was before.
+ *
+ * Node module became optional. The default front page path was changed to
+ * 'user'. Since 'node' was the implicit default front page path previously and
+ * may not have been explicitly configured as such, this update ensures that the
+ * old implicit default is still the default.
+ *
+ * @see http://drupal.org/node/375397
+ */
+function node_update_8000() {
+ $front_page = variable_get('site_frontpage');
+ if (!isset($front_page)) {
+ variable_set('site_frontpage', 'node');
+ }
+}
+
+/**
+ * @} End of "addtogroup updates-7.x-to-8.x"
+ * The next series of updates should start at 9000.
+ */
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 2a6aaa3..6da41c2 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -228,6 +228,7 @@
// Bundles must provide a human readable name so we can create help and error
// messages, and the path to attach Field admin pages to.
+ node_type_cache_reset();
foreach (node_type_get_names() as $type => $name) {
$return['node']['bundles'][$type] = array(
'label' => $name,
@@ -2895,6 +2896,31 @@
}
/**
+ * Implements hook_form_FORM_ID_alter().
+ *
+ * Alters the theme form to use the admin theme on node editing.
+ *
+ * @see node_form_system_themes_admin_form_submit()
+ */
+function node_form_system_themes_admin_form_alter(&$form, &$form_state, $form_id) {
+ $form['admin_theme']['node_admin_theme'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use the administration theme when editing or creating content'),
+ '#default_value' => variable_get('node_admin_theme', '0'),
+ );
+ $form['#submit'][] = 'node_form_system_themes_admin_form_submit';
+}
+
+/**
+ * Form submission handler for system_themes_admin_form().
+ *
+ * @see node_form_system_themes_admin_form_alter()
+ */
+function node_form_system_themes_admin_form_submit($form, &$form_state) {
+ variable_set('node_admin_theme', $form_state['values']['node_admin_theme']);
+}
+
+/**
* @defgroup node_access Node access rights
* @{
* The node access system determines who can do what to which nodes.
@@ -2918,13 +2944,14 @@
* that this table is a list of grants; any matching row is sufficient to
* grant access to the node.
*
- * In node listings, the process above is followed except that
- * hook_node_access() is not called on each node for performance reasons and for
- * proper functioning of the pager system. When adding a node listing to your
- * module, be sure to use a dynamic query created by db_select() and add a tag
- * of "node_access". This will allow modules dealing with node access to ensure
- * only nodes to which the user has access are retrieved, through the use of
- * hook_query_TAG_alter().
+ * In node listings (lists of nodes generated from a select query, such as the
+ * default home page at path 'node', an RSS feed, a recent content block, etc.),
+ * the process above is followed except that hook_node_access() is not called on
+ * each node for performance reasons and for proper functioning of the pager
+ * system. When adding a node listing to your module, be sure to use a dynamic
+ * query created by db_select() and add a tag of "node_access". This will allow
+ * modules dealing with node access to ensure only nodes to which the user has
+ * access are retrieved, through the use of hook_query_TAG_alter().
*
* Note: Even a single module returning NODE_ACCESS_DENY from hook_node_access()
* will block access to the node. Therefore, implementers should take care to
@@ -4079,6 +4106,28 @@
}
/**
+ * Implements hook_modules_disabled().
+ */
+function node_modules_disabled($modules) {
+ // Check whether any of the disabled modules implemented hook_node_grants(),
+ // in which case the node access table needs to be rebuilt.
+ foreach ($modules as $module) {
+ // At this point, the module is already disabled, but its code is still
+ // loaded in memory. Module functions must no longer be called. We only
+ // check whether a hook implementation function exists and do not invoke it.
+ if (!node_access_needs_rebuild() && module_hook($module, 'node_grants')) {
+ node_access_needs_rebuild(TRUE);
+ }
+ }
+
+ // If there remains no more node_access module, rebuilding will be
+ // straightforward, we can do it right now.
+ if (node_access_needs_rebuild() && count(module_implements('node_grants')) == 0) {
+ node_access_rebuild();
+ }
+}
+
+/**
* Controller class for nodes.
*
* This extends the DrupalDefaultEntityController class, adding required
@@ -4137,9 +4186,9 @@
}
/**
- * Implements hook_locale_language_delete().
+ * Implements hook_language_delete().
*/
-function node_locale_language_delete($language) {
+function node_language_delete($language) {
// On nodes with this language, unset the language
db_update('node')
->fields(array('language' => ''))
diff --git a/core/modules/node/node.test b/core/modules/node/node.test
index a04b0e6..2e9b075 100644
--- a/core/modules/node/node.test
+++ b/core/modules/node/node.test
@@ -1732,7 +1732,7 @@
// Test breadcrumb in comment preview.
$this->drupalGet("comment/reply/$node->nid");
- $xpath = '//div[@class="breadcrumb"]/a[last()]';
+ $xpath = '//nav[@class="breadcrumb"]/ol/li[last()]/a';
$this->assertEqual(current($this->xpath($xpath)), $node->title, 'Node breadcrumb is equal to node title.', 'Node');
// Test node title in comment preview.
diff --git a/core/modules/openid/openid.api.php b/core/modules/openid/openid.api.php
index 5e3d15d..bd286ff 100644
--- a/core/modules/openid/openid.api.php
+++ b/core/modules/openid/openid.api.php
@@ -13,21 +13,15 @@
/**
* Allow modules to modify the OpenID request parameters.
*
- * @param $op
- * The operation to be performed.
- * Possible values:
- * - request: Modify parameters before they are sent to the OpenID provider.
* @param $request
- * An associative array of parameter defaults to which to modify or append.
- * @return
- * An associative array of parameters to be merged with the default list.
- *
+ * An associative array of request parameters.
+ * @param $service
+ * A service array as returned by openid_discovery().
*/
-function hook_openid($op, $request) {
- if ($op == 'request') {
+function hook_openid_request_alter(&$request, $service) {
+ if ($request['openid.mode'] == 'checkid_setup') {
$request['openid.identity'] = 'http://myname.myopenid.com/';
}
- return $request;
}
/**
diff --git a/core/modules/openid/openid.inc b/core/modules/openid/openid.inc
index a0549ee..f38b22e 100644
--- a/core/modules/openid/openid.inc
+++ b/core/modules/openid/openid.inc
@@ -25,11 +25,6 @@
const OPENID_DH_DEFAULT_GEN = '2';
/**
- * SHA-1 hash block size; used for Diffie-Hellman key exchange computations.
- */
-const OPENID_SHA1_BLOCKSIZE = 64;
-
-/**
* Random number generator; used for Diffie-Hellman key exchange computations.
*/
const OPENID_RAND_SOURCE = '/dev/urandom';
@@ -414,23 +409,9 @@
$message = _openid_create_message($sign_data);
$secret = base64_decode($association->mac_key);
- $signature = _openid_hmac($secret, $message);
+ $signature = hash_hmac('sha1', $message, $secret, TRUE);
return base64_encode($signature);
-}
-
-function _openid_hmac($key, $text) {
- if (strlen($key) > OPENID_SHA1_BLOCKSIZE) {
- $key = sha1($key, TRUE);
- }
-
- $key = str_pad($key, OPENID_SHA1_BLOCKSIZE, chr(0x00));
- $ipad = str_repeat(chr(0x36), OPENID_SHA1_BLOCKSIZE);
- $opad = str_repeat(chr(0x5c), OPENID_SHA1_BLOCKSIZE);
- $hash1 = sha1(($key ^ $ipad) . $text, TRUE);
- $hmac = sha1(($key ^ $opad) . $hash1, TRUE);
-
- return $hmac;
}
function _openid_dh_base64_to_long($str) {
diff --git a/core/modules/openid/openid.module b/core/modules/openid/openid.module
index ed02891..433ffee 100644
--- a/core/modules/openid/openid.module
+++ b/core/modules/openid/openid.module
@@ -218,6 +218,58 @@
$form['account']['pass']['#value'] = user_password();
}
+ $timezone = FALSE;
+ if (!empty($sreg_values['timezone'])) {
+ $timezone = $sreg_values['timezone'];
+ }
+ elseif ($ax_timezone_values = openid_extract_ax_values($ax_values, array('http://axschema.org/pref/timezone', 'http://openid.net/schema/timezone'))) {
+ $timezone = current($ax_timezone_values);
+ }
+ if (in_array($timezone, timezone_identifiers_list())) {
+ $form['#user']->timezone = $timezone;
+ }
+
+ $language = FALSE;
+ if (!empty($sreg_values['language'])) {
+ $language = $sreg_values['language'];
+ }
+ elseif ($ax_language_values = openid_extract_ax_values($ax_values, array('http://axschema.org/pref/language', 'http://openid.net/schema/language/pref'))) {
+ $language = current($ax_language_values);
+ }
+ if ($language) {
+ // The OpenID Simple Registration Extension specification is unclear about
+ // the format of openid.sreg.language. Codes like "EN" and "ZH_CN" have
+ // been observed.
+ // AX values are in RFC 4646 format, e.g. "de", "en-GB", "en-Latn-GB",
+ // "zh-Hans", or "zh-Hans-CN". The first part is the language, the second
+ // is the script, and the third is the region. Other parts are also
+ // defined, but we will not use them here. All parts except the first are
+ // optional.
+ // We generate a list of all permutations of the first three parts and
+ // match them against the list of enabled languages. E.g. if the user's
+ // preferred langugage is "en-GB", we look for "en-gb" (Drupal's language
+ // codes are lower-case) or fall back to "en".
+ $parts = preg_split('/[_-]/', strtolower($language));
+ $candidate_languages[] = $parts[0];
+ if (count($parts) > 1) {
+ $candidate_languages[] = $parts[0] . '-' . $parts[1];
+ }
+ if (count($parts) > 2) {
+ $candidate_languages[] = $parts[0] . '-' . $parts[2];
+ $candidate_languages[] = $parts[0] . '-' . $parts[1] . '-' . $parts[2];
+ }
+ $all_languages = language_list('enabled');
+ $enabled_languages = $all_languages[1];
+ // Iterate over the generated permutations starting with the longest (most
+ // specific) strings.
+ foreach (array_reverse($candidate_languages) as $candidate_language) {
+ if (isset($enabled_languages[$candidate_language])) {
+ $form['locale']['language']['#type'] = 'hidden';
+ $form['locale']['language']['#value'] = $candidate_language;
+ }
+ }
+ }
+
$form['openid_claimed_id'] = array(
'#type' => 'value',
'#default_value' => $response['openid.claimed_id'],
@@ -657,13 +709,13 @@
// Load global $user and perform final login tasks.
$form_state['uid'] = $account->uid;
user_login_submit(array(), $form_state);
- // Let other modules act on OpenID login
- module_invoke_all('openid_response', $response, $account);
}
}
else {
drupal_set_message(t('You must validate your email address for this account before logging in via OpenID.'));
}
+ // Let other modules act on OpenID login
+ module_invoke_all('openid_response', $response, $account);
}
elseif (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)) {
// Register new user.
@@ -675,7 +727,10 @@
$form_state['values']['op'] = t('Create new account');
drupal_form_submit('user_register_form', $form_state);
- if (!empty($form_state['user'])) {
+ if (empty($form_state['user'])) {
+ module_invoke_all('openid_response', $response, NULL);
+ }
+ else {
module_invoke_all('openid_response', $response, $form_state['user']);
drupal_goto();
}
@@ -703,6 +758,7 @@
}
else {
drupal_set_message(t('Only site administrators can create new user accounts.'), 'error');
+ module_invoke_all('openid_response', $response, NULL);
}
drupal_goto();
}
@@ -750,6 +806,7 @@
// that the Endpoint advertise OPENID_NS_SREG in the service description.
$request['openid.ns.sreg'] = OPENID_NS_SREG;
$request['openid.sreg.required'] = 'nickname,email';
+ $request['openid.sreg.optional'] = 'timezone,language';
// Request Attribute Exchange, if available.
// We only request the minimum attributes we need here, contributed modules
@@ -758,6 +815,7 @@
$request['openid.ns.ax'] = OPENID_NS_AX;
$request['openid.ax.mode'] = 'fetch_request';
$request['openid.ax.required'] = 'mail_ao,name_ao,mail_son,name_son';
+ $request['openid.ax.if_available'] = 'timezone_ao,language_ao,timezone_son,language_son';
// Implementors disagree on which URIs to use, even for simple
// attributes like name and email (*sigh*). We ask for both axschema.org
@@ -767,13 +825,17 @@
// Attributes as defined by axschema.org.
$request['openid.ax.type.mail_ao'] = 'http://axschema.org/contact/email';
$request['openid.ax.type.name_ao'] = 'http://axschema.org/namePerson/friendly';
+ $request['openid.ax.type.timezone_ao'] = 'http://axschema.org/pref/timezone';
+ $request['openid.ax.type.language_ao'] = 'http://axschema.org/pref/language';
// Attributes as defined by schema.openid.net.
$request['openid.ax.type.mail_son'] = 'http://schema.openid.net/contact/email';
$request['openid.ax.type.name_son'] = 'http://schema.openid.net/namePerson/friendly';
+ $request['openid.ax.type.timezone_son'] = 'http://openid.net/schema/timezone';
+ $request['openid.ax.type.language_son'] = 'http://openid.net/schema/language/pref';
}
- $request = array_merge($request, module_invoke_all('openid', 'request', $request));
+ drupal_alter('openid_request', $request, $service);
return $request;
}
diff --git a/core/modules/openid/openid.pages.inc b/core/modules/openid/openid.pages.inc
index 6e3f096..dcdb3e9 100644
--- a/core/modules/openid/openid.pages.inc
+++ b/core/modules/openid/openid.pages.inc
@@ -31,9 +31,9 @@
drupal_add_css(drupal_get_path('module', 'openid') . '/openid.css');
// Check to see if we got a response
- $result = openid_complete();
- if ($result['status'] == 'success') {
- $identity = $result['openid.claimed_id'];
+ $response = openid_complete();
+ if ($response['status'] == 'success') {
+ $identity = $response['openid.claimed_id'];
$query = db_insert('authmap')
->fields(array(
'uid' => $account->uid,
@@ -42,6 +42,8 @@
))
->execute();
drupal_set_message(t('Successfully added %identity', array('%identity' => $identity)));
+ // Let other modules act on OpenID authentication.
+ module_invoke_all('openid_response', $response, $account);
}
$header = array(t('OpenID'), t('Operations'));
diff --git a/core/modules/openid/openid.test b/core/modules/openid/openid.test
index d873c32..5c6ca69 100644
--- a/core/modules/openid/openid.test
+++ b/core/modules/openid/openid.test
@@ -78,13 +78,13 @@
// the URL of the OpenID Provider Endpoint.
// Identifier is the URL of an XRDS document.
- // The URL scheme is stripped in order to test that the supplied identifier
- // is normalized in openid_begin().
+ // On HTTP test environments, the URL scheme is stripped in order to test
+ // that the supplied identifier is normalized in openid_begin().
$identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
- $this->addIdentity(preg_replace('@^https?://@', '', $identity), 2, 'http://example.com/xrds', $identity);
+ $this->addIdentity(preg_replace('@^http://@', '', $identity), 2, 'http://example.com/xrds', $identity);
$identity = url('openid-test/yadis/xrds/delegate', array('absolute' => TRUE));
- $this->addIdentity(preg_replace('@^https?://@', '', $identity), 2, 'http://example.com/xrds-delegate', $identity);
+ $this->addIdentity(preg_replace('@^http://@', '', $identity), 2, 'http://example.com/xrds-delegate', $identity);
// Identifier is the URL of an XRDS document containing an OP Identifier
// Element. The Relying Party sends the special value
@@ -92,8 +92,8 @@
// Identifier. The OpenID Provider responds with the actual identifier
// including the fragment.
$identity = url('openid-test/yadis/xrds/dummy-user', array('absolute' => TRUE, 'fragment' => $this->randomName()));
- // Tell openid_test.module to respond with this identifier. We test if
- // openid_complete() processes it right.
+ // Tell openid_test.module to respond with this identifier. If the fragment
+ // part is present in the identifier, it should be retained.
variable_set('openid_test_response', array('openid.claimed_id' => $identity));
$this->addIdentity(url('openid-test/yadis/xrds/server', array('absolute' => TRUE)), 2, 'http://specs.openid.net/auth/2.0/identifier_select', $identity);
variable_set('openid_test_response', array());
@@ -157,12 +157,22 @@
// Use a User-supplied Identity that is the URL of an XRDS document.
$identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
$this->addIdentity($identity);
+ $response = variable_get('openid_test_hook_openid_response_response');
+ $account = variable_get('openid_test_hook_openid_response_account');
+ $this->assertEqual($response['openid.claimed_id'], $identity, t('hook_openid_response() was invoked.'));
+ $this->assertEqual($account->uid, $this->web_user->uid, t('Proper user object passed to hook_openid_response().'));
$this->drupalLogout();
// Test logging in via the login block on the front page.
+ variable_del('openid_test_hook_openid_response_response');
+ variable_del('openid_test_hook_openid_response_account');
$this->submitLoginForm($identity);
$this->assertLink(t('Log out'), 0, t('User was logged in.'));
+ $response = variable_get('openid_test_hook_openid_response_response');
+ $account = variable_get('openid_test_hook_openid_response_account');
+ $this->assertEqual($response['openid.claimed_id'], $identity, t('hook_openid_response() was invoked.'));
+ $this->assertEqual($account->uid, $this->web_user->uid, t('Proper user object passed to hook_openid_response().'));
$this->drupalLogout();
@@ -180,6 +190,17 @@
// Verify user was redirected away from user/login to an accessible page.
$this->assertResponse(200);
+
+ $this->drupalLogout();
+
+ // Tell openid_test.module to alter the checkid_setup request.
+ $new_identity = 'http://example.com/' . $this->randomName();
+ variable_set('openid_test_identity', $new_identity);
+ variable_set('openid_test_request_alter', array('checkid_setup' => array('openid.identity' => $new_identity)));
+ $this->submitLoginForm($identity);
+ $this->assertLink(t('Log out'), 0, t('User was logged in.'));
+ $response = variable_get('openid_test_hook_openid_response_response');
+ $this->assertEqual($response['openid.identity'], $new_identity, t('hook_openid_request_alter() were invoked.'));
}
/**
@@ -378,9 +399,16 @@
*/
function testRegisterUserWithEmailVerification() {
variable_set('user_email_verification', TRUE);
+ variable_get('configurable_timezones', 1);
+ variable_set('date_default_timezone', 'Europe/Brussels');
// Tell openid_test.module to respond with these SREG fields.
- variable_set('openid_test_response', array('openid.sreg.nickname' => 'john', 'openid.sreg.email' => 'john@example.com'));
+ variable_set('openid_test_response', array(
+ 'openid.sreg.nickname' => 'john',
+ 'openid.sreg.email' => 'john@example.com',
+ 'openid.sreg.language' => 'en-GB',
+ 'openid.sreg.timezone' => 'Europe/London',
+ ));
// Use a User-supplied Identity that is the URL of an XRDS document.
$identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
@@ -392,6 +420,8 @@
$user = user_load_by_name('john');
$this->assertTrue($user, t('User was registered with right username.'));
$this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
+ $this->assertEqual($user->timezone, 'Europe/London', t('User was registered with right timezone.'));
+ $this->assertEqual($user->language, 'en', t('User was registered with right language.'));
$this->assertFalse($user->data, t('No additional user info was saved.'));
$this->submitLoginForm($identity);
@@ -413,9 +443,16 @@
*/
function testRegisterUserWithoutEmailVerification() {
variable_set('user_email_verification', FALSE);
+ variable_get('configurable_timezones', 1);
+ variable_set('date_default_timezone', 'Europe/Brussels');
// Tell openid_test.module to respond with these SREG fields.
- variable_set('openid_test_response', array('openid.sreg.nickname' => 'john', 'openid.sreg.email' => 'john@example.com'));
+ variable_set('openid_test_response', array(
+ 'openid.sreg.nickname' => 'john',
+ 'openid.sreg.email' => 'john@example.com',
+ 'openid.sreg.language' => 'en-GB',
+ 'openid.sreg.timezone' => 'Europe/London',
+ ));
// Use a User-supplied Identity that is the URL of an XRDS document.
$identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
@@ -425,6 +462,8 @@
$user = user_load_by_name('john');
$this->assertTrue($user, t('User was registered with right username.'));
$this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
+ $this->assertEqual($user->timezone, 'Europe/London', t('User was registered with right timezone.'));
+ $this->assertEqual($user->language, 'en', t('User was registered with right language.'));
$this->assertFalse($user->data, t('No additional user info was saved.'));
$this->drupalLogout();
@@ -438,9 +477,17 @@
* information (a username that is already taken, and no e-mail address).
*/
function testRegisterUserWithInvalidSreg() {
+ variable_get('configurable_timezones', 1);
+ variable_set('date_default_timezone', 'Europe/Brussels');
+
// Tell openid_test.module to respond with these SREG fields.
$web_user = $this->drupalCreateUser(array());
- variable_set('openid_test_response', array('openid.sreg.nickname' => $web_user->name, 'openid.sreg.email' => 'mail@invalid#'));
+ variable_set('openid_test_response', array(
+ 'openid.sreg.nickname' => $web_user->name,
+ 'openid.sreg.email' => 'mail@invalid#',
+ 'openid.sreg.timezone' => 'Foo/Bar',
+ 'openid.sreg.language' => 'foobar',
+ ));
// Use a User-supplied Identity that is the URL of an XRDS document.
$identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
@@ -449,8 +496,11 @@
$this->assertRaw(t('Account registration using the information provided by your OpenID provider failed due to the reasons listed below. Complete the registration by filling out the form below. If you already have an account, you can log in now and add your OpenID under "My account".', array('@login' => url('user/login'))), t('User was asked to complete the registration process manually.'));
$this->assertRaw(t('The name %name is already taken.', array('%name' => $web_user->name)), t('Form validation error for username was displayed.'));
$this->assertRaw(t('The e-mail address %mail is not valid.', array('%mail' => 'mail@invalid#')), t('Form validation error for e-mail address was displayed.'));
+ $this->assertTrue(variable_get('openid_test_hook_openid_response_response'), t('hook_openid_response() was invoked.'));
+ $this->assertFalse(variable_get('openid_test_hook_openid_response_account', TRUE), t('No user object passed to hook_openid_response().'));
// Enter username and e-mail address manually.
+ variable_del('openid_test_hook_openid_response_response');
$edit = array('name' => 'john', 'mail' => 'john@example.com');
$this->drupalPost(NULL, $edit, t('Create new account'));
$this->assertRaw(t('Once you have verified your e-mail address, you may log in via OpenID.'), t('User was asked to verify e-mail address.'));
@@ -458,11 +508,13 @@
$user = user_load_by_name('john');
$this->assertTrue($user, t('User was registered with right username.'));
+ $this->assertFalse($user->language, t('No user language was saved.'));
$this->assertFalse($user->data, t('No additional user info was saved.'));
// Follow the one-time login that was sent in the welcome e-mail.
$this->drupalGet($reset_url);
$this->drupalPost(NULL, array(), t('Log in'));
+ $this->assertFalse(variable_get('openid_test_hook_openid_response_response'), t('hook_openid_response() was not invoked.'));
// The user is taken to user/%uid/edit.
$this->assertFieldByName('mail', 'john@example.com', t('User was registered with right e-mail address.'));
@@ -476,6 +528,8 @@
* information (i.e. no username or e-mail address).
*/
function testRegisterUserWithoutSreg() {
+ variable_get('configurable_timezones', 1);
+
// Load the front page to get the user login block.
$this->drupalGet('');
@@ -494,6 +548,7 @@
$user = user_load_by_name('john');
$this->assertTrue($user, t('User was registered with right username.'));
+ $this->assertFalse($user->language, t('No user language was saved.'));
$this->assertFalse($user->data, t('No additional user info was saved.'));
// Follow the one-time login that was sent in the welcome e-mail.
@@ -513,6 +568,7 @@
*/
function testRegisterUserWithAXButNoSREG() {
variable_set('user_email_verification', FALSE);
+ variable_set('date_default_timezone', 'Europe/Brussels');
// Tell openid_test.module to respond with these AX fields.
variable_set('openid_test_response', array(
@@ -522,6 +578,10 @@
'openid.ext123.type.name789' => 'http://schema.openid.net/namePerson/friendly',
'openid.ext123.count.name789' => '1',
'openid.ext123.value.name789.1' => 'john',
+ 'openid.ext123.type.timezone' => 'http://axschema.org/pref/timezone',
+ 'openid.ext123.value.timezone' => 'Europe/London',
+ 'openid.ext123.type.language' => 'http://axschema.org/pref/language',
+ 'openid.ext123.value.language' => 'en-GB',
));
// Use a User-supplied Identity that is the URL of an XRDS document.
@@ -532,6 +592,8 @@
$user = user_load_by_name('john');
$this->assertTrue($user, t('User was registered with right username.'));
$this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
+ $this->assertEqual($user->timezone, 'Europe/London', t('User was registered with right timezone.'));
+ $this->assertEqual($user->language, 'en', t('User was registered with right language.'));
}
}
diff --git a/core/modules/openid/tests/openid_test.module b/core/modules/openid/tests/openid_test.module
index 629dcd3..8b37d47 100644
--- a/core/modules/openid/tests/openid_test.module
+++ b/core/modules/openid/tests/openid_test.module
@@ -350,3 +350,21 @@
drupal_add_http_header('Content-Type', 'text/plain');
header('Location: ' . url($_REQUEST['openid_return_to'], array('query' => $response, 'external' => TRUE)));
}
+
+/**
+ * Implements hook_openid_request_alter().
+ */
+function openid_test_openid_request_alter(&$request, $service) {
+ $parameters = variable_get('openid_test_request_alter', array());
+ if (isset($parameters[$request['openid.mode']])) {
+ $request = $parameters[$request['openid.mode']] + $request;
+ }
+}
+
+/**
+ * Implements hook_openid_response().
+ */
+function openid_test_openid_response($response, $account) {
+ variable_set('openid_test_hook_openid_response_response', $response);
+ variable_set('openid_test_hook_openid_response_account', $account ? $account : FALSE);
+}
diff --git a/core/modules/overlay/overlay-parent.js b/core/modules/overlay/overlay-parent.js
index 135320f..d1fc4ca 100644
--- a/core/modules/overlay/overlay-parent.js
+++ b/core/modules/overlay/overlay-parent.js
@@ -334,7 +334,7 @@
$placeholder.one('blur', function () {
$(this).remove();
});
-}
+};
/**
* Check if the given link is in the administrative section of the site.
@@ -961,7 +961,7 @@
var $element = $(this);
var tabindex = $(this).attr('tabindex');
$element.data('drupalOverlayOriginalTabIndex', tabindex);
-}
+};
/**
* Restore an element's original tabindex.
diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index 5433d3e..8f62c01 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -635,7 +635,7 @@
// Let the client side know which paths are administrative.
$paths = path_get_admin_paths();
foreach ($paths as &$type) {
- $type = str_replace('', variable_get('site_frontpage', 'node'), $type);
+ $type = str_replace('', variable_get('site_frontpage', 'user'), $type);
}
drupal_add_js(array('overlay' => array('paths' => $paths)), 'setting');
// Pass along the Ajax callback for rerendering sections of the parent window.
diff --git a/core/modules/path/path.test b/core/modules/path/path.test
index 8f0406e..a3e1562 100644
--- a/core/modules/path/path.test
+++ b/core/modules/path/path.test
@@ -476,7 +476,7 @@
$this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
// Verify that French is the only language.
- $this->assertFalse(drupal_multilingual(), t('Site is mono-lingual'));
+ $this->assertFalse(language_multilingual(), t('Site is mono-lingual'));
$this->assertEqual(language_default()->language, 'fr', t('French is the default language'));
// Set language detection to URL.
diff --git a/core/modules/php/php.module b/core/modules/php/php.module
index 37bf9a1..4c68abe 100644
--- a/core/modules/php/php.module
+++ b/core/modules/php/php.module
@@ -36,23 +36,26 @@
}
/**
- * Evaluate a string of PHP code.
+ * Implements hook_filter_FILTER_process().
*
- * This is a wrapper around PHP's eval(). It uses output buffering to capture both
- * returned and printed text. Unlike eval(), we require code to be surrounded by
- * tags; in other words, we evaluate the code as if it were a stand-alone
- * PHP file.
+ * This is a wrapper around PHP's eval(). It uses output buffering to capture
+ * both returned and printed text. Unlike eval(), we require code to be
+ * surrounded by tags; in other words, we evaluate the code as if it
+ * were a stand-alone PHP file.
*
* Using this wrapper also ensures that the PHP code which is evaluated can not
* overwrite any variables in the calling code, unlike a regular eval() call.
*
* @param $code
* The code to evaluate.
+ *
* @return
- * A string containing the printed output of the code, followed by the returned
- * output of the code.
+ * A string containing the printed output of the code, followed by the
+ * returned output of the code.
*
* @ingroup php_wrappers
+ *
+ * @see php_filter_info()
*/
function php_eval($code) {
global $theme_path, $theme_info, $conf;
@@ -82,7 +85,9 @@
}
/**
- * Tips callback for php filter.
+ * Implements hook_filter_FILTER_tips().
+ *
+ * @see php_filter_info()
*/
function _php_filter_tips($filter, $format, $long = FALSE) {
global $base_url;
@@ -137,4 +142,3 @@
);
return $filters;
}
-
diff --git a/core/modules/php/php.test b/core/modules/php/php.test
index 8ead2ac..50fb552 100644
--- a/core/modules/php/php.test
+++ b/core/modules/php/php.test
@@ -6,7 +6,7 @@
*/
/**
- * Base PHP test case class.
+ * Defines a base PHP test case class.
*/
class PHPTestCase extends DrupalWebTestCase {
protected $php_code_format;
@@ -38,7 +38,7 @@
}
/**
- * Create a test node with PHP code in the body.
+ * Creates a test node with PHP code in the body.
*
* @return stdObject Node object.
*/
@@ -60,7 +60,7 @@
}
/**
- * Make sure that the PHP filter evaluates PHP code when used.
+ * Makes sure that the PHP filter evaluates PHP code when used.
*/
function testPHPFilter() {
// Log in as a user with permission to use the PHP code text format.
@@ -101,7 +101,7 @@
}
/**
- * Make sure that user can't use the PHP filter when not given access.
+ * Makes sure that the user can't use the PHP filter when not given access.
*/
function testNoPrivileges() {
// Create node with PHP filter enabled.
diff --git a/core/modules/poll/poll.info b/core/modules/poll/poll.info
index de6ac25..dbdd621 100644
--- a/core/modules/poll/poll.info
+++ b/core/modules/poll/poll.info
@@ -3,5 +3,6 @@
package = Core
version = VERSION
core = 8.x
+dependencies[] = node
files[] = poll.test
stylesheets[all][] = poll.css
diff --git a/core/modules/poll/poll.module b/core/modules/poll/poll.module
index 7fe34e4..c4adcf5 100644
--- a/core/modules/poll/poll.module
+++ b/core/modules/poll/poll.module
@@ -288,9 +288,10 @@
// Add initial or additional choices.
$existing_delta = $delta;
- $weight++;
for ($delta; $delta < $choice_count; $delta++) {
$key = 'new:' . ($delta - $existing_delta);
+ // Increase the weight of each new choice.
+ $weight++;
$form['choice_wrapper']['choice'][$key] = _poll_choice_form($key, NULL, '', 0, $weight, $choice_count);
}
@@ -404,6 +405,7 @@
'#maxlength' => 7,
'#parents' => array('choice', $key, 'chvotes'),
'#access' => user_access('administer nodes'),
+ '#element_validate' => array('element_validate_integer'),
);
$form['weight'] = array(
@@ -447,10 +449,8 @@
*/
function poll_validate($node, $form) {
if (isset($node->title)) {
- // Check for at least two options and validate amount of votes:
+ // Check for at least two options and validate amount of votes.
$realchoices = 0;
- // Renumber fields
- $node->choice = array_values($node->choice);
foreach ($node->choice as $i => $choice) {
if ($choice['chtext'] != '') {
$realchoices++;
@@ -472,6 +472,9 @@
function poll_field_attach_prepare_translation_alter(&$entity, $context) {
if ($context['entity_type'] == 'node' && $entity->type == 'poll') {
$entity->choice = $context['source_entity']->choice;
+ foreach ($entity->choice as $i => $choice) {
+ $entity->choice[$i]['chvotes'] = 0;
+ }
}
}
@@ -582,8 +585,10 @@
'weight' => $choice['weight'],
))
->insertFields(array(
- 'nid' => $node->nid,
- 'chtext' => $choice['chtext'],
+ 'nid' => $node->nid,
+ 'chtext' => $choice['chtext'],
+ 'chvotes' => (int) $choice['chvotes'],
+ 'weight' => $choice['weight'],
))
->execute();
}
diff --git a/core/modules/poll/poll.test b/core/modules/poll/poll.test
index 20a4678..a424154 100644
--- a/core/modules/poll/poll.test
+++ b/core/modules/poll/poll.test
@@ -24,13 +24,26 @@
function pollCreate($title, $choices, $preview = TRUE) {
$this->assertTrue(TRUE, 'Create a poll');
+ $admin_user = $this->drupalCreateUser(array('create poll content', 'administer nodes'));
$web_user = $this->drupalCreateUser(array('create poll content', 'access content', 'edit own poll content'));
- $this->drupalLogin($web_user);
+ $this->drupalLogin($admin_user);
// Get the form first to initialize the state of the internal browser.
$this->drupalGet('node/add/poll');
// Prepare a form with two choices.
+ list($edit, $index) = $this->_pollGenerateEdit($title, $choices);
+
+ // Verify that the vote count element only allows non-negative integers.
+ $edit['choice[new:1][chvotes]'] = -1;
+ $edit['choice[new:0][chvotes]'] = $this->randomString(7);
+ $this->drupalPost(NULL, $edit, t('Save'));
+ $this->assertText(t('Negative values are not allowed.'));
+ $this->assertText(t('Vote count for new choice must be an integer.'));
+
+ // Repeat steps for initializing the state of the internal browser.
+ $this->drupalLogin($web_user);
+ $this->drupalGet('node/add/poll');
list($edit, $index) = $this->_pollGenerateEdit($title, $choices);
// Re-submit the form until all choices are filled in.
@@ -88,10 +101,6 @@
}
foreach ($new_choices as $k => $text) {
$edit['choice[new:' . $k . '][chtext]'] = $text;
- // To test poll choice weights, every new choice is sorted in front of
- // existing choices. Existing/already submitted choices should keep their
- // weight.
- $edit['choice[new:' . $k . '][weight]'] = (- $index - $k);
}
return array($edit, count($already_submitted_choices) + count($new_choices));
}
@@ -122,11 +131,11 @@
*/
function assertPollChoiceOrder(array $choices, $index = 0, $preview = FALSE) {
$expected = array();
+ $weight = 0;
foreach ($choices as $id => $label) {
if ($id < $index) {
- // The expected weight of each choice is exactly the negated id.
- // @see PollTestCase::_pollGenerateEdit()
- $weight = -$id;
+ // The expected weight of each choice is higher than the previous one.
+ $weight++;
// Directly assert the weight form element value for this choice.
$this->assertFieldByName('choice[chid:' . $id . '][weight]', $weight, t('Found choice @id with weight @weight.', array(
'@id' => $id,
@@ -205,11 +214,12 @@
$new_option = $this->randomName();
+ $vote_count = '2000';
$node->choice[] = array(
'chid' => '',
'chtext' => $new_option,
- 'chvotes' => 0,
- 'weight' => 0,
+ 'chvotes' => (int) $vote_count,
+ 'weight' => 1000,
);
node_save($node);
@@ -217,6 +227,12 @@
$this->drupalGet('poll');
$this->clickLink($title);
$this->assertText($new_option, 'New option found.');
+
+ $option = $this->xpath('//div[@id="node-1"]//div[@class="poll"]//div[@class="text"]');
+ $this->assertEqual(end($option), $new_option, 'Last item is equal to new option.');
+
+ $votes = $this->xpath('//div[@id="node-1"]//div[@class="poll"]//div[@class="percent"]');
+ $this->assertTrue(strpos(end($votes), $vote_count) > 0, t("Votes saved."));
}
function testPollClose() {
diff --git a/core/modules/rdf/tests/rdf_test.info b/core/modules/rdf/tests/rdf_test.info
index b168815..87a6dac 100644
--- a/core/modules/rdf/tests/rdf_test.info
+++ b/core/modules/rdf/tests/rdf_test.info
@@ -4,3 +4,4 @@
version = VERSION
core = 8.x
hidden = TRUE
+dependencies[] = rdf
diff --git a/core/modules/search/search.module b/core/modules/search/search.module
index e731e4f..4d6f1be 100644
--- a/core/modules/search/search.module
+++ b/core/modules/search/search.module
@@ -1165,7 +1165,7 @@
if (($s = strrpos($end, ' ')) !== FALSE) {
// Account for the added spaces.
$q = max($q - 1, 0);
- $s = min($s, drupal_strlen($end) - 1);
+ $s = min($s, strlen($end) - 1);
$ranges[$q] = $p + $s;
$length += $p + $s - $q;
$included[$key] = $p + 1;
diff --git a/core/modules/search/search.test b/core/modules/search/search.test
index 6909efd..1ee4e6f 100644
--- a/core/modules/search/search.test
+++ b/core/modules/search/search.test
@@ -1599,6 +1599,12 @@
$result = preg_replace('| +|', ' ', search_excerpt('nothing', $entities));
$this->assertFalse(strpos($result, '&'), 'Entities are not present in excerpt');
$this->assertTrue(strpos($result, 'í') > 0, 'Entities are converted in excerpt');
+
+ // The node body that will produce this rendered $text is:
+ // 123456789 HTMLTest +123456789+‘ +‘ +‘ +‘ +12345678 +‘ +‘ +‘ ‘
+ $text = "
";
+ $result = search_excerpt('HTMLTest', $text);
+ $this->assertFalse(empty($result), 'Rendered Multi-byte HTML encodings are not corrupted in search excerpts');
}
/**
diff --git a/core/modules/shortcut/shortcut.admin.js b/core/modules/shortcut/shortcut.admin.js
index 5e71e6f..9a730fa 100644
--- a/core/modules/shortcut/shortcut.admin.js
+++ b/core/modules/shortcut/shortcut.admin.js
@@ -42,6 +42,15 @@
if (total == -1) {
var disabled = $(table).find('tr.shortcut-status-disabled');
disabled.after(disabled.prevAll().filter(':not(.shortcut-slot-empty)').get(0));
+ if ($(swappedRow).hasClass('draggable')) {
+ // The dropped element will automatically be marked as changed by
+ // the tableDrag system. However, the row that swapped with it
+ // has moved to the "disabled" section, so we need to force its
+ // status to be disabled and mark it also as changed.
+ swappedRowObject = new tableDrag.row(swappedRow, 'mouse', self.indentEnabled, self.maxDepth, true);
+ swappedRowObject.markChanged();
+ rowStatusChange(swappedRowObject);
+ }
}
else if (total != visibleLength) {
if (total > visibleLength) {
@@ -59,13 +68,17 @@
// Add a handler so when a row is dropped, update fields dropped into new regions.
tableDrag.onDrop = function () {
+ rowStatusChange(this.rowObject);
+ return true;
+ };
+
+ function rowStatusChange(rowObject) {
// Use "status-message" row instead of "status" row because
// "status-{status_name}-message" is less prone to regexp match errors.
- var statusRow = $(this.rowObject.element).prevAll('tr.shortcut-status').get(0);
+ var statusRow = $(rowObject.element).prevAll('tr.shortcut-status').get(0);
var statusName = statusRow.className.replace(/([^ ]+[ ]+)*shortcut-status-([^ ]+)([ ]+[^ ]+)*/, '$2');
- var statusField = $('select.shortcut-status-select', this.rowObject.element);
+ var statusField = $('select.shortcut-status-select', rowObject.element);
statusField.val(statusName);
- return true;
};
tableDrag.restripeTable = function () {
diff --git a/core/modules/shortcut/shortcut.install b/core/modules/shortcut/shortcut.install
index 60ee6be..7aee9c9 100644
--- a/core/modules/shortcut/shortcut.install
+++ b/core/modules/shortcut/shortcut.install
@@ -13,18 +13,19 @@
// Create an initial default shortcut set.
$shortcut_set = new stdClass();
$shortcut_set->title = $t('Default');
- $shortcut_set->links = array(
- array(
+ $shortcut_set->links = array();
+ if (module_exists('node')) {
+ $shortcut_set->links[] = array(
'link_path' => 'node/add',
'link_title' => $t('Add content'),
'weight' => -20,
- ),
- array(
+ );
+ $shortcut_set->links[] = array(
'link_path' => 'admin/content',
'link_title' => $t('Find content'),
'weight' => -19,
- ),
- );
+ );
+ }
// If Drupal is being installed, rebuild the menu before saving the shortcut
// set, to make sure the links defined above can be correctly saved. (During
// installation, the menu might not have been built at all yet, or it might
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index 34177bb..a60f8d8 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -744,6 +744,6 @@
* shortcut_set_load().
*/
function shortcut_set_title($shortcut_set) {
- return check_plain($shortcut_set->title);
+ return $shortcut_set->title;
}
diff --git a/core/modules/simpletest/drupal_web_test_case.php b/core/modules/simpletest/drupal_web_test_case.php
index 0edd3fd..a5fb606 100644
--- a/core/modules/simpletest/drupal_web_test_case.php
+++ b/core/modules/simpletest/drupal_web_test_case.php
@@ -1355,6 +1355,13 @@
$test_info['test_run_id'] = $this->databasePrefix;
$test_info['in_child_site'] = FALSE;
+ // Preset the 'install_profile' system variable, so the first call into
+ // system_rebuild_module_data() (in drupal_install_system()) will register
+ // the test's profile as a module. Without this, the installation profile of
+ // the parent site (executing the test) is registered, and the test
+ // profile's hook_install() and other hook implementations are never invoked.
+ $conf['install_profile'] = $this->profile;
+
include_once DRUPAL_ROOT . '/core/includes/install.inc';
drupal_install_system();
diff --git a/core/modules/simpletest/simpletest.test b/core/modules/simpletest/simpletest.test
index 716b36e..bd4427c 100644
--- a/core/modules/simpletest/simpletest.test
+++ b/core/modules/simpletest/simpletest.test
@@ -20,10 +20,7 @@
public static function getInfo() {
return array(
'name' => 'SimpleTest functionality',
- 'description' => 'Test SimpleTest\'s web interface: check that the intended tests were
- run and ensure that test reports display the intended results. Also
- test SimpleTest\'s internal browser and API\'s both explicitly and
- implicitly.',
+ 'description' => "Test SimpleTest's web interface: check that the intended tests were run and ensure that test reports display the intended results. Also test SimpleTest's internal browser and APIs both explicitly and implicitly.",
'group' => 'SimpleTest'
);
}
diff --git a/core/modules/simpletest/tests/ajax.test b/core/modules/simpletest/tests/ajax.test
index 9a76b96..8e731b8 100644
--- a/core/modules/simpletest/tests/ajax.test
+++ b/core/modules/simpletest/tests/ajax.test
@@ -127,31 +127,7 @@
'css' => drupal_get_path('module', 'system') . '/system.admin.css',
'js' => drupal_get_path('module', 'system') . '/system.js',
);
-
- // Get the base page.
- $this->drupalGet('ajax_forms_test_lazy_load_form');
- $original_settings = $this->drupalGetSettings();
- $original_css = $original_settings['ajaxPageState']['css'];
- $original_js = $original_settings['ajaxPageState']['js'];
-
- // Verify that the base page doesn't have the settings and files that are to
- // be lazy loaded as part of the next request.
- $this->assertTrue(!isset($original_settings[$expected['setting_name']]), t('Page originally lacks the %setting, as expected.', array('%setting' => $expected['setting_name'])));
- $this->assertTrue(!isset($original_settings[$expected['css']]), t('Page originally lacks the %css file, as expected.', array('%css' => $expected['css'])));
- $this->assertTrue(!isset($original_settings[$expected['js']]), t('Page originally lacks the %js file, as expected.', array('%js' => $expected['js'])));
-
- // Submit the AJAX request.
- $commands = $this->drupalPostAJAX(NULL, array(), array('op' => t('Submit')));
- $new_settings = $this->drupalGetSettings();
- $new_css = $new_settings['ajaxPageState']['css'];
- $new_js = $new_settings['ajaxPageState']['js'];
-
- // Verify the expected setting was added.
- $this->assertIdentical($new_settings[$expected['setting_name']], $expected['setting_value'], t('Page now has the %setting.', array('%setting' => $expected['setting_name'])));
-
- // Verify the expected CSS file was added, both to Drupal.settings, and as
- // an AJAX command for inclusion into the HTML.
- // @todo A drupal_css_defaults() function in Drupal 8 would be nice.
+ // @todo D8: Add a drupal_css_defaults() helper function.
$expected_css_html = drupal_get_css(array($expected['css'] => array(
'type' => 'file',
'group' => CSS_DEFAULT,
@@ -162,6 +138,52 @@
'data' => $expected['css'],
'browsers' => array('IE' => TRUE, '!IE' => TRUE),
)), TRUE);
+ $expected_js_html = drupal_get_js('header', array($expected['js'] => drupal_js_defaults($expected['js'])), TRUE);
+
+ // Get the base page.
+ $this->drupalGet('ajax_forms_test_lazy_load_form');
+ $original_settings = $this->drupalGetSettings();
+ $original_css = $original_settings['ajaxPageState']['css'];
+ $original_js = $original_settings['ajaxPageState']['js'];
+
+ // Verify that the base page doesn't have the settings and files that are to
+ // be lazy loaded as part of the next requests.
+ $this->assertTrue(!isset($original_settings[$expected['setting_name']]), t('Page originally lacks the %setting, as expected.', array('%setting' => $expected['setting_name'])));
+ $this->assertTrue(!isset($original_settings[$expected['css']]), t('Page originally lacks the %css file, as expected.', array('%css' => $expected['css'])));
+ $this->assertTrue(!isset($original_settings[$expected['js']]), t('Page originally lacks the %js file, as expected.', array('%js' => $expected['js'])));
+
+ // Submit the AJAX request without triggering files getting added.
+ $commands = $this->drupalPostAJAX(NULL, array('add_files' => FALSE), array('op' => t('Submit')));
+ $new_settings = $this->drupalGetSettings();
+
+ // Verify the setting was not added when not expected.
+ $this->assertTrue(!isset($new_settings['setting_name']), t('Page still lacks the %setting, as expected.', array('%setting' => $expected['setting_name'])));
+ // Verify a settings command does not add CSS or scripts to Drupal.settings
+ // and no command inserts the corresponding tags on the page.
+ $found_settings_command = FALSE;
+ $found_markup_command = FALSE;
+ foreach ($commands as $command) {
+ if ($command['command'] == 'settings' && (array_key_exists('css', $command['settings']['ajaxPageState']) || array_key_exists('js', $command['settings']['ajaxPageState']))) {
+ $found_settings_command = TRUE;
+ }
+ if (isset($command['data']) && ($command['data'] == $expected_js_html || $command['data'] == $expected_css_html)) {
+ $found_markup_command = TRUE;
+ }
+ }
+ $this->assertFalse($found_settings_command, t('Page state still lacks the %css and %js files, as expected.', array('%css' => $expected['css'], '%js' => $expected['js'])));
+ $this->assertFalse($found_markup_command, t('Page still lacks the %css and %js files, as expected.', array('%css' => $expected['css'], '%js' => $expected['js'])));
+
+ // Submit the AJAX request and trigger adding files.
+ $commands = $this->drupalPostAJAX(NULL, array('add_files' => TRUE), array('op' => t('Submit')));
+ $new_settings = $this->drupalGetSettings();
+ $new_css = $new_settings['ajaxPageState']['css'];
+ $new_js = $new_settings['ajaxPageState']['js'];
+
+ // Verify the expected setting was added.
+ $this->assertIdentical($new_settings[$expected['setting_name']], $expected['setting_value'], t('Page now has the %setting.', array('%setting' => $expected['setting_name'])));
+
+ // Verify the expected CSS file was added, both to Drupal.settings, and as
+ // an AJAX command for inclusion into the HTML.
$this->assertEqual($new_css, $original_css + array($expected['css'] => 1), t('Page state now has the %css file.', array('%css' => $expected['css'])));
$this->assertCommand($commands, array('data' => $expected_css_html), t('Page now has the %css file.', array('%css' => $expected['css'])));
@@ -170,7 +192,6 @@
// string containing the SCRIPT tag, we also ensure that unexpected
// JavaScript code, such as a jQuery.extend() that would potentially clobber
// rather than properly merge settings, didn't accidentally get added.
- $expected_js_html = drupal_get_js('header', array($expected['js'] => drupal_js_defaults($expected['js'])), TRUE);
$this->assertEqual($new_js, $original_js + array($expected['js'] => 1), t('Page state now has the %js file.', array('%js' => $expected['js'])));
$this->assertCommand($commands, array('data' => $expected_js_html), t('Page now has the %js file.', array('%js' => $expected['js'])));
}
diff --git a/core/modules/simpletest/tests/ajax_forms_test.module b/core/modules/simpletest/tests/ajax_forms_test.module
index 075b005..6a95710 100644
--- a/core/modules/simpletest/tests/ajax_forms_test.module
+++ b/core/modules/simpletest/tests/ajax_forms_test.module
@@ -468,6 +468,10 @@
* Form builder: Builds a form that triggers a simple AJAX callback.
*/
function ajax_forms_test_lazy_load_form($form, &$form_state) {
+ $form['add_files'] = array(
+ '#type' => 'checkbox',
+ '#default_value' => FALSE,
+ );
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
@@ -482,9 +486,11 @@
* Form submit handler: Adds JavaScript and CSS that wasn't on the original form.
*/
function ajax_forms_test_lazy_load_form_submit($form, &$form_state) {
- drupal_add_js(array('ajax_forms_test_lazy_load_form_submit' => 'executed'), 'setting');
- drupal_add_css(drupal_get_path('module', 'system') . '/system.admin.css');
- drupal_add_js(drupal_get_path('module', 'system') . '/system.js');
+ if ($form_state['values']['add_files']) {
+ drupal_add_js(array('ajax_forms_test_lazy_load_form_submit' => 'executed'), 'setting');
+ drupal_add_css(drupal_get_path('module', 'system') . '/system.admin.css');
+ drupal_add_js(drupal_get_path('module', 'system') . '/system.js');
+ }
$form_state['rebuild'] = TRUE;
}
diff --git a/core/modules/simpletest/tests/cache.test b/core/modules/simpletest/tests/cache.test
index 664247b..bca4e25 100644
--- a/core/modules/simpletest/tests/cache.test
+++ b/core/modules/simpletest/tests/cache.test
@@ -1,7 +1,7 @@
drupalGet('user/register');
- $this->assertFalse(cache_get(''), t('No cache entry is written with an empty cid.'));
+ $this->assertFalse(cache()->get(''), t('No cache entry is written with an empty cid.'));
}
}
diff --git a/core/modules/simpletest/tests/common_test.module b/core/modules/simpletest/tests/common_test.module
index 1481513..e1cfdf2 100644
--- a/core/modules/simpletest/tests/common_test.module
+++ b/core/modules/simpletest/tests/common_test.module
@@ -241,7 +241,7 @@
// Change the title of Farbtastic to "Farbtastic: Altered Library".
$libraries['farbtastic']['title'] = 'Farbtastic: Altered Library';
// Make Farbtastic depend on jQuery Form to test library dependencies.
- $libraries['farbtastic']['dependencies'][] = array('system', 'form');
+ $libraries['farbtastic']['dependencies'][] = array('system', 'jquery.form');
}
}
diff --git a/core/modules/simpletest/tests/database_test.test b/core/modules/simpletest/tests/database_test.test
index 6e55fbd..16c09c6 100644
--- a/core/modules/simpletest/tests/database_test.test
+++ b/core/modules/simpletest/tests/database_test.test
@@ -19,7 +19,12 @@
protected $profile = 'testing';
function setUp() {
- parent::setUp('database_test');
+ $modules = func_get_args();
+ if (isset($modules[0]) && is_array($modules[0])) {
+ $modules = $modules[0];
+ }
+ $modules[] = 'database_test';
+ parent::setUp($modules);
$schema['test'] = drupal_get_schema('test');
$schema['test_people'] = drupal_get_schema('test_people');
@@ -375,10 +380,6 @@
'description' => 'Test the Database system\'s various fetch capabilities.',
'group' => 'Database',
);
- }
-
- function setUp() {
- parent::setUp();
}
// Confirm that we can fetch a record into an indexed array explicitly.
@@ -2218,24 +2219,14 @@
}
function setUp() {
- DrupalWebTestCase::setUp('database_test', 'node_access_test');
-
- $schema['test'] = drupal_get_schema('test');
- $schema['test_people'] = drupal_get_schema('test_people');
- $schema['test_one_blob'] = drupal_get_schema('test_one_blob');
- $schema['test_two_blobs'] = drupal_get_schema('test_two_blobs');
- $schema['test_task'] = drupal_get_schema('test_task');
-
- $this->installTables($schema);
-
- $this->addSampleData();
+ parent::setUp(array('node_access_test'));
}
/**
* Test that we can join on a query.
*/
function testJoinSubquery() {
- $acct = $this->drupalCreateUser(array('access content'));
+ $acct = $this->drupalCreateUser();
$this->drupalLogin($acct);
$query = db_select('test_task', 'tt', array('target' => 'slave'));
@@ -2754,6 +2745,10 @@
);
}
+ function setUp() {
+ parent::setUp(array('node'));
+ }
+
/**
* Regression test for #310447.
*
@@ -3045,10 +3040,6 @@
);
}
- function setUp() {
- parent::setUp('database_test');
- }
-
/**
* Test for string concatenation.
*/
@@ -3146,10 +3137,6 @@
);
}
- function setUp() {
- parent::setUp('database_test');
- }
-
/**
* Traditional SQL database systems abort inserts when invalid data is encountered.
*/
@@ -3217,10 +3204,6 @@
'description' => 'Test Drupal\'s extended prepared statement syntax..',
'group' => 'Database',
);
- }
-
- function setUp() {
- parent::setUp('database_test');
}
/**
@@ -3450,35 +3433,89 @@
*/
function testTransactionWithDdlStatement() {
// First, test that a commit works normally, even with DDL statements.
- try {
- $this->transactionOuterLayer('D', FALSE, TRUE);
+ $transaction = db_transaction();
+ $this->insertRow('row');
+ $this->executeDDLStatement();
+ unset($transaction);
+ $this->assertRowPresent('row');
- // Because we committed, the inserted rows should both be present.
- $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DavidD'))->fetchField();
- $this->assertIdentical($saved_age, '24', t('Can retrieve DavidD row after commit.'));
- $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DanielD'))->fetchField();
- $this->assertIdentical($saved_age, '19', t('Can retrieve DanielD row after commit.'));
- // The created table should also exist.
- $count = db_query('SELECT COUNT(id) FROM {database_test_1}')->fetchField();
- $this->assertIdentical($count, '0', t('Table was successfully created inside a transaction.'));
- }
- catch (Exception $e) {
- $this->fail((string) $e);
- }
+ // Even in different order.
+ $this->cleanUp();
+ $transaction = db_transaction();
+ $this->executeDDLStatement();
+ $this->insertRow('row');
+ unset($transaction);
+ $this->assertRowPresent('row');
- // If we rollback the transaction, an exception might be thrown.
- try {
- $this->transactionOuterLayer('E', TRUE, TRUE);
+ // Even with stacking.
+ $this->cleanUp();
+ $transaction = db_transaction();
+ $transaction2 = db_transaction();
+ $this->executeDDLStatement();
+ unset($transaction2);
+ $transaction3 = db_transaction();
+ $this->insertRow('row');
+ unset($transaction3);
+ unset($transaction);
+ $this->assertRowPresent('row');
- // Because we rolled back, the inserted rows shouldn't be present.
- $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DavidE'))->fetchField();
- $this->assertNotIdentical($saved_age, '24', t('Cannot retrieve DavidE row after rollback.'));
- $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DanielE'))->fetchField();
- $this->assertNotIdentical($saved_age, '19', t('Cannot retrieve DanielE row after rollback.'));
+ // A transaction after a DDL statement should still work the same.
+ $this->cleanUp();
+ $transaction = db_transaction();
+ $transaction2 = db_transaction();
+ $this->executeDDLStatement();
+ unset($transaction2);
+ $transaction3 = db_transaction();
+ $this->insertRow('row');
+ $transaction3->rollback();
+ unset($transaction3);
+ unset($transaction);
+ $this->assertRowAbsent('row');
+
+ // The behavior of a rollback depends on the type of database server.
+ if (Database::getConnection()->supportsTransactionalDDL()) {
+ // For database servers that support transactional DDL, a rollback
+ // of a transaction including DDL statements should be possible.
+ $this->cleanUp();
+ $transaction = db_transaction();
+ $this->insertRow('row');
+ $this->executeDDLStatement();
+ $transaction->rollback();
+ unset($transaction);
+ $this->assertRowAbsent('row');
+
+ // Including with stacking.
+ $this->cleanUp();
+ $transaction = db_transaction();
+ $transaction2 = db_transaction();
+ $this->executeDDLStatement();
+ unset($transaction2);
+ $transaction3 = db_transaction();
+ $this->insertRow('row');
+ unset($transaction3);
+ $transaction->rollback();
+ unset($transaction);
+ $this->assertRowAbsent('row');
}
- catch (Exception $e) {
- // An exception also lets the test pass.
- $this->assertTrue(true, t('Exception thrown on rollback after a DDL statement was executed.'));
+ else {
+ // For database servers that do not support transactional DDL,
+ // the DDL statement should commit the transaction stack.
+ $this->cleanUp();
+ $transaction = db_transaction();
+ $this->insertRow('row');
+ $this->executeDDLStatement();
+ // Rollback the outer transaction.
+ try {
+ $transaction->rollback();
+ unset($transaction);
+ // @TODO: an exception should be triggered here, but is not, because
+ // "ROLLBACK" fails silently in MySQL if there is no transaction active.
+ // $this->fail(t('Rolling back a transaction containing DDL should fail.'));
+ }
+ catch (DatabaseTransactionNoActiveException $e) {
+ $this->pass(t('Rolling back a transaction containing DDL should fail.'));
+ }
+ $this->assertRowPresent('row');
}
}
@@ -3491,6 +3528,24 @@
'name' => $name,
))
->execute();
+ }
+
+ /**
+ * Execute a DDL statement.
+ */
+ protected function executeDDLStatement() {
+ static $count = 0;
+ $table = array(
+ 'fields' => array(
+ 'id' => array(
+ 'type' => 'serial',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ ),
+ ),
+ 'primary key' => array('id'),
+ );
+ db_create_table('database_test_' . ++$count, $table);
}
/**
@@ -3537,8 +3592,8 @@
* Test transaction stacking and commit / rollback.
*/
function testTransactionStacking() {
- // This test won't work right if transactions are supported.
- if (Database::getConnection()->supportsTransactions()) {
+ // This test won't work right if transactions are not supported.
+ if (!Database::getConnection()->supportsTransactions()) {
return;
}
@@ -3617,26 +3672,33 @@
$this->insertRow('outer');
$transaction2 = db_transaction();
$this->insertRow('inner');
+ $transaction3 = db_transaction();
+ $this->insertRow('inner2');
// Rollback the outer transaction.
try {
$transaction->rollback();
unset($transaction);
$this->fail(t('Rolling back the outer transaction while the inner transaction is active resulted in an exception.'));
}
- catch (Exception $e) {
+ catch (DatabaseTransactionOutOfOrderException $e) {
$this->pass(t('Rolling back the outer transaction while the inner transaction is active resulted in an exception.'));
}
$this->assertFalse($database->inTransaction(), t('No more in a transaction after rolling back the outer transaction'));
- // Try to commit the inner transaction.
+ // Try to commit one inner transaction.
+ unset($transaction3);
+ $this->pass(t('Trying to commit an inner transaction resulted in an exception.'));
+ // Try to rollback one inner transaction.
try {
+ $transaction->rollback();
unset($transaction2);
- $this->fail(t('Trying to commit the inner transaction resulted in an exception.'));
+ $this->fail(t('Trying to commit an inner transaction resulted in an exception.'));
}
- catch (Exception $e) {
- $this->pass(t('Trying to commit the inner transaction resulted in an exception.'));
+ catch (DatabaseTransactionNoActiveException $e) {
+ $this->pass(t('Trying to commit an inner transaction resulted in an exception.'));
}
$this->assertRowAbsent('outer');
$this->assertRowAbsent('inner');
+ $this->assertRowAbsent('inner2');
}
}
diff --git a/core/modules/simpletest/tests/menu.test b/core/modules/simpletest/tests/menu.test
index d0612ac..5a173b1 100644
--- a/core/modules/simpletest/tests/menu.test
+++ b/core/modules/simpletest/tests/menu.test
@@ -107,7 +107,7 @@
*/
protected function getParts() {
$parts = array();
- $elements = $this->xpath('//div[@class="breadcrumb"]/a');
+ $elements = $this->xpath('//nav[@class="breadcrumb"]/ol/li/a');
if (!empty($elements)) {
foreach ($elements as $element) {
$parts[] = array(
diff --git a/core/modules/simpletest/tests/theme.test b/core/modules/simpletest/tests/theme.test
index 6fb6b3b..6980b19 100644
--- a/core/modules/simpletest/tests/theme.test
+++ b/core/modules/simpletest/tests/theme.test
@@ -66,7 +66,8 @@
$q = $_GET['q'];
// Set $_GET['q'] to node because theme_get_suggestions() will query it to
// see if we are on the front page.
- $_GET['q'] = variable_get('site_frontpage', 'node');
+ variable_set('site_frontpage', 'node');
+ $_GET['q'] = 'node';
$suggestions = theme_get_suggestions(explode('/', $_GET['q']), 'page');
// Set it back to not annoy the batch runner.
$_GET['q'] = $q;
@@ -247,6 +248,69 @@
}
/**
+ * Tests theme_links().
+ */
+ function testLinks() {
+ // Verify that empty variables produce no output.
+ $variables = array();
+ $expected = '';
+ $this->assertThemeOutput('links', $variables, $expected, 'Empty %callback generates no output.');
+
+ $variables = array();
+ $variables['heading'] = 'Some title';
+ $expected = '';
+ $this->assertThemeOutput('links', $variables, $expected, 'Empty %callback with heading generates no output.');
+
+ // Set the current path to the front page path.
+ // Required to verify the "active" class in expected links below, and
+ // because the current path is different when running tests manually via
+ // simpletest.module ('batch') and via the testing framework ('').
+ $_GET['q'] = variable_get('site_frontpage', 'user');
+
+ // Verify that a list of links is properly rendered.
+ $variables = array();
+ $variables['attributes'] = array('id' => 'somelinks');
+ $variables['links'] = array(
+ 'a link' => array(
+ 'title' => 'A ',
+ 'href' => 'a/link',
+ ),
+ 'plain text' => array(
+ 'title' => 'Plain "text"',
+ ),
+ 'front page' => array(
+ 'title' => 'Front page',
+ 'href' => '',
+ ),
+ );
+
+ $expected_links = '';
+ $expected_links .= '
';
+ $expected = $expected_heading . $expected_links;
+ $this->assertThemeOutput('links', $variables, $expected);
+ }
+
+ /**
* Asserts themed output.
*
* @param $callback
@@ -270,19 +334,6 @@
}
$message = t($message, array('%callback' => 'theme_' . $callback . '()'));
$this->assertIdentical($output, $expected, $message);
- }
-}
-
-/**
- * Unit tests for theme_links().
- */
-class ThemeLinksTest extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Links',
- 'description' => 'Test the theme_links() function and rendering groups of links.',
- 'group' => 'Theme',
- );
}
/**
diff --git a/core/modules/simpletest/tests/theme_test.module b/core/modules/simpletest/tests/theme_test.module
index 400902d..2a2552a 100644
--- a/core/modules/simpletest/tests/theme_test.module
+++ b/core/modules/simpletest/tests/theme_test.module
@@ -26,14 +26,14 @@
$items['theme-test/suggestion'] = array(
'title' => 'Suggestion',
'page callback' => '_theme_test_suggestion',
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'theme callback' => '_theme_custom_theme',
'type' => MENU_CALLBACK,
);
$items['theme-test/alter'] = array(
'title' => 'Suggestion',
'page callback' => '_theme_test_alter',
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'theme callback' => '_theme_custom_theme',
'type' => MENU_CALLBACK,
);
diff --git a/core/modules/syslog/syslog.module b/core/modules/syslog/syslog.module
index c4ee382..7c7bf40 100644
--- a/core/modules/syslog/syslog.module
+++ b/core/modules/syslog/syslog.module
@@ -6,6 +6,15 @@
*/
if (defined('LOG_LOCAL0')) {
+ /**
+ * Sets the proper logging facility.
+ *
+ * Note that LOG_LOCAL0 through LOG_LOCAL7 are not available on Windows, so we
+ * check for availability. If LOG_LOCAL0 is defined by the PHP environment, we
+ * set that as the default; if not, we use LOG_USER.
+ *
+ * @see http://php.net/manual/function.syslog.php
+ */
define('DEFAULT_SYSLOG_FACILITY', LOG_LOCAL0);
}
else {
diff --git a/core/modules/system/page.tpl.php b/core/modules/system/page.tpl.php
index 23b577e..c76e27f 100644
--- a/core/modules/system/page.tpl.php
+++ b/core/modules/system/page.tpl.php
@@ -107,9 +107,7 @@
-
-
-
+
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 6dca80b..4a359be 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -260,11 +260,6 @@
'#description' => t('Choose "Default theme" to always use the same theme as the rest of the site.'),
'#default_value' => variable_get('admin_theme', 0),
);
- $form['admin_theme']['node_admin_theme'] = array(
- '#type' => 'checkbox',
- '#title' => t('Use the administration theme when editing or creating content'),
- '#default_value' => variable_get('node_admin_theme', '0'),
- );
$form['admin_theme']['actions'] = array('#type' => 'actions');
$form['admin_theme']['actions']['submit'] = array(
'#type' => 'submit',
@@ -279,7 +274,6 @@
function system_themes_admin_form_submit($form, &$form_state) {
drupal_set_message(t('The configuration options have been saved.'));
variable_set('admin_theme', $form_state['values']['admin_theme']);
- variable_set('node_admin_theme', $form_state['values']['node_admin_theme']);
}
/**
@@ -1487,7 +1481,7 @@
$form['front_page']['site_frontpage'] = array(
'#type' => 'textfield',
'#title' => t('Default front page'),
- '#default_value' => (variable_get('site_frontpage')!='node'?drupal_get_path_alias(variable_get('site_frontpage', 'node')):''),
+ '#default_value' => (variable_get('site_frontpage') != 'user' ? drupal_get_path_alias(variable_get('site_frontpage', 'user')) : ''),
'#size' => 40,
'#description' => t('Optionally, specify a relative URL to display as the front page. Leave blank to display the default content feed.'),
'#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='),
@@ -1497,8 +1491,8 @@
'#default_value' => variable_get('default_nodes_main', 10),
'#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30)),
'#description' => t('The maximum number of posts displayed on overview pages such as the front page.'),
- '#access' => (variable_get('site_frontpage')=='node'),
- );
+ '#access' => (variable_get('site_frontpage') == 'node'),
+ );
$form['error_page'] = array(
'#type' => 'fieldset',
'#title' => t('Error pages'),
@@ -1535,8 +1529,8 @@
}
// Check for empty front page path.
if (empty($form_state['values']['site_frontpage'])) {
- // Set to default "node".
- form_set_value($form['front_page']['site_frontpage'], 'node', $form_state);
+ // Set to default "user".
+ form_set_value($form['front_page']['site_frontpage'], 'user', $form_state);
}
else {
// Get the normal path of the front page.
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 872b002..e377a9d 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -3350,8 +3350,6 @@
* steps within the installation process.
* @param $install_state
* An array of information about the current installation state.
- *
- * @see install_profile_info()
*/
function hook_install_tasks_alter(&$tasks, $install_state) {
// Replace the entire site configuration form provided by Drupal core
@@ -3751,7 +3749,7 @@
* @param $path
* The outbound path to alter, not adjusted for path aliases yet. It won't be
* adjusted for path aliases until all modules are finished altering it, thus
- * being consistent with hook_url_alter_inbound(), which adjusts for all path
+ * being consistent with hook_url_inbound_alter(), which adjusts for all path
* aliases before allowing modules to alter it. This may have been altered by
* other modules before this one.
* @param $options
diff --git a/core/modules/system/system.base-rtl.css b/core/modules/system/system.base-rtl.css
index 9099c9d..8dd0068 100644
--- a/core/modules/system/system.base-rtl.css
+++ b/core/modules/system/system.base-rtl.css
@@ -27,9 +27,6 @@
.ajax-progress {
float: right;
}
-.ajax-progress .throbber {
- float: right;
-}
/**
* TableDrag behavior.
diff --git a/core/modules/system/system.base.css b/core/modules/system/system.base.css
index 99fcfcb..8519362 100644
--- a/core/modules/system/system.base.css
+++ b/core/modules/system/system.base.css
@@ -160,18 +160,18 @@
/* Throbber */
.ajax-progress {
display: inline-block;
+ padding: 1px 5px 2px 5px;
}
-.ajax-progress .throbber {
+.ajax-progress-throbber .throbber {
background: transparent url(../../misc/throbber.gif) no-repeat 0px -18px;
- float: left; /* LTR */
- height: 15px;
- margin: 2px;
- width: 15px;
+ display: inline;
+ padding: 1px 5px 2px;
}
-.ajax-progress .message {
- padding-left: 20px;
+.ajax-progress-throbber .message {
+ display: inline;
+ padding: 1px 5px 2px;
}
-tr .ajax-progress .throbber {
+tr .ajax-progress-throbber .throbber {
margin: 0 2px;
}
.ajax-progress-bar {
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index f33d0ea..20e1dc1 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -770,7 +770,7 @@
'not null' => TRUE,
),
'language' => array(
- 'description' => 'A {languages}.language for this format to be used with.',
+ 'description' => 'A {language}.language for this format to be used with.',
'type' => 'varchar',
'length' => 12,
'not null' => TRUE,
@@ -1471,7 +1471,7 @@
'default' => 0,
),
'cache' => array(
- 'description' => "The time of this user's last post. This is used when the site has specified a minimum_cache_lifetime. See cache_get().",
+ 'description' => "The time of this user's last post. This is used when the site has specified a minimum_cache_lifetime. See DrupalCacheInterface::get().",
'type' => 'int',
'not null' => TRUE,
'default' => 0,
diff --git a/core/modules/system/system.mail.inc b/core/modules/system/system.mail.inc
index ef50642..1ce9fc0 100644
--- a/core/modules/system/system.mail.inc
+++ b/core/modules/system/system.mail.inc
@@ -65,26 +65,47 @@
// For headers, PHP's API suggests that we use CRLF normally,
// but some MTAs incorrectly replace LF with CRLF. See #234403.
$mail_headers = join("\n", $mimeheaders);
- if (isset($message['Return-Path']) && !ini_get('safe_mode')) {
- $mail_result = mail(
- $message['to'],
- $mail_subject,
- $mail_body,
- $mail_headers,
- // Pass the Return-Path via sendmail's -f command.
- '-f ' . $message['Return-Path']
- );
+
+ // We suppress warnings and notices from mail() because of issues on some
+ // hosts. The return value of this method will still indicate whether mail
+ // was sent successfully.
+ if (!isset($_SERVER['WINDIR']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Win32') === FALSE) {
+ if (isset($message['Return-Path']) && !ini_get('safe_mode')) {
+ // On most non-Windows systems, the "-f" option to the sendmail command
+ // is used to set the Return-Path. There is no space between -f and
+ // the value of the return path.
+ $mail_result = @mail(
+ $message['to'],
+ $mail_subject,
+ $mail_body,
+ $mail_headers,
+ '-f' . $message['Return-Path']
+ );
+ }
+ else {
+ // The optional $additional_parameters argument to mail() is not
+ // allowed if safe_mode is enabled. Passing any value throws a PHP
+ // warning and makes mail() return FALSE.
+ $mail_result = @mail(
+ $message['to'],
+ $mail_subject,
+ $mail_body,
+ $mail_headers
+ );
+ }
}
else {
- // The optional $additional_parameters argument to mail() is not allowed
- // if safe_mode is enabled. Passing any value throws a PHP warning and
- // makes mail() return FALSE.
- $mail_result = mail(
+ // On Windows, PHP will use the value of sendmail_from for the
+ // Return-Path header.
+ $old_from = ini_get('sendmail_from');
+ ini_set('sendmail_from', $message['Return-Path']);
+ $mail_result = @mail(
$message['to'],
$mail_subject,
$mail_body,
$mail_headers
);
+ ini_set('sendmail_from', $old_from);
}
return $mail_result;
}
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 625be0a..7e5a43d 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -982,7 +982,7 @@
);
$items['admin/config/system/site-information'] = array(
'title' => 'Site information',
- 'description' => t('Change site name, e-mail address, slogan, default front page, and number of posts per page, error pages.'),
+ 'description' => 'Change site name, e-mail address, slogan, default front page, and number of posts per page, error pages.',
'page callback' => 'drupal_get_form',
'page arguments' => array('system_site_information_settings'),
'access arguments' => array('administer site configuration'),
@@ -990,8 +990,8 @@
'weight' => -20,
);
$items['admin/config/system/cron'] = array(
- 'title' => t('Cron'),
- 'description' => t('Manage automatic site maintenance tasks.'),
+ 'title' => 'Cron',
+ 'description' => 'Manage automatic site maintenance tasks.',
'page callback' => 'drupal_get_form',
'page arguments' => array('system_cron_settings'),
'access arguments' => array('administer site configuration'),
@@ -1121,7 +1121,7 @@
'title' => 'Drupal progress indicator',
'version' => VERSION,
'js' => array(
- 'core/misc/progress.js' => array('group' => JS_DEFAULT, 'cache' => FALSE),
+ 'core/misc/progress.js' => array('group' => JS_DEFAULT),
),
);
@@ -1275,7 +1275,7 @@
$libraries['ui'] = array(
'title' => 'jQuery UI: Core',
'website' => 'http://jqueryui.com',
- 'version' => '1.8.7',
+ 'version' => '1.8.16',
'js' => array(
'core/misc/ui/jquery.ui.core.min.js' => array('group' => JS_LIBRARY, 'weight' => -11),
),
@@ -1287,7 +1287,7 @@
$libraries['ui.accordion'] = array(
'title' => 'jQuery UI: Accordion',
'website' => 'http://jqueryui.com/demos/accordion/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.accordion.min.js' => array(),
),
@@ -1301,7 +1301,7 @@
$libraries['ui.autocomplete'] = array(
'title' => 'jQuery UI: Autocomplete',
'website' => 'http://jqueryui.com/demos/autocomplete/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.autocomplete.min.js' => array(),
),
@@ -1316,7 +1316,7 @@
$libraries['ui.button'] = array(
'title' => 'jQuery UI: Button',
'website' => 'http://jqueryui.com/demos/button/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.button.min.js' => array(),
),
@@ -1330,7 +1330,7 @@
$libraries['ui.datepicker'] = array(
'title' => 'jQuery UI: Date Picker',
'website' => 'http://jqueryui.com/demos/datepicker/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.datepicker.min.js' => array(),
),
@@ -1344,7 +1344,7 @@
$libraries['ui.dialog'] = array(
'title' => 'jQuery UI: Dialog',
'website' => 'http://jqueryui.com/demos/dialog/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.dialog.min.js' => array(),
),
@@ -1363,7 +1363,7 @@
$libraries['ui.draggable'] = array(
'title' => 'jQuery UI: Draggable',
'website' => 'http://jqueryui.com/demos/draggable/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.draggable.min.js' => array(),
),
@@ -1375,7 +1375,7 @@
$libraries['ui.droppable'] = array(
'title' => 'jQuery UI: Droppable',
'website' => 'http://jqueryui.com/demos/droppable/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.droppable.min.js' => array(),
),
@@ -1388,7 +1388,7 @@
$libraries['ui.mouse'] = array(
'title' => 'jQuery UI: Mouse',
'website' => 'http://docs.jquery.com/UI/Mouse',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.mouse.min.js' => array(),
),
@@ -1399,7 +1399,7 @@
$libraries['ui.position'] = array(
'title' => 'jQuery UI: Position',
'website' => 'http://jqueryui.com/demos/position/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.position.min.js' => array(),
),
@@ -1407,7 +1407,7 @@
$libraries['ui.progressbar'] = array(
'title' => 'jQuery UI: Progress Bar',
'website' => 'http://jqueryui.com/demos/progressbar/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.progressbar.min.js' => array(),
),
@@ -1421,7 +1421,7 @@
$libraries['ui.resizable'] = array(
'title' => 'jQuery UI: Resizable',
'website' => 'http://jqueryui.com/demos/resizable/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.resizable.min.js' => array(),
),
@@ -1436,7 +1436,7 @@
$libraries['ui.selectable'] = array(
'title' => 'jQuery UI: Selectable',
'website' => 'http://jqueryui.com/demos/selectable/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.selectable.min.js' => array(),
),
@@ -1451,7 +1451,7 @@
$libraries['ui.slider'] = array(
'title' => 'jQuery UI: Slider',
'website' => 'http://jqueryui.com/demos/slider/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.slider.min.js' => array(),
),
@@ -1466,7 +1466,7 @@
$libraries['ui.sortable'] = array(
'title' => 'jQuery UI: Sortable',
'website' => 'http://jqueryui.com/demos/sortable/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.sortable.min.js' => array(),
),
@@ -1478,7 +1478,7 @@
$libraries['ui.tabs'] = array(
'title' => 'jQuery UI: Tabs',
'website' => 'http://jqueryui.com/demos/tabs/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.tabs.min.js' => array(),
),
@@ -1492,7 +1492,7 @@
$libraries['ui.widget'] = array(
'title' => 'jQuery UI: Widget',
'website' => 'http://docs.jquery.com/UI/Widget',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.ui.widget.min.js' => array('group' => JS_LIBRARY, 'weight' => -10),
),
@@ -1503,7 +1503,7 @@
$libraries['effects'] = array(
'title' => 'jQuery UI: Effects',
'website' => 'http://jqueryui.com/demos/effect/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.effects.core.min.js' => array('group' => JS_LIBRARY, 'weight' => -9),
),
@@ -1511,7 +1511,7 @@
$libraries['effects.blind'] = array(
'title' => 'jQuery UI: Effects Blind',
'website' => 'http://jqueryui.com/demos/effect/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.effects.blind.min.js' => array(),
),
@@ -1522,7 +1522,7 @@
$libraries['effects.bounce'] = array(
'title' => 'jQuery UI: Effects Bounce',
'website' => 'http://jqueryui.com/demos/effect/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.effects.bounce.min.js' => array(),
),
@@ -1533,7 +1533,7 @@
$libraries['effects.clip'] = array(
'title' => 'jQuery UI: Effects Clip',
'website' => 'http://jqueryui.com/demos/effect/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.effects.clip.min.js' => array(),
),
@@ -1544,7 +1544,7 @@
$libraries['effects.drop'] = array(
'title' => 'jQuery UI: Effects Drop',
'website' => 'http://jqueryui.com/demos/effect/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.effects.drop.min.js' => array(),
),
@@ -1555,7 +1555,7 @@
$libraries['effects.explode'] = array(
'title' => 'jQuery UI: Effects Explode',
'website' => 'http://jqueryui.com/demos/effect/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.effects.explode.min.js' => array(),
),
@@ -1566,7 +1566,7 @@
$libraries['effects.fade'] = array(
'title' => 'jQuery UI: Effects Fade',
'website' => 'http://jqueryui.com/demos/effect/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.effects.fade.min.js' => array(),
),
@@ -1577,7 +1577,7 @@
$libraries['effects.fold'] = array(
'title' => 'jQuery UI: Effects Fold',
'website' => 'http://jqueryui.com/demos/effect/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.effects.fold.min.js' => array(),
),
@@ -1588,7 +1588,7 @@
$libraries['effects.highlight'] = array(
'title' => 'jQuery UI: Effects Highlight',
'website' => 'http://jqueryui.com/demos/effect/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.effects.highlight.min.js' => array(),
),
@@ -1599,7 +1599,7 @@
$libraries['effects.pulsate'] = array(
'title' => 'jQuery UI: Effects Pulsate',
'website' => 'http://jqueryui.com/demos/effect/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.effects.pulsate.min.js' => array(),
),
@@ -1610,7 +1610,7 @@
$libraries['effects.scale'] = array(
'title' => 'jQuery UI: Effects Scale',
'website' => 'http://jqueryui.com/demos/effect/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.effects.scale.min.js' => array(),
),
@@ -1621,7 +1621,7 @@
$libraries['effects.shake'] = array(
'title' => 'jQuery UI: Effects Shake',
'website' => 'http://jqueryui.com/demos/effect/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.effects.shake.min.js' => array(),
),
@@ -1632,7 +1632,7 @@
$libraries['effects.slide'] = array(
'title' => 'jQuery UI: Effects Slide',
'website' => 'http://jqueryui.com/demos/effect/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.effects.slide.min.js' => array(),
),
@@ -1643,7 +1643,7 @@
$libraries['effects.transfer'] = array(
'title' => 'jQuery UI: Effects Transfer',
'website' => 'http://jqueryui.com/demos/effect/',
- 'version' => '1.8.7',
+ 'version' => $libraries['ui']['version'],
'js' => array(
'core/misc/ui/jquery.effects.transfer.min.js' => array(),
),
@@ -1651,15 +1651,6 @@
array('system', 'effects'),
),
);
-
- // These library names are deprecated. Earlier versions of Drupal 7 didn't
- // consistently namespace their libraries, so these names are included for
- // backwards compatibility with those versions.
- $libraries['once'] = &$libraries['jquery.once'];
- $libraries['form'] = &$libraries['jquery.form'];
- $libraries['jquery-bbq'] = &$libraries['jquery.bbq'];
- $libraries['vertical-tabs'] = &$libraries['drupal.vertical-tabs'];
- $libraries['cookie'] = &$libraries['jquery.cookie'];
return $libraries;
}
@@ -1979,21 +1970,23 @@
* Implements hook_form_FORM_ID_alter().
*/
function system_form_user_register_form_alter(&$form, &$form_state) {
- if (variable_get('configurable_timezones', 1)) {
- if (variable_get('user_default_timezone', DRUPAL_USER_TIMEZONE_DEFAULT) == DRUPAL_USER_TIMEZONE_SELECT) {
- system_user_timezone($form, $form_state);
- }
- else {
- $form['account']['timezone'] = array(
- '#type' => 'hidden',
- '#value' => variable_get('user_default_timezone', DRUPAL_USER_TIMEZONE_DEFAULT) ? '' : variable_get('date_default_timezone', ''),
- );
- }
+ if (variable_get('configurable_timezones', 1) && variable_get('user_default_timezone', DRUPAL_USER_TIMEZONE_DEFAULT) == DRUPAL_USER_TIMEZONE_SELECT) {
+ system_user_timezone($form, $form_state);
return $form;
}
}
/**
+ * Implements hook_user_insert().
+ */
+function system_user_presave(&$edit, $account) {
+ if (variable_get('configurable_timezones', 1) && empty($account->timezone) && !variable_get('user_default_timezone', DRUPAL_USER_TIMEZONE_DEFAULT)) {
+ $account->timezone = variable_get('date_default_timezone', '');
+ }
+}
+
+
+/**
* Implements hook_user_login().
*/
function system_user_login(&$edit, $account) {
diff --git a/core/modules/system/system.test b/core/modules/system/system.test
index 4e3761d..12797ed 100644
--- a/core/modules/system/system.test
+++ b/core/modules/system/system.test
@@ -379,10 +379,10 @@
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertText(t('Some required modules must be enabled'), t('Dependency required.'));
- $this->assertModules(array('translation', 'locale'), FALSE);
+ $this->assertModules(array('translation', 'locale', 'language'), FALSE);
// Assert that the locale tables weren't enabled.
- $this->assertTableCount('languages', FALSE);
+ $this->assertTableCount('language', FALSE);
$this->assertTableCount('locale', FALSE);
$this->drupalPost(NULL, NULL, t('Continue'));
@@ -391,7 +391,7 @@
$this->assertModules(array('translation', 'locale'), TRUE);
// Assert that the locale tables were enabled.
- $this->assertTableCount('languages', TRUE);
+ $this->assertTableCount('language', TRUE);
$this->assertTableCount('locale', TRUE);
}
@@ -1248,7 +1248,7 @@
'language' => 'de',
'default' => TRUE,
);
- locale_language_save($language);
+ language_save($language);
$date_format = array(
'type' => 'short',
diff --git a/core/modules/system/system.theme.css b/core/modules/system/system.theme.css
index 1993d17..7121813 100644
--- a/core/modules/system/system.theme.css
+++ b/core/modules/system/system.theme.css
@@ -294,6 +294,16 @@
.breadcrumb {
padding-bottom: 0.5em;
}
+.breadcrumb ol {
+ margin: 0;
+ padding: 0;
+}
+.breadcrumb li {
+ display: inline;
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+}
/**
* Markup generated by theme_menu_local_tasks().
diff --git a/core/modules/taxonomy/taxonomy.admin.inc b/core/modules/taxonomy/taxonomy.admin.inc
index 99114a6..8541b78 100644
--- a/core/modules/taxonomy/taxonomy.admin.inc
+++ b/core/modules/taxonomy/taxonomy.admin.inc
@@ -115,7 +115,7 @@
'name' => '',
'machine_name' => '',
'description' => '',
- 'hierarchy' => 0,
+ 'hierarchy' => TAXONOMY_HIERARCHY_DISABLED,
'weight' => 0,
);
foreach ($defaults as $key => $value) {
@@ -368,7 +368,7 @@
}
$form[$key]['view'] = array('#type' => 'link', '#title' => $term->name, '#href' => "taxonomy/term/$term->tid");
- if ($vocabulary->hierarchy < 2 && count($tree) > 1) {
+ if ($vocabulary->hierarchy != TAXONOMY_HIERARCHY_MULTIPLE && count($tree) > 1) {
$form['#parent_fields'] = TRUE;
$form[$key]['tid'] = array(
'#type' => 'hidden',
@@ -402,7 +402,7 @@
$form['#forward_step'] = $forward_step;
$form['#empty_text'] = t('No terms available. Add term.', array('@link' => url('admin/structure/taxonomy/' . $vocabulary->machine_name . '/add')));
- if ($vocabulary->hierarchy < 2 && count($tree) > 1) {
+ if ($vocabulary->hierarchy != TAXONOMY_HIERARCHY_MULTIPLE && count($tree) > 1) {
$form['actions'] = array('#type' => 'actions', '#tree' => FALSE);
$form['actions']['submit'] = array(
'#type' => 'submit',
@@ -449,7 +449,8 @@
uasort($form_state['values'], 'drupal_sort_weight');
$vocabulary = $form['#vocabulary'];
- $hierarchy = 0; // Update the current hierarchy type as we go.
+ // Update the current hierarchy type as we go.
+ $hierarchy = TAXONOMY_HIERARCHY_DISABLED;
$changed_terms = array();
$tree = taxonomy_get_tree($vocabulary->vid);
@@ -468,7 +469,7 @@
$changed_terms[$term['tid']] = $term;
}
$weight++;
- $hierarchy = $term['parents'][0] != 0 ? 1 : $hierarchy;
+ $hierarchy = $term['parents'][0] != 0 ? TAXONOMY_HIERARCHY_SINGLE : $hierarchy;
$term = (array) $tree[$weight];
}
@@ -495,7 +496,7 @@
$term['parent'] = $values['parent'];
$changed_terms[$term['tid']] = $term;
}
- $hierarchy = $term['parent'] != 0 ? 1 : $hierarchy;
+ $hierarchy = $term['parent'] != 0 ? TAXONOMY_HIERARCHY_SINGLE : $hierarchy;
$weight++;
}
}
@@ -508,7 +509,7 @@
$term['weight'] = $weight;
$changed_terms[$term['tid']] = $term;
}
- $hierarchy = $term['parents'][0] != 0 ? 1 : $hierarchy;
+ $hierarchy = $term['parents'][0] != 0 ? TAXONOMY_HIERARCHY_SINGLE : $hierarchy;
}
// Save all updated terms.
@@ -702,7 +703,7 @@
'#type' => 'fieldset',
'#title' => t('Relations'),
'#collapsible' => TRUE,
- '#collapsed' => $vocabulary->hierarchy < 2,
+ '#collapsed' => ($vocabulary->hierarchy != TAXONOMY_HIERARCHY_MULTIPLE),
'#weight' => 10,
);
@@ -840,8 +841,8 @@
}
// If we've increased the number of parents and this is a single or flat
// hierarchy, update the vocabulary immediately.
- elseif ($current_parent_count > $previous_parent_count && $form['#vocabulary']->hierarchy < 2) {
- $form['#vocabulary']->hierarchy = $current_parent_count == 1 ? 1 : 2;
+ elseif ($current_parent_count > $previous_parent_count && $form['#vocabulary']->hierarchy != TAXONOMY_HIERARCHY_MULTIPLE) {
+ $form['#vocabulary']->hierarchy = $current_parent_count == 1 ? TAXONOMY_HIERARCHY_SINGLE : TAXONOMY_HIERARCHY_MULTIPLE;
taxonomy_vocabulary_save($form['#vocabulary']);
}
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 191b519..581f440 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -6,6 +6,21 @@
*/
/**
+ * Denotes that no term in the vocabulary has a parent.
+ */
+const TAXONOMY_HIERARCHY_DISABLED = 0;
+
+/**
+ * Denotes that one or more terms in the vocabulary has a single parent.
+ */
+const TAXONOMY_HIERARCHY_SINGLE = 1;
+
+/**
+ * Denotes that one or more terms in the vocabulary have multiple parents.
+ */
+const TAXONOMY_HIERARCHY_MULTIPLE = 2;
+
+/**
* Users can create new terms in a free-tagging vocabulary when
* submitting a taxonomy_autocomplete_widget. We store a term object
* whose tid is 'autocreate' as a field data item during widget
@@ -51,11 +66,11 @@
case 'admin/structure/taxonomy/%':
$vocabulary = taxonomy_vocabulary_machine_name_load($arg[3]);
switch ($vocabulary->hierarchy) {
- case 0:
+ case TAXONOMY_HIERARCHY_DISABLED:
return '
' . t('You can reorganize the terms in %capital_name using their drag-and-drop handles, and group terms under a parent term by sliding them under and to the right of the parent.', array('%capital_name' => drupal_ucfirst($vocabulary->name), '%name' => $vocabulary->name)) . '
';
- case 1:
+ case TAXONOMY_HIERARCHY_SINGLE:
return '
' . t('%capital_name contains terms grouped under parent terms. You can reorganize the terms in %capital_name using their drag-and-drop handles.', array('%capital_name' => drupal_ucfirst($vocabulary->name), '%name' => $vocabulary->name)) . '
';
- case 2:
+ case TAXONOMY_HIERARCHY_MULTIPLE:
return '
' . t('%capital_name contains terms with multiple parents. Drag and drop of terms with multiple parents is not supported, but you can re-enable drag-and-drop support by editing each term to include only a single parent.', array('%capital_name' => drupal_ucfirst($vocabulary->name))) . '
';
}
}
@@ -295,7 +310,9 @@
$items['taxonomy/term/%taxonomy_term/edit'] = array(
'title' => 'Edit',
'page callback' => 'drupal_get_form',
- 'page arguments' => array('taxonomy_form_term', 2),
+ // Pass a NULL argument to ensure that additional path components are not
+ // passed to taxonomy_form_term() as the vocabulary machine name argument.
+ 'page arguments' => array('taxonomy_form_term', 2, NULL),
'access callback' => 'taxonomy_term_edit_access',
'access arguments' => array(2),
'type' => MENU_LOCAL_TASK,
@@ -422,6 +439,7 @@
if (!empty($vocabulary->vid) && !empty($vocabulary->name)) {
$status = drupal_write_record('taxonomy_vocabulary', $vocabulary, 'vid');
+ taxonomy_vocabulary_static_reset(array($vocabulary->vid));
if ($vocabulary->old_machine_name != $vocabulary->machine_name) {
field_attach_rename_bundle('taxonomy_term', $vocabulary->old_machine_name, $vocabulary->machine_name);
}
@@ -430,6 +448,7 @@
}
elseif (empty($vocabulary->vid)) {
$status = drupal_write_record('taxonomy_vocabulary', $vocabulary);
+ taxonomy_vocabulary_static_reset();
field_attach_create_bundle('taxonomy_term', $vocabulary->machine_name);
module_invoke_all('taxonomy_vocabulary_insert', $vocabulary);
module_invoke_all('entity_insert', $vocabulary, 'taxonomy_vocabulary');
@@ -437,7 +456,6 @@
unset($vocabulary->original);
cache_clear_all();
- taxonomy_vocabulary_static_reset(array($vocabulary->vid));
return $status;
}
@@ -519,10 +537,11 @@
*
* Checks the current parents of all terms in a vocabulary and updates the
* vocabulary's hierarchy setting to the lowest possible level. If no term
- * has parent terms then the vocabulary will be given a hierarchy of 0.
- * If any term has a single parent then the vocabulary will be given a
- * hierarchy of 1. If any term has multiple parents then the vocabulary
- * will be given a hierarchy of 2.
+ * has parent terms then the vocabulary will be given a hierarchy of
+ * TAXONOMY_HIERARCHY_DISABLED. If any term has a single parent then the
+ * vocabulary will be given a hierarchy of TAXONOMY_HIERARCHY_SINGLE. If any
+ * term has multiple parents then the vocabulary will be given a hierarchy of
+ * TAXONOMY_HIERARCHY_MULTIPLE.
*
* @param $vocabulary
* A vocabulary object.
@@ -534,7 +553,7 @@
*/
function taxonomy_check_vocabulary_hierarchy($vocabulary, $changed_term) {
$tree = taxonomy_get_tree($vocabulary->vid);
- $hierarchy = 0;
+ $hierarchy = TAXONOMY_HIERARCHY_DISABLED;
foreach ($tree as $term) {
// Update the changed term with the new parent value before comparison.
if ($term->tid == $changed_term['tid']) {
@@ -543,11 +562,11 @@
}
// Check this term's parent count.
if (count($term->parents) > 1) {
- $hierarchy = 2;
+ $hierarchy = TAXONOMY_HIERARCHY_MULTIPLE;
break;
}
elseif (count($term->parents) == 1 && 0 !== array_shift($term->parents)) {
- $hierarchy = 1;
+ $hierarchy = TAXONOMY_HIERARCHY_SINGLE;
}
}
if ($hierarchy != $vocabulary->hierarchy) {
@@ -1084,12 +1103,25 @@
*
* @param $name
* Name of the term to search for.
+ * @param $vocabulary
+ * (optional) Vocabulary machine name to limit the search. Defaults to NULL.
*
* @return
* An array of matching term objects.
*/
-function taxonomy_get_term_by_name($name) {
- return taxonomy_term_load_multiple(array(), array('name' => trim($name)));
+function taxonomy_get_term_by_name($name, $vocabulary = NULL) {
+ $conditions = array('name' => trim($name));
+ if (isset($vocabulary)) {
+ $vocabularies = taxonomy_vocabulary_get_names();
+ if (isset($vocabularies[$vocabulary])){
+ $conditions['vid'] = $vocabularies[$vocabulary]->vid;
+ }
+ else {
+ // Return an empty array when filtering by a non-existing vocabulary.
+ return array();
+ }
+ }
+ return taxonomy_term_load_multiple(array(), $conditions);
}
/**
@@ -1210,6 +1242,8 @@
* @return
* The vocabulary object with all of its metadata, if exists, FALSE otherwise.
* Results are statically cached.
+ *
+ * @see taxonomy_vocabulary_machine_name_load()
*/
function taxonomy_vocabulary_load($vid) {
$vocabularies = taxonomy_vocabulary_load_multiple(array($vid));
@@ -1225,6 +1259,8 @@
* @return
* The vocabulary object with all of its metadata, if exists, FALSE otherwise.
* Results are statically cached.
+ *
+ * @see taxonomy_vocabulary_load()
*/
function taxonomy_vocabulary_machine_name_load($name) {
$vocabularies = taxonomy_vocabulary_load_multiple(NULL, array('machine_name' => $name));
diff --git a/core/modules/taxonomy/taxonomy.test b/core/modules/taxonomy/taxonomy.test
index 3e6301a..b992903 100644
--- a/core/modules/taxonomy/taxonomy.test
+++ b/core/modules/taxonomy/taxonomy.test
@@ -343,9 +343,15 @@
field_create_instance($instance);
// Change the machine name.
+ $old_name = $this->vocabulary->machine_name;
$new_name = drupal_strtolower($this->randomName());
$this->vocabulary->machine_name = $new_name;
taxonomy_vocabulary_save($this->vocabulary);
+
+ // Check that entity bundles are properly updated.
+ $info = entity_get_info('taxonomy_term');
+ $this->assertFalse(isset($info['bundles'][$old_name]), t('The old bundle name does not appear in entity_get_info().'));
+ $this->assertTrue(isset($info['bundles'][$new_name]), t('The new bundle name appears in entity_get_info().'));
// Check that the field instance is still attached to the vocabulary.
$this->assertTrue(field_info_instance('taxonomy_term', 'field_test', $new_name), t('The bundle name was updated correctly.'));
@@ -579,9 +585,9 @@
$instance['bundle'] = 'page';
field_create_instance($instance);
$terms = array(
- $this->randomName(),
- $this->randomName() . ', ' . $this->randomName(),
- $this->randomName(),
+ 'term1' => $this->randomName(),
+ 'term2' => $this->randomName() . ', ' . $this->randomName(),
+ 'term3' => $this->randomName(),
);
$edit = array();
@@ -611,33 +617,37 @@
}
// Get the created terms.
- list($term1, $term2, $term3) = array_values(taxonomy_term_load_multiple(FALSE));
+ $term_objects = array();
+ foreach ($terms as $key => $term) {
+ $term_objects[$key] = taxonomy_get_term_by_name($term);
+ $term_objects[$key] = reset($term_objects[$key]);
+ }
// Delete term 1.
- $this->drupalPost('taxonomy/term/' . $term1->tid . '/edit', array(), t('Delete'));
+ $this->drupalPost('taxonomy/term/' . $term_objects['term1']->tid . '/edit', array(), t('Delete'));
$this->drupalPost(NULL, NULL, t('Delete'));
- $term_names = array($term2->name, $term3->name);
+ $term_names = array($term_objects['term2']->name, $term_objects['term3']->name);
// Get the node.
$node = $this->drupalGetNodeByTitle($edit["title"]);
$this->drupalGet('node/' . $node->nid);
foreach ($term_names as $term_name) {
- $this->assertText($term_name, t('The term %name appears on the node page after one term %deleted was deleted', array('%name' => $term_name, '%deleted' => $term1->name)));
+ $this->assertText($term_name, t('The term %name appears on the node page after one term %deleted was deleted', array('%name' => $term_name, '%deleted' => $term_objects['term1']->name)));
}
- $this->assertNoText($term1->name, t('The deleted term %name does not appear on the node page.', array('%name' => $term1->name)));
+ $this->assertNoText($term_objects['term1']->name, t('The deleted term %name does not appear on the node page.', array('%name' => $term_objects['term1']->name)));
// Test autocomplete on term 2, which contains a comma.
// The term will be quoted, and the " will be encoded in unicode (\u0022).
- $input = substr($term2->name, 0, 3);
+ $input = substr($term_objects['term2']->name, 0, 3);
$this->drupalGet('taxonomy/autocomplete/taxonomy_' . $this->vocabulary->machine_name . '/' . $input);
- $this->assertRaw('{"\u0022' . $term2->name . '\u0022":"' . $term2->name . '"}', t('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term2->name)));
+ $this->assertRaw('{"\u0022' . $term_objects['term2']->name . '\u0022":"' . $term_objects['term2']->name . '"}', t('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term_objects['term2']->name)));
// Test autocomplete on term 3 - it is alphanumeric only, so no extra
// quoting.
- $input = substr($term3->name, 0, 3);
+ $input = substr($term_objects['term3']->name, 0, 3);
$this->drupalGet('taxonomy/autocomplete/taxonomy_' . $this->vocabulary->machine_name . '/' . $input);
- $this->assertRaw('{"' . $term3->name . '":"' . $term3->name . '"}', t('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term3->name)));
+ $this->assertRaw('{"' . $term_objects['term3']->name . '":"' . $term_objects['term3']->name . '"}', t('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term_objects['term3']->name)));
}
/**
@@ -698,6 +708,10 @@
// Check that the term feed page is working.
$this->drupalGet('taxonomy/term/' . $term->tid . '/feed');
+
+ // Check that the term edit page does not try to interpret additional path
+ // components as arguments for taxonomy_form_term().
+ $this->drupalGet('taxonomy/term/' . $term->tid . '/edit/' . $this->randomName());
// Delete the term.
$this->drupalPost('taxonomy/term/' . $term->tid . '/edit', array(), t('Delete'));
@@ -825,6 +839,34 @@
// Try to load the term using a substring of the name.
$terms = taxonomy_get_term_by_name(drupal_substr($term->name, 2));
$this->assertFalse($terms);
+
+ // Create a new term in a different vocabulary with the same name.
+ $new_vocabulary = $this->createVocabulary();
+ $new_term = new stdClass();
+ $new_term->name = $term->name;
+ $new_term->vid = $new_vocabulary->vid;
+ taxonomy_term_save($new_term);
+
+ // Load multiple terms with the same name.
+ $terms = taxonomy_get_term_by_name($term->name);
+ $this->assertEqual(count($terms), 2, t('Two terms loaded with the same name.'));
+
+ // Load single term when restricted to one vocabulary.
+ $terms = taxonomy_get_term_by_name($term->name, $this->vocabulary->machine_name);
+ $this->assertEqual(count($terms), 1, t('One term loaded when restricted by vocabulary.'));
+ $this->assertTrue(isset($terms[$term->tid]), t('Term loaded using exact name and vocabulary machine name.'));
+
+ // Create a new term with another name.
+ $term2 = $this->createTerm($this->vocabulary);
+
+ // Try to load a term by name that doesn't exist in this vocabulary but
+ // exists in another vocabulary.
+ $terms = taxonomy_get_term_by_name($term2->name, $new_vocabulary->machine_name);
+ $this->assertFalse($terms, t('Invalid term name restricted by vocabulary machine name not loaded.'));
+
+ // Try to load terms filtering by a non-existing vocabulary.
+ $terms = taxonomy_get_term_by_name($term2->name, 'non_existing_vocabulary');
+ $this->assertEqual(count($terms), 0, t('No terms loaded when restricted by a non-existing vocabulary.'));
}
}
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index d25ca2d..5151966 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -65,7 +65,11 @@
}
/**
- * Menu callback; toggles the visibility of the toolbar drawer.
+ * Page callback: Toggles the visibility of the toolbar drawer.
+ *
+ * Path: toolbar/toggle
+ *
+ * @see toolbar_menu().
*/
function toolbar_toggle_page() {
global $base_path;
@@ -82,6 +86,7 @@
* An associative array containing:
* - collapsed: A boolean value representing the toolbar drawer's visibility.
* - attributes: An associative array of HTML attributes.
+ *
* @return
* An HTML string representing the element for toggling.
*
@@ -124,10 +129,12 @@
}
/**
- * Prerender function for the toolbar.
+ * Provides pre_render function for the toolbar.
*
* Since building the toolbar takes some time, it is done just prior to
* rendering to ensure that it is built only if it will be displayed.
+ *
+ * @see toolbar_page_build().
*/
function toolbar_pre_render($toolbar) {
$toolbar = array_merge($toolbar, toolbar_view());
@@ -175,7 +182,10 @@
}
/**
- * Build the admin menu as a structured array ready for drupal_render().
+ * Builds the admin menu as a structured array ready for drupal_render().
+ *
+ * @return
+ * Array of links and settings relating to the admin menu.
*/
function toolbar_view() {
global $user;
@@ -273,7 +283,10 @@
}
/**
- * Get only the top level items below the 'admin' path.
+ * Gets only the top level items below the 'admin' path.
+ *
+ * @return
+ * An array containing a menu tree of top level items below the 'admin' path.
*/
function toolbar_get_menu_tree() {
$tree = array();
@@ -290,10 +303,13 @@
}
/**
- * Generate a links array from a menu tree array.
+ * Generates an array of links from a menu tree array.
*
* Based on menu_navigation_links(). Adds path based IDs and icon placeholders
* to the links.
+ *
+ * @return
+ * An array of links as defined above.
*/
function toolbar_menu_navigation_links($tree) {
$links = array();
@@ -331,6 +347,9 @@
* Useful when using a menu generated by menu_tree_all_data() which does
* not set the 'in_active_trail' flag on items.
*
+ * @return
+ * TRUE when path is in the active trail, FALSE if not.
+ *
* @todo
* Look at migrating to a menu system level function.
*/
diff --git a/core/modules/tracker/tracker.module b/core/modules/tracker/tracker.module
index 89907b5..3e2207d 100644
--- a/core/modules/tracker/tracker.module
+++ b/core/modules/tracker/tracker.module
@@ -1,370 +1,370 @@
-' . t('About') . '';
- $output .= '
' . t('The Tracker module displays the most recently added and updated content on your site, and allows you to follow new content created by each user. This module has no configuration options. For more information, see the online handbook entry for Tracker module.', array('@tracker' => 'http://drupal.org/handbook/modules/tracker/')) . '
';
- $output .= '
' . t('Uses') . '
';
- $output .= '
';
- $output .= '
' . t('Navigation') . '
';
- $output .= '
' . t('The Tracker module adds a new menu item to the Navigation menu, called Recent content. You can configure menu items via the Menus administration page.', array('@menus' => url('admin/structure/menu'))) . '
';
- $output .= '
' . t('Tracking new and updated site content') . '
';
- $output .= '
' . t("The Recent content page shows new and updated content in reverse chronological order, listing the content type, title, author's name, number of comments, and time of last update. Content is considered updated when changes occur in the text, or when new comments are added. The My recent content tab limits the list to the currently logged-in user.", array('@recent' => url('tracker'))) . '
';
- $output .= '
' . t('Tracking user-specific content') . '
';
- $output .= '
' . t("To follow a specific user's new and updated content, select the Track tab from the user's profile page.") . '
';
- $output .= '
';
- return $output;
- }
-}
-
-/**
- * Implements hook_menu().
- */
-function tracker_menu() {
- $items['tracker'] = array(
- 'title' => 'Recent content',
- 'page callback' => 'tracker_page',
- 'access arguments' => array('access content'),
- 'weight' => 1,
- 'file' => 'tracker.pages.inc',
- );
- $items['tracker/all'] = array(
- 'title' => 'All recent content',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['tracker/%user_uid_optional'] = array(
- 'title' => 'My recent content',
- 'page callback' => 'tracker_page',
- 'access callback' => '_tracker_myrecent_access',
- 'access arguments' => array(1),
- 'page arguments' => array(1),
- 'type' => MENU_LOCAL_TASK,
- 'file' => 'tracker.pages.inc',
- );
-
- $items['user/%user/track'] = array(
- 'title' => 'Track',
- 'page callback' => 'tracker_page',
- 'page arguments' => array(1, TRUE),
- 'access callback' => '_tracker_user_access',
- 'access arguments' => array(1),
- 'type' => MENU_LOCAL_TASK,
- 'file' => 'tracker.pages.inc',
- );
- $items['user/%user/track/content'] = array(
- 'title' => 'Track content',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
-
- return $items;
-}
-
-/**
- * Implements hook_cron().
- */
-function tracker_cron() {
- $max_nid = variable_get('tracker_index_nid', 0);
- $batch_size = variable_get('tracker_batch_size', 1000);
- if ($max_nid > 0) {
- $last_nid = FALSE;
- $result = db_query_range('SELECT nid, uid, status FROM {node} WHERE nid <= :max_nid ORDER BY nid DESC', 0, $batch_size, array(':max_nid' => $max_nid), array('target' => 'slave'));
-
- $count = 0;
-
- foreach ($result as $row) {
- // Calculate the changed timestamp for this node.
- $changed = _tracker_calculate_changed($row->nid);
-
- // Remove existing data for this node.
- db_delete('tracker_node')
- ->condition('nid', $row->nid)
- ->execute();
- db_delete('tracker_user')
- ->condition('nid', $row->nid)
- ->execute();
-
- // Insert the node-level data.
- db_insert('tracker_node')
- ->fields(array(
- 'nid' => $row->nid,
- 'published' => $row->status,
- 'changed' => $changed,
- ))
- ->execute();
-
- // Insert the user-level data for the node's author.
- db_insert('tracker_user')
- ->fields(array(
- 'nid' => $row->nid,
- 'published' => $row->status,
- 'changed' => $changed,
- 'uid' => $row->uid,
- ))
- ->execute();
-
- $query = db_select('comment', 'c', array('target' => 'slave'));
- // Force PostgreSQL to do an implicit cast by adding 0.
- $query->addExpression('0 + :changed', 'changed', array(':changed' => $changed));
- $query->addField('c', 'status', 'published');
- $query
- ->distinct()
- ->fields('c', array('uid', 'nid'))
- ->condition('c.nid', $row->nid)
- ->condition('c.uid', $row->uid, '<>')
- ->condition('c.status', COMMENT_PUBLISHED);
-
- // Insert the user-level data for the commenters (except if a commenter
- // is the node's author).
- db_insert('tracker_user')
- ->from($query)
- ->execute();
-
- // Note that we have indexed at least one node.
- $last_nid = $row->nid;
-
- $count++;
- }
-
- if ($last_nid !== FALSE) {
- // Prepare a starting point for the next run.
- variable_set('tracker_index_nid', $last_nid - 1);
-
- watchdog('tracker', 'Indexed %count content items for tracking.', array('%count' => $count));
- }
- else {
- // If all nodes have been indexed, set to zero to skip future cron runs.
- variable_set('tracker_index_nid', 0);
- }
- }
-}
-
-/**
- * Access callback for tracker/%user_uid_optional.
- */
-function _tracker_myrecent_access($account) {
- // This path is only allowed for authenticated users looking at their own content.
- return $account->uid && ($GLOBALS['user']->uid == $account->uid) && user_access('access content');
-}
-
-/**
- * Access callback for user/%user/track.
- */
-function _tracker_user_access($account) {
- return user_view_access($account) && user_access('access content');
-}
-
-/**
- * Implements hook_node_insert().
- */
-function tracker_node_insert($node, $arg = 0) {
- _tracker_add($node->nid, $node->uid, $node->changed);
-}
-
-/**
- * Implements hook_node_update().
- */
-function tracker_node_update($node, $arg = 0) {
- _tracker_add($node->nid, $node->uid, $node->changed);
-}
-
-/**
- * Implements hook_node_predelete().
- */
-function tracker_node_predelete($node, $arg = 0) {
- db_delete('tracker_node')
- ->condition('nid', $node->nid)
- ->execute();
- db_delete('tracker_user')
- ->condition('nid', $node->nid)
- ->execute();
-}
-
-/**
- * Implements hook_comment_update().
- *
- * Comment module doesn't call hook_comment_unpublish() when saving individual
- * comments so we need to check for those here.
- */
-function tracker_comment_update($comment) {
- // comment_save() calls hook_comment_publish() for all published comments
- // so we to handle all other values here.
- if ($comment->status != COMMENT_PUBLISHED) {
- _tracker_remove($comment->nid, $comment->uid, $comment->changed);
- }
-}
-
-/**
- * Implements hook_comment_publish().
- *
- * This actually handles the insert and update of published nodes since
- * comment_save() calls hook_comment_publish() for all published comments.
- */
-function tracker_comment_publish($comment) {
- _tracker_add($comment->nid, $comment->uid, $comment->changed);
-}
-
-/**
- * Implements hook_comment_unpublish().
- */
-function tracker_comment_unpublish($comment) {
- _tracker_remove($comment->nid, $comment->uid, $comment->changed);
-}
-
-/**
- * Implements hook_comment_delete().
- */
-function tracker_comment_delete($comment) {
- _tracker_remove($comment->nid, $comment->uid, $comment->changed);
-}
-
-/**
- * Update indexing tables when a node is added, updated or commented on.
- *
- * @param $nid
- * A node ID.
- * @param $uid
- * The node or comment author.
- * @param $changed
- * The node updated timestamp or comment timestamp.
- */
-function _tracker_add($nid, $uid, $changed) {
- $node = db_query('SELECT nid, status, uid, changed FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject();
-
- // Adding a comment can only increase the changed timestamp, so our
- // calculation here is simple.
- $changed = max($node->changed, $changed);
-
- // Update the node-level data.
- db_merge('tracker_node')
- ->key(array('nid' => $nid))
- ->fields(array(
- 'changed' => $changed,
- 'published' => $node->status,
- ))
- ->execute();
-
- // Create or update the user-level data.
- db_merge('tracker_user')
- ->key(array(
- 'nid' => $nid,
- 'uid' => $uid,
- ))
- ->fields(array(
- 'changed' => $changed,
- 'published' => $node->status,
- ))
- ->execute();
-}
-
-/**
- * Determine the max timestamp between $node->changed and the last comment.
- *
- * @param $nid
- * A node ID.
- *
- * @return
- * The $node->changed timestamp, or most recent comment timestamp, whichever
- * is the greatest.
- */
-function _tracker_calculate_changed($nid) {
- $changed = db_query('SELECT changed FROM {node} WHERE nid = :nid', array(':nid' => $nid), array('target' => 'slave'))->fetchField();
- $latest_comment = db_query_range('SELECT cid, changed FROM {comment} WHERE nid = :nid AND status = :status ORDER BY changed DESC', 0, 1, array(
- ':nid' => $nid,
- ':status' => COMMENT_PUBLISHED,
- ), array('target' => 'slave'))->fetchObject();
- if ($latest_comment && $latest_comment->changed > $changed) {
- $changed = $latest_comment->changed;
- }
- return $changed;
-}
-
-/**
- * Clean up indexed data when nodes or comments are removed.
- *
- * @param $nid
- * The node ID.
- * @param $uid
- * The author of the node or comment.
- * @param $changed
- * The last changed timestamp of the node.
- */
-function _tracker_remove($nid, $uid = NULL, $changed = NULL) {
- $node = db_query('SELECT nid, status, uid, changed FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject();
-
- // The user only keeps his or her subscription if both of the following are true:
- // (1) The node exists.
- // (2) The user is either the node author or has commented on the node.
- $keep_subscription = FALSE;
-
- if ($node) {
- // Self-authorship is one reason to keep the user's subscription.
- $keep_subscription = ($node->uid == $uid);
-
- // Comments are a second reason to keep the user's subscription.
- if (!$keep_subscription) {
- // Check if the user has commented at least once on the given nid
- $keep_subscription = db_query_range('SELECT COUNT(*) FROM {comment} WHERE nid = :nid AND uid = :uid AND status = :status', 0, 1, array(
- ':nid' => $nid,
- ':uid' => $uid,
- ':status' => COMMENT_PUBLISHED,
- ))->fetchField();
- }
-
- // If we haven't found a reason to keep the user's subscription, delete it.
- if (!$keep_subscription) {
- db_delete('tracker_user')
- ->condition('nid', $nid)
- ->condition('uid', $uid)
- ->execute();
- }
-
- // Now we need to update the (possibly) changed timestamps for other users
- // and the node itself.
-
- // We only need to do this if the removed item has a timestamp that equals
- // or exceeds the listed changed timestamp for the node
- $tracker_node = db_query('SELECT nid, changed FROM {tracker_node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject();
- if ($tracker_node && $changed >= $tracker_node->changed) {
- // If we're here, the item being removed is *possibly* the item that
- // established the node's changed timestamp.
-
- // We just have to recalculate things from scratch.
- $changed = _tracker_calculate_changed($nid);
-
- // And then we push the out the new changed timestamp to our denormalized
- // tables.
- db_update('tracker_node')
- ->fields(array(
- 'changed' => $changed,
- 'published' => $node->status,
- ))
- ->condition('nid', $nid)
- ->execute();
- db_update('tracker_node')
- ->fields(array(
- 'changed' => $changed,
- 'published' => $node->status,
- ))
- ->condition('nid', $nid)
- ->execute();
- }
- }
- else {
- // If the node doesn't exist, remove everything.
- db_delete('tracker_node')
- ->condition('nid', $nid)
- ->execute();
- db_delete('tracker_user')
- ->condition('nid', $nid)
- ->execute();
- }
-}
+' . t('About') . '';
+ $output .= '
' . t('The Tracker module displays the most recently added and updated content on your site, and allows you to follow new content created by each user. This module has no configuration options. For more information, see the online handbook entry for Tracker module.', array('@tracker' => 'http://drupal.org/handbook/modules/tracker/')) . '
';
+ $output .= '
' . t('Uses') . '
';
+ $output .= '
';
+ $output .= '
' . t('Navigation') . '
';
+ $output .= '
' . t('The Tracker module adds a new menu item to the Navigation menu, called Recent content. You can configure menu items via the Menus administration page.', array('@menus' => url('admin/structure/menu'))) . '
';
+ $output .= '
' . t('Tracking new and updated site content') . '
';
+ $output .= '
' . t("The Recent content page shows new and updated content in reverse chronological order, listing the content type, title, author's name, number of comments, and time of last update. Content is considered updated when changes occur in the text, or when new comments are added. The My recent content tab limits the list to the currently logged-in user.", array('@recent' => url('tracker'))) . '
';
+ $output .= '
' . t('Tracking user-specific content') . '
';
+ $output .= '
' . t("To follow a specific user's new and updated content, select the Activity tab from the user's profile page.") . '
';
+ $output .= '
';
+ return $output;
+ }
+}
+
+/**
+ * Implements hook_menu().
+ */
+function tracker_menu() {
+ $items['tracker'] = array(
+ 'title' => 'Recent content',
+ 'page callback' => 'tracker_page',
+ 'access arguments' => array('access content'),
+ 'weight' => 1,
+ 'file' => 'tracker.pages.inc',
+ );
+ $items['tracker/all'] = array(
+ 'title' => 'All recent content',
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ );
+ $items['tracker/%user_uid_optional'] = array(
+ 'title' => 'My recent content',
+ 'page callback' => 'tracker_page',
+ 'access callback' => '_tracker_myrecent_access',
+ 'access arguments' => array(1),
+ 'page arguments' => array(1),
+ 'type' => MENU_LOCAL_TASK,
+ 'file' => 'tracker.pages.inc',
+ );
+
+ $items['user/%user/track'] = array(
+ 'title' => 'Activity',
+ 'page callback' => 'tracker_page',
+ 'page arguments' => array(1, TRUE),
+ 'access callback' => '_tracker_user_access',
+ 'access arguments' => array(1),
+ 'type' => MENU_LOCAL_TASK,
+ 'file' => 'tracker.pages.inc',
+ );
+ $items['user/%user/track/content'] = array(
+ 'title' => 'Track content',
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ );
+
+ return $items;
+}
+
+/**
+ * Implements hook_cron().
+ */
+function tracker_cron() {
+ $max_nid = variable_get('tracker_index_nid', 0);
+ $batch_size = variable_get('tracker_batch_size', 1000);
+ if ($max_nid > 0) {
+ $last_nid = FALSE;
+ $result = db_query_range('SELECT nid, uid, status FROM {node} WHERE nid <= :max_nid ORDER BY nid DESC', 0, $batch_size, array(':max_nid' => $max_nid), array('target' => 'slave'));
+
+ $count = 0;
+
+ foreach ($result as $row) {
+ // Calculate the changed timestamp for this node.
+ $changed = _tracker_calculate_changed($row->nid);
+
+ // Remove existing data for this node.
+ db_delete('tracker_node')
+ ->condition('nid', $row->nid)
+ ->execute();
+ db_delete('tracker_user')
+ ->condition('nid', $row->nid)
+ ->execute();
+
+ // Insert the node-level data.
+ db_insert('tracker_node')
+ ->fields(array(
+ 'nid' => $row->nid,
+ 'published' => $row->status,
+ 'changed' => $changed,
+ ))
+ ->execute();
+
+ // Insert the user-level data for the node's author.
+ db_insert('tracker_user')
+ ->fields(array(
+ 'nid' => $row->nid,
+ 'published' => $row->status,
+ 'changed' => $changed,
+ 'uid' => $row->uid,
+ ))
+ ->execute();
+
+ $query = db_select('comment', 'c', array('target' => 'slave'));
+ // Force PostgreSQL to do an implicit cast by adding 0.
+ $query->addExpression('0 + :changed', 'changed', array(':changed' => $changed));
+ $query->addField('c', 'status', 'published');
+ $query
+ ->distinct()
+ ->fields('c', array('uid', 'nid'))
+ ->condition('c.nid', $row->nid)
+ ->condition('c.uid', $row->uid, '<>')
+ ->condition('c.status', COMMENT_PUBLISHED);
+
+ // Insert the user-level data for the commenters (except if a commenter
+ // is the node's author).
+ db_insert('tracker_user')
+ ->from($query)
+ ->execute();
+
+ // Note that we have indexed at least one node.
+ $last_nid = $row->nid;
+
+ $count++;
+ }
+
+ if ($last_nid !== FALSE) {
+ // Prepare a starting point for the next run.
+ variable_set('tracker_index_nid', $last_nid - 1);
+
+ watchdog('tracker', 'Indexed %count content items for tracking.', array('%count' => $count));
+ }
+ else {
+ // If all nodes have been indexed, set to zero to skip future cron runs.
+ variable_set('tracker_index_nid', 0);
+ }
+ }
+}
+
+/**
+ * Access callback for tracker/%user_uid_optional.
+ */
+function _tracker_myrecent_access($account) {
+ // This path is only allowed for authenticated users looking at their own content.
+ return $account->uid && ($GLOBALS['user']->uid == $account->uid) && user_access('access content');
+}
+
+/**
+ * Access callback for user/%user/track.
+ */
+function _tracker_user_access($account) {
+ return user_view_access($account) && user_access('access content');
+}
+
+/**
+ * Implements hook_node_insert().
+ */
+function tracker_node_insert($node, $arg = 0) {
+ _tracker_add($node->nid, $node->uid, $node->changed);
+}
+
+/**
+ * Implements hook_node_update().
+ */
+function tracker_node_update($node, $arg = 0) {
+ _tracker_add($node->nid, $node->uid, $node->changed);
+}
+
+/**
+ * Implements hook_node_predelete().
+ */
+function tracker_node_predelete($node, $arg = 0) {
+ db_delete('tracker_node')
+ ->condition('nid', $node->nid)
+ ->execute();
+ db_delete('tracker_user')
+ ->condition('nid', $node->nid)
+ ->execute();
+}
+
+/**
+ * Implements hook_comment_update().
+ *
+ * Comment module doesn't call hook_comment_unpublish() when saving individual
+ * comments so we need to check for those here.
+ */
+function tracker_comment_update($comment) {
+ // comment_save() calls hook_comment_publish() for all published comments
+ // so we to handle all other values here.
+ if ($comment->status != COMMENT_PUBLISHED) {
+ _tracker_remove($comment->nid, $comment->uid, $comment->changed);
+ }
+}
+
+/**
+ * Implements hook_comment_publish().
+ *
+ * This actually handles the insert and update of published nodes since
+ * comment_save() calls hook_comment_publish() for all published comments.
+ */
+function tracker_comment_publish($comment) {
+ _tracker_add($comment->nid, $comment->uid, $comment->changed);
+}
+
+/**
+ * Implements hook_comment_unpublish().
+ */
+function tracker_comment_unpublish($comment) {
+ _tracker_remove($comment->nid, $comment->uid, $comment->changed);
+}
+
+/**
+ * Implements hook_comment_delete().
+ */
+function tracker_comment_delete($comment) {
+ _tracker_remove($comment->nid, $comment->uid, $comment->changed);
+}
+
+/**
+ * Update indexing tables when a node is added, updated or commented on.
+ *
+ * @param $nid
+ * A node ID.
+ * @param $uid
+ * The node or comment author.
+ * @param $changed
+ * The node updated timestamp or comment timestamp.
+ */
+function _tracker_add($nid, $uid, $changed) {
+ $node = db_query('SELECT nid, status, uid, changed FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject();
+
+ // Adding a comment can only increase the changed timestamp, so our
+ // calculation here is simple.
+ $changed = max($node->changed, $changed);
+
+ // Update the node-level data.
+ db_merge('tracker_node')
+ ->key(array('nid' => $nid))
+ ->fields(array(
+ 'changed' => $changed,
+ 'published' => $node->status,
+ ))
+ ->execute();
+
+ // Create or update the user-level data.
+ db_merge('tracker_user')
+ ->key(array(
+ 'nid' => $nid,
+ 'uid' => $uid,
+ ))
+ ->fields(array(
+ 'changed' => $changed,
+ 'published' => $node->status,
+ ))
+ ->execute();
+}
+
+/**
+ * Determine the max timestamp between $node->changed and the last comment.
+ *
+ * @param $nid
+ * A node ID.
+ *
+ * @return
+ * The $node->changed timestamp, or most recent comment timestamp, whichever
+ * is the greatest.
+ */
+function _tracker_calculate_changed($nid) {
+ $changed = db_query('SELECT changed FROM {node} WHERE nid = :nid', array(':nid' => $nid), array('target' => 'slave'))->fetchField();
+ $latest_comment = db_query_range('SELECT cid, changed FROM {comment} WHERE nid = :nid AND status = :status ORDER BY changed DESC', 0, 1, array(
+ ':nid' => $nid,
+ ':status' => COMMENT_PUBLISHED,
+ ), array('target' => 'slave'))->fetchObject();
+ if ($latest_comment && $latest_comment->changed > $changed) {
+ $changed = $latest_comment->changed;
+ }
+ return $changed;
+}
+
+/**
+ * Clean up indexed data when nodes or comments are removed.
+ *
+ * @param $nid
+ * The node ID.
+ * @param $uid
+ * The author of the node or comment.
+ * @param $changed
+ * The last changed timestamp of the node.
+ */
+function _tracker_remove($nid, $uid = NULL, $changed = NULL) {
+ $node = db_query('SELECT nid, status, uid, changed FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject();
+
+ // The user only keeps his or her subscription if both of the following are true:
+ // (1) The node exists.
+ // (2) The user is either the node author or has commented on the node.
+ $keep_subscription = FALSE;
+
+ if ($node) {
+ // Self-authorship is one reason to keep the user's subscription.
+ $keep_subscription = ($node->uid == $uid);
+
+ // Comments are a second reason to keep the user's subscription.
+ if (!$keep_subscription) {
+ // Check if the user has commented at least once on the given nid
+ $keep_subscription = db_query_range('SELECT COUNT(*) FROM {comment} WHERE nid = :nid AND uid = :uid AND status = :status', 0, 1, array(
+ ':nid' => $nid,
+ ':uid' => $uid,
+ ':status' => COMMENT_PUBLISHED,
+ ))->fetchField();
+ }
+
+ // If we haven't found a reason to keep the user's subscription, delete it.
+ if (!$keep_subscription) {
+ db_delete('tracker_user')
+ ->condition('nid', $nid)
+ ->condition('uid', $uid)
+ ->execute();
+ }
+
+ // Now we need to update the (possibly) changed timestamps for other users
+ // and the node itself.
+
+ // We only need to do this if the removed item has a timestamp that equals
+ // or exceeds the listed changed timestamp for the node
+ $tracker_node = db_query('SELECT nid, changed FROM {tracker_node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject();
+ if ($tracker_node && $changed >= $tracker_node->changed) {
+ // If we're here, the item being removed is *possibly* the item that
+ // established the node's changed timestamp.
+
+ // We just have to recalculate things from scratch.
+ $changed = _tracker_calculate_changed($nid);
+
+ // And then we push the out the new changed timestamp to our denormalized
+ // tables.
+ db_update('tracker_node')
+ ->fields(array(
+ 'changed' => $changed,
+ 'published' => $node->status,
+ ))
+ ->condition('nid', $nid)
+ ->execute();
+ db_update('tracker_node')
+ ->fields(array(
+ 'changed' => $changed,
+ 'published' => $node->status,
+ ))
+ ->condition('nid', $nid)
+ ->execute();
+ }
+ }
+ else {
+ // If the node doesn't exist, remove everything.
+ db_delete('tracker_node')
+ ->condition('nid', $nid)
+ ->execute();
+ db_delete('tracker_user')
+ ->condition('nid', $nid)
+ ->execute();
+ }
+}
diff --git a/core/modules/tracker/tracker.test b/core/modules/tracker/tracker.test
index 3cc227e..a559f1b 100644
--- a/core/modules/tracker/tracker.test
+++ b/core/modules/tracker/tracker.test
@@ -8,7 +8,6 @@
class TrackerTest extends DrupalWebTestCase {
protected $user;
protected $other_user;
- protected $new_node;
public static function getInfo() {
return array(
diff --git a/core/modules/translation/translation.module b/core/modules/translation/translation.module
index db60a08..5fbdf01 100644
--- a/core/modules/translation/translation.module
+++ b/core/modules/translation/translation.module
@@ -207,7 +207,7 @@
function translation_node_view($node, $view_mode) {
// If the site has no translations or is not multilingual we have no content
// translation links to display.
- if (isset($node->tnid) && drupal_multilingual() && $translations = translation_node_get_translations($node->tnid)) {
+ if (isset($node->tnid) && language_multilingual() && $translations = translation_node_get_translations($node->tnid)) {
$languages = language_list('enabled');
$languages = $languages[1];
diff --git a/core/modules/translation/translation.test b/core/modules/translation/translation.test
index 0e801c1..776825a 100644
--- a/core/modules/translation/translation.test
+++ b/core/modules/translation/translation.test
@@ -17,7 +17,7 @@
}
function setUp() {
- parent::setUp('locale', 'translation', 'translation_test');
+ parent::setUp('language', 'locale', 'translation', 'translation_test');
// Setup users.
$this->admin_user = $this->drupalCreateUser(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer blocks', 'access administration pages', 'translate content'));
@@ -291,7 +291,7 @@
$this->assertTrue(array_key_exists($language_code, $languages), t('Language was installed successfully.'));
if (array_key_exists($language_code, $languages)) {
- $this->assertRaw(t('The language %language has been created and can now be used. More information is available on the help screen.', array('%language' => $languages[$language_code]->name, '@locale-help' => url('admin/help/locale'))), t('Language has been created.'));
+ $this->assertRaw(t('The language %language has been created and can now be used.', array('%language' => $languages[$language_code]->name)), t('Language has been created.'));
}
}
elseif ($this->xpath('//input[@type="checkbox" and @name=:name and @checked="checked"]', array(':name' => 'languages[' . $language_code . '][enabled]'))) {
diff --git a/core/modules/update/update.module b/core/modules/update/update.module
index 5612b07..57a2854 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -724,10 +724,10 @@
* plug-able cache system that assumes volatile caches.
*
* Update module still uses the {cache_update} table, but instead of using
- * cache_set(), cache_get(), and cache_clear_all(), there are private helper
- * functions that implement these same basic tasks but ensure that the cache
- * is not prematurely cleared, and that the data is always stored in the
- * database, even if memcache or another cache backend is in use.
+ * the cache API, there are private helper functions that implement these same
+ * basic tasks but ensure that the cache is not prematurely cleared, and that
+ * the data is always stored in the database, even if memcache or another cache
+ * backend is in use.
*/
/**
diff --git a/core/themes/bartik/color/preview.css b/core/themes/bartik/color/preview.css
index 48a4a83..dc408e0 100644
--- a/core/themes/bartik/color/preview.css
+++ b/core/themes/bartik/color/preview.css
@@ -57,11 +57,9 @@
background: #ccc;
background: rgba(255, 255, 255, 0.7);
text-shadow: 0 1px #eee;
- -khtml-border-radius-topleft: 8px;
-moz-border-radius-topleft: 8px;
-webkit-border-top-left-radius: 8px;
border-top-left-radius: 8px;
- -khtml-border-radius-topright: 8px;
-moz-border-radius-topright: 8px;
-webkit-border-top-right-radius: 8px;
border-top-right-radius: 8px;
diff --git a/core/themes/bartik/color/preview.html b/core/themes/bartik/color/preview.html
index 52ea566..ae9aa14 100644
--- a/core/themes/bartik/color/preview.html
+++ b/core/themes/bartik/color/preview.html
@@ -1,7 +1,7 @@