Compare commits

...
32 Commits
Author SHA1 Message Date
bachy 5658794f17 update to 7.22
Signed-off-by: bachy <git@g-u-i.net>
2013-05-24 13:03:57 +02:00
bachy d5097a4bc6 rematch user module
Signed-off-by: bachy <git@g-u-i.net>
2013-03-29 16:58:46 +01:00
bachy 661765bde9 repatch autocomplete js
Signed-off-by: bachy <git@g-u-i.net>
2013-03-29 16:58:31 +01:00
bachy fde4f26165 repatch entity.inc
Signed-off-by: bachy <git@g-u-i.net>
2013-03-29 16:58:16 +01:00
bachy 8763bf01dd update to 7.21
Signed-off-by: bachy <git@g-u-i.net>
2013-03-29 16:53:05 +01:00
bachy 49fb38b169 re : one-time-login-url localized
Signed-off-by: bachy <git@g-u-i.net>
2013-03-06 15:03:43 +01:00
bachy de022d62e2 repatch misc/autocomplete.js
Signed-off-by: bachy <git@g-u-i.net>
2013-03-06 15:00:09 +01:00
bachy d9d092295b rematch includes/entity.inc
Signed-off-by: bachy <git@g-u-i.net>
2013-03-06 14:58:30 +01:00
bachy 8c47736b71 core update 7.20
Signed-off-by: bachy <git@g-u-i.net>
2013-03-06 14:55:44 +01:00
bachy 1aa3c4e9eb htaccess again
Signed-off-by: bachy <git@g-u-i.net>
2013-02-13 13:09:21 +01:00
bachy 1f662a2b40 annul htaccess
Signed-off-by: bachy <git@g-u-i.net>
2013-02-13 12:52:28 +01:00
bachy 83cf488d4a htaccess again
Signed-off-by: bachy <git@g-u-i.net>
2013-02-13 12:51:33 +01:00
bachy 1a145b8470 htaccess just basebeta
Signed-off-by: bachy <git@g-u-i.net>
2013-02-13 12:50:38 +01:00
bachy 8c09d74e68 htaccess again
Signed-off-by: bachy <git@g-u-i.net>
2013-02-13 12:49:47 +01:00
bachy 8e432ea544 htaccess again …
Signed-off-by: bachy <git@g-u-i.net>
2013-02-13 12:47:41 +01:00
bachy 2d4301ad40 htaccess
Signed-off-by: bachy <git@g-u-i.net>
2013-02-13 12:41:07 +01:00
bachy 662012976d htaccess rewrite url bug fix
Signed-off-by: bachy <git@g-u-i.net>
2013-02-13 12:39:17 +01:00
bachy cc526dd563 htaccess redirecte basebeta to www
Signed-off-by: bachy <git@g-u-i.net>
2013-02-13 12:33:43 +01:00
bachy 6d0af35191 one-time-login-url localized
http://drupal.org/node/1754162#comment-6399678
Signed-off-by: bachy <git@g-u-i.net>
2013-01-31 12:48:00 +01:00
bachy 6a94814eaa repatch misc/autocomplete.js
Signed-off-by: bachy <git@g-u-i.net>
2013-01-31 11:41:15 +01:00
bachy 1b6b74ea40 repatch inc/entity.inc
http://drupal.org/node/1003788#comment-5195682
Signed-off-by: bachy <git@g-u-i.net>
2013-01-31 11:38:20 +01:00
bachy 00df84c69c update Drupal 7.19
Signed-off-by: bachy <git@g-u-i.net>
2013-01-31 11:32:52 +01:00
bachy 6c0f932603 removed install files
Signed-off-by: bachy <git@g-u-i.net>
2013-01-30 15:34:12 +01:00
bachy 12045fe181 one-time-login-url localized
http://drupal.org/node/1754162#comment-6399678
Signed-off-by: bachy <git@g-u-i.net>
2013-01-07 17:25:05 +01:00
bachy 60ca2f9e72 rematch for js autocomplete submit
Signed-off-by: bachy <git@g-u-i.net>
2012-12-08 11:44:53 +01:00
bachy aa45d84855 repatch inc/entity.inc
http://drupal.org/node/1003788#comment-5195682
Signed-off-by: bachy <git@g-u-i.net>
2012-12-08 11:39:10 +01:00
bachy 5396b3e2b5 update to D 7.17
Signed-off-by: bachy <git@g-u-i.net>
2012-12-08 11:35:42 +01:00
bachy 975d758599 ignore sublimetext project files
Signed-off-by: bachy <git@g-u-i.net>
2012-12-06 18:55:10 +01:00
bachy 4240ab47e8 7.16 less patch previous patches are preserved
Signed-off-by: bachy <git@g-u-i.net>
2012-10-26 21:57:49 +02:00
bachy e5028b4522 htaccess file mime html5 boilerplate
Signed-off-by: bachy <git@g-u-i.net>
2012-10-09 21:35:32 +02:00
bachy 3a3a620cac autocomplete select event patch
Signed-off-by: bachy <git@g-u-i.net>
2012-10-05 14:07:20 +02:00
bachy 4f6a8d389b includes/entity.inc patch
http://drupal.org/node/1003788#comment-5195682
Signed-off-by: bachy <git@g-u-i.net>
2012-10-05 14:03:27 +02:00
370 changed files with 9440 additions and 4692 deletions
+5 -1
View File
@@ -6,4 +6,8 @@ sites/*
#sites/*/files
#sites/*/private
_base_d7.tmproj
_base_d7.tmproj
/_materio.sublime-project
/_materio.sublime-workspace
/_solr.sublime-project
/_solr.sublime-workspace
+105
View File
@@ -71,6 +71,18 @@ DirectoryIndex index.php index.html index.htm
# downloaded.
RewriteRule "(^|/)\." - [F]
# custom
RewriteCond %{HTTP_HOST} ^basebeta\.materio\.com [OR]
RewriteCond %{HTTP_HOST} ^materio\.com [OR]
RewriteCond %{HTTP_HOST} ^www\.materio\.fr [OR]
RewriteCond %{HTTP_HOST} ^materio\.fr [OR]
RewriteCond %{HTTP_HOST} ^www\.materio\.net [OR]
RewriteCond %{HTTP_HOST} ^materio\.net [OR]
RewriteCond %{HTTP_HOST} ^www\.materio\.eu [OR]
RewriteCond %{HTTP_HOST} ^materio\.eu [NC]
RewriteRule ^ http://www.materio.com%{REQUEST_URI} [L,R=301]
# If your site can be accessed both with and without the 'www.' prefix, you
# can use one of the following settings to redirect users to your preferred
# URL, either WITH or WITHOUT the 'www.' prefix. Choose ONLY one option:
@@ -129,3 +141,96 @@ DirectoryIndex index.php index.html index.htm
</FilesMatch>
</IfModule>
</IfModule>
# FROM Html5 BoilerPlate 4.0
# ----------------------------------------------------------------------
# Proper MIME type for all files
# ----------------------------------------------------------------------
# JavaScript
# Normalize to standard type (it's sniffed in IE anyways)
# tools.ietf.org/html/rfc4329#section-7.2
AddType application/javascript js jsonp
AddType application/json json
# Audio
AddType audio/ogg oga ogg
AddType audio/mp4 m4a f4a f4b
# Video
AddType video/ogg ogv
AddType video/mp4 mp4 m4v f4v f4p
AddType video/webm webm
AddType video/x-flv flv
# SVG
# Required for svg webfonts on iPad
# twitter.com/FontSquirrel/status/14855840545
AddType image/svg+xml svg svgz
AddEncoding gzip svgz
# Webfonts
AddType application/vnd.ms-fontobject eot
AddType application/x-font-ttf ttf ttc
AddType font/opentype otf
AddType application/x-font-woff woff
# Assorted types
AddType image/x-icon ico
AddType image/webp webp
AddType text/cache-manifest appcache manifest
AddType text/x-component htc
AddType application/xml rss atom xml rdf
AddType application/x-chrome-extension crx
AddType application/x-opera-extension oex
AddType application/x-xpinstall xpi
AddType application/octet-stream safariextz
AddType application/x-web-app-manifest+json webapp
AddType text/x-vcard vcf
AddType application/x-shockwave-flash swf
AddType text/vtt vtt
# ----------------------------------------------------------------------
# UTF-8 encoding
# ----------------------------------------------------------------------
# Use UTF-8 encoding for anything served text/plain or text/html
AddDefaultCharset utf-8
# Force UTF-8 for a number of file formats
AddCharset utf-8 .atom .css .js .json .rss .vtt .xml
# ----------------------------------------------------------------------
# A little more security
# ----------------------------------------------------------------------
# Block access to "hidden" directories or files whose names begin with a
# period. This includes directories used by version control systems such as
# Subversion or Git.
<IfModule mod_rewrite.c>
RewriteCond %{SCRIPT_FILENAME} -d [OR]
RewriteCond %{SCRIPT_FILENAME} -f
RewriteRule "(^|/)\." - [F]
</IfModule>
# Block access to backup and source files. These files may be left by some
# text/html editors and pose a great security danger, when anyone can access
# them.
<FilesMatch "(\.(bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)|~)$">
Order allow,deny
Deny from all
Satisfy All
</FilesMatch>
# Increase cookie security
<IfModule php5_module>
php_value session.cookie_httponly true
</IfModule>
@@ -0,0 +1,155 @@
diff --git a/modules/user/user.module b/modules/user/user.module
index 47ac642..c204f6d 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -2286,14 +2286,26 @@ function user_external_login_register($name, $module) {
*
* @param object $account
* An object containing the user account.
+ * @param array $options
+ * (optional) A keyed array of settings. Supported options are:
+ * - langcode: A language code to be used when generating locale-sensitive
+ * urls. If langcode is NULL the users preferred language is used.
*
* @return
* A unique URL that provides a one-time log in for the user, from which
* they can change their password.
*/
-function user_pass_reset_url($account) {
+function user_pass_reset_url($account, $options = array()) {
$timestamp = REQUEST_TIME;
- return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE));
+ $url_options = array('absolute' => TRUE);
+ if (isset($options['langcode'])) {
+ $languages = language_list();
+ $url_options['language'] = $languages[$options['langcode']];
+ }
+ else {
+ $url_options['language'] = user_preferred_language($account);
+ }
+ return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), $url_options);
}
/**
@@ -2305,6 +2317,10 @@ function user_pass_reset_url($account) {
* - uid: The user uid number.
* - pass: The hashed user password string.
* - login: The user login name.
+ * @param array $options
+ * (optional) A keyed array of settings. Supported options are:
+ * - langcode: A language code to be used when generating locale-sensitive
+ * urls. If langcode is NULL the users preferred language is used.
*
* @return
* A unique URL that may be used to confirm the cancellation of the user
@@ -2313,9 +2329,17 @@ function user_pass_reset_url($account) {
* @see user_mail_tokens()
* @see user_cancel_confirm()
*/
-function user_cancel_url($account) {
+function user_cancel_url($account, $options = array()) {
$timestamp = REQUEST_TIME;
- return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE));
+ $url_options = array('absolute' => TRUE);
+ if (isset($options['langcode'])) {
+ $languages = language_list();
+ $url_options['language'] = $languages[$options['langcode']];
+ }
+ else {
+ $url_options['language'] = user_preferred_language($account);
+ }
+ return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), $url_options);
}
/**
@@ -2752,7 +2776,7 @@ Your account on [site:name] has been canceled.
if ($replace) {
// We do not sanitize the token replacement, since the output of this
// replacement is intended for an e-mail message, not a web browser.
- return token_replace($text, $variables, array('language' => $language, 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE));
+ return token_replace($text, $variables, array('langcode' => $langcode, 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE));
}
return $text;
@@ -2779,8 +2803,8 @@ Your account on [site:name] has been canceled.
*/
function user_mail_tokens(&$replacements, $data, $options) {
if (isset($data['user'])) {
- $replacements['[user:one-time-login-url]'] = user_pass_reset_url($data['user']);
- $replacements['[user:cancel-url]'] = user_cancel_url($data['user']);
+ $replacements['[user:one-time-login-url]'] = user_pass_reset_url($data['user'], $options);
+ $replacements['[user:cancel-url]'] = user_cancel_url($data['user'], $options);
}
}
diff --git a/modules/user/user.test b/modules/user/user.test
index b53db07..0417642 100644
--- a/modules/user/user.test
+++ b/modules/user/user.test
@@ -2012,6 +2012,26 @@ class UserTokenReplaceTestCase extends DrupalWebTestCase {
);
}
+ public function setUp() {
+ parent::setUp('locale');
+
+ $account = $this->drupalCreateUser(array('access administration pages', 'administer languages'));
+ $this->drupalLogin($account);
+
+ // Add language.
+ $edit = array('langcode' => 'de');
+ $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+ // Enable URL language detection and selection.
+ $edit = array('language[enabled][locale-url]' => 1);
+ $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings'));
+
+ // Reset static caching.
+ drupal_static_reset('language_list');
+ drupal_static_reset('locale_url_outbound_alter');
+ drupal_static_reset('locale_language_url_rewrite_url');
+ }
+
/**
* Creates a user, then tests the tokens generated from it.
*/
@@ -2062,6 +2082,39 @@ class UserTokenReplaceTestCase extends DrupalWebTestCase {
$output = token_replace($input, array('user' => $account), array('language' => $language, 'sanitize' => FALSE));
$this->assertEqual($output, $expected, t('Unsanitized user token %token replaced.', array('%token' => $input)));
}
+
+ $languages = language_list();
+
+ // Generate login and cancel link.
+ $tests = array();
+ $tests['[user:one-time-login-url]'] = user_pass_reset_url($account);
+ $tests['[user:cancel-url]'] = user_cancel_url($account);
+
+ // Generate tokens with interface language.
+ $link = url('user', array('absolute' => TRUE));
+ foreach ($tests as $input => $expected) {
+ $output = token_replace($input, array('user' => $account), array('langcode' => $language->language, 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE));
+ $this->assertTrue(strpos($output, $link) === 0, 'Generated URL is in interface language.');
+ }
+
+ // Generate tokens with the user's preferred language.
+ $edit['language'] = 'de';
+ $account = user_save($account, $edit);
+ $link = url('user', array('language' => $languages[$account->language], 'absolute' => TRUE));
+ foreach ($tests as $input => $expected) {
+ $output = token_replace($input, array('user' => $account), array('callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE));
+ $this->assertTrue(strpos($output, $link) === 0, "Generated URL is in the user's preferred language.");
+ }
+
+ // Generate tokens with one specific language.
+ $link = url('user', array('language' => $languages['de'], 'absolute' => TRUE));
+ foreach ($tests as $input => $expected) {
+ foreach (array($user1, $user2) as $account) {
+ $output = token_replace($input, array('user' => $account), array('langcode' => 'de', 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE));
+ $this->assertTrue(strpos($output, $link) === 0, "Generated URL in in the requested language.");
+ }
+ }
+
}
}
+159 -7
View File
@@ -1,4 +1,156 @@
Drupal 7.22, 2013-04-03
-----------------------
- Allowed the drupal_http_request() function to be overridden so that
additional HTTP request capabilities can be added by contributed modules.
- Changed the Simpletest module to allow PSR-0 test classes to be used in
Drupal 7.
- Removed an unnecessary "Content-Disposition" header from private file
downloads; it prevented many private files from being viewed inline in a web
browser.
- Changed various field API functions to allow them to optionally act on a
single field within an entity (API addition: http://drupal.org/node/1825844).
- Fixed a bug which prevented Drupal's file transfer functionality from working
on some PHP 5.4 systems.
- Fixed incorrect log message when theme() is called for a theme hook that does
not exist (minor string change).
- Fixed Drupal's token-replacement system to allow spaces in the token value.
- Changed the default behavior after a user creates a node they do not have
access to view. The user will now be redirected to the front page rather than
an access denied page.
- Fixed a bug which prevented empty HTTP headers (such as "0") from being set.
(Minor behavior change: Callers of drupal_add_http_header() must now set
FALSE explicitly to prevent a header from being sent at all; this was already
indicated in the function's documentation.)
- Fixed OpenID errors when more than one module implements hook_openid(). The
behavior is now changed so that if more than one module tries to set the same
parameter, the last module's change takes effect.
- Fixed a serious documentation bug: The $name variable in the
taxonomy-term.tpl.php theme template was incorrectly documented as being
sanitized when in fact it is not.
- Fixed a bug which prevented Drupal 6 to Drupal 7 upgrades on sites which had
duplicate permission names in the User module's database tables.
- Added an empty "datatype" attribute to taxonomy term and username links to
make the RDFa markup upward compatible with RDFa 1.1 (minor markup addition).
- Fixed a bug which caused the denial-of-service protection added in Drupal
7.20 to break certain valid image URLs that had an extra slash in them.
- Fixed a bug with update queries in the SQLite database driver that prevented
Drupal from being installed with SQLite on PHP 5.4.
- Fixed enforced dependencies errors updating to recent versions of Drupal 7 on
certain non-MySQL databases.
- Refactored the Field module's caching behavior to obtain large improvements
in memory usage for sites with many fields and instances (API addition:
http://drupal.org/node/1915646).
- Fixed entity argument not being passed to implementations of
hook_file_download_access_alter(). The fix adds an additional context
parameter that can be passed when calling drupal_alter() for any hook (API
change: http://drupal.org/node/1882722).
- Fixed broken support for translatable comment fields (API change:
http://drupal.org/node/1874724).
- Added an assertThemeOutput() method to Simpletest to allow tests to check
that themed output matches an expected HTML string (API addition).
- Added a link to "Install another module" after a module has been successfully
downloaded via the Update Manager (UI change).
- Added an optional "exclusive" flag to installation profile .info files which
allows Drupal distributions to force a profile to be selected during
installation (API addition).
- Fixed a bug which caused the database API to not properly close database
connections.
- Added a link to the URL for running cron from outside the site to the Cron
settings page (UI change).
- Fixed a bug which prevented image styles from being reverted on PHP 5.4.
- Made the default .htaccess rules protocol sensitive to improve security for
sites which use HTTPS and redirect between "www" and non-"www" versions of
the page.
- Numerous small bug fixes.
- Numerous API documentation improvements.
- Additional automated test coverage.
Drupal 7.21, 2013-03-06
-----------------------
- Allowed sites using the 'image_allow_insecure_derivatives' variable to still
have partial protection from the security issues fixed in Drupal 7.20.
Drupal 7.20, 2013-02-20
-----------------------
- Fixed security issues (denial of service). See SA-CORE-2013-002.
Drupal 7.19, 2013-01-16
-----------------------
- Fixed security issues (multiple vulnerabilities). See SA-CORE-2013-001.
Drupal 7.18, 2012-12-19
-----------------------
- Fixed security issues (multiple vulnerabilities). See SA-CORE-2012-004.
Drupal 7.17, 2012-11-07
-----------------------
- Changed the default value of the '404_fast_html' variable to have a DOCTYPE
declaration.
- Made it possible to use associative arrays for the 'items' variable in
theme_item_list().
- Fixed a bug which prevented required form elements without a title from being
given an "error" class when the form fails validation.
- Prevented duplicate HTML IDs from appearing when two forms are displayed on
the same page and one of them is submitted with invalid data (minor markup
change).
- Fixed a bug which prevented Drupal 6 to Drupal 7 upgrades on sites which had
stale data in the Upload module's database tables.
- Fixed a bug in the States API which prevented certain types of form elements
from being disabled when requested.
- Allowed aggregator feed items with author names longer than 255 characters to
have a truncated version saved to the database (rather than causing a fatal
error).
- Allowed aggregator feed items to have URLs longer than 255 characters
(schema change which results in several columns in the Aggregator module's
database tables changing from VARCHAR to TEXT fields).
- Added hook_taxonomy_term_view() and standardized the process for rendering
taxonomy terms to invoke hook_entity_view() and otherwise make it consistent
with other entities (API change: http://drupal.org/node/1808870).
- Added hook_entity_view_mode_alter() to allow modules to change entity view
modes on display (API addition: http://drupal.org/node/1833086).
- Fixed a bug which made database queries running a "LIKE" query on blob fields
fail on PostgreSQL databases. This caused errors during the Drupal 6 to
Drupal 7 upgrade.
- Changed the hook_menu() entry for Drupal's rss.xml page to prevent extra path
components from being accidentally passed to the page callback function (data
structure change).
- Removed a non-standard "name" attribute from Drupal's default Content-Type
header for file downloads.
- Fixed the theme settings form to properly clean up submitted values in
$form_state['values'] when the form is submitted (data structure change).
- Fixed an inconsistency by removing the colon from the end of the label on
multi-valued form fields (minor string change).
- Added support for 'weight' in hook_field_widget_info() to allow modules to
control the order in which widgets are displayed in the Field UI.
- Updated various tables in the OpenID and Book modules to use the default
"empty table" text pattern (string change).
- Added proxy server support to drupal_http_request().
- Added "lang" attributes to language links, to better support screen readers.
- Fixed double occurrence of a "ul" HTML tag on secondary local tasks in the
Seven theme (markup change).
- Fixed bugs which caused taxonomy vocabulary and shortcut set titles to be
double-escaped. The fix replaces the taxonomy vocabulary overview page and
"Edit shortcuts" menu items' title callback entries in hook_menu() with new
functions that do not escape HTML characters (data structure change).
- Modified the Update manager module to allow drupal.org to collect usage
statistics for individual modules and themes, rather than only for entire
projects.
- Modified the node listing database query on Drupal's default front page to
add table aliases for better query altering (this is a data structure change
affecting code which implements hook_query_alter() on this query).
- Improved the translatability of the "Field type(s) in use" message on the
modules page (admin-facing string change).
- Fixed a regression which caused a "call to undefined function
drupal_find_base_themes()" fatal error under rare circumstances.
- Numerous API documentation improvements.
- Additional automated test coverage.
Drupal 7.16, 2012-10-17
-----------------------
- Fixed security issues (Arbitrary PHP code execution and information
disclosure). See SA-CORE-2012-003.
Drupal 7.15, 2012-08-01
-----------------------
- Introduced a 'user_password_reset_timeout' variable to allow the 24-hour
@@ -310,8 +462,8 @@ Drupal 7.0, 2011-01-05
order can now be customized using the Views module.
* Removed the 'related terms' feature from taxonomy module since this can
now be achieved with Field API.
* Added additional features to the default install profile, and implemented
a "slimmed down" install profile designed for developers.
* Added additional features to the default installation profile, and
implemented a "slimmed down" profile designed for developers.
* Added a built-in, automated cron run feature, which is triggered by site
visitors.
* Added an administrator role which is assigned all permissions for
@@ -538,7 +690,7 @@ Drupal 6.16, 2010-03-03
see SA-CORE-2010-001.
- Better support for updated jQuery versions.
- Reduced resource usage of update.module.
- Fixed several issues relating to support of install profiles and
- Fixed several issues relating to support of installation profiles and
distributions.
- Added a locking framework to avoid data corruption on long operations.
- Fixed a variety of other bugs.
@@ -656,7 +808,7 @@ Drupal 6.0, 2008-02-13
* Expands the severity levels from 3 (Error, Warning, Notice) to the 8
levels defined in RFC 3164.
* The watchdog module is now called dblog, and is optional, but enabled by
default in the default install profile.
default in the default installation profile.
* Extended the database log module so log messages can be filtered.
* Added syslog module: useful for monitoring large Drupal installations.
- Added optional e-mail notifications when users are approved, blocked, or
@@ -711,7 +863,7 @@ Drupal 6.0, 2008-02-13
* Themed the installer with the Garland theme.
* Added form to provide initial site information during installation.
* Added ability to provide extra installation steps programmatically.
* Made it possible to import interface translations at install time.
* Made it possible to import interface translations during installation.
- Added the HTML corrector filter:
* Fixes faulty and chopped off HTML in postings.
* Tags are now automatically closed at the end of the teaser.
@@ -890,7 +1042,7 @@ Drupal 5.0, 2007-01-15
- Added web-based installer which can:
* Check installation and run-time requirements
* Automatically generate the database configuration file
* Install pre-made 'install profiles' or distributions
* Install pre-made installation profiles or distributions
* Import the database structure with automatic table prefixing
* Be localized
- Added new default Garland theme
@@ -950,7 +1102,7 @@ Drupal 5.0, 2007-01-15
- Removed the archive module.
- Upgrade system:
* Created space for update branches.
- Forms API:
- Form API:
* Made it possible to programmatically submit forms.
* Improved api for multistep forms.
- Theme system:
+2 -2
View File
@@ -89,8 +89,8 @@ INSTALLATION
- Download a translation file for the correct Drupal version and language
from the translation server: http://localize.drupal.org/translate/downloads
- Place the file into your installation profile's translations
directory. For instance, if you are using the Standard install profile,
- Place the file into your installation profile's translations directory.
For instance, if you are using the Standard installation profile,
move the .po file into the directory:
profiles/standard/translations/
+108 -108
View File
@@ -9,9 +9,9 @@ Branch maintainers
The Drupal Core branch maintainers oversee the development of Drupal as a whole.
The branch maintainers for Drupal 7 are:
- Dries Buytaert 'dries' <http://drupal.org/user/1>
- Angela Byron 'webchick' <http://drupal.org/user/24967>
- David Rothstein 'David_Rothstein' <http://drupal.org/user/124982>
- Dries Buytaert 'dries' http://drupal.org/user/1
- Angela Byron 'webchick' http://drupal.org/user/24967
- David Rothstein 'David_Rothstein' http://drupal.org/user/124982
Component maintainers
@@ -23,134 +23,136 @@ information on their responsibilities, and to find out how to become a component
maintainer. Current component maintainers for Drupal 7:
Ajax system
- Alex Bronstein 'effulgentsia' <http://drupal.org/user/78040>
- Earl Miles 'merlinofchaos' <http://drupal.org/user/26979>
- Alex Bronstein 'effulgentsia' http://drupal.org/user/78040
- Earl Miles 'merlinofchaos' http://drupal.org/user/26979
Base system
- Károly Négyesi 'chx' <http://drupal.org/user/9446>
- Damien Tournoud 'DamZ' <http://drupal.org/user/22211>
- Moshe Weitzman 'moshe weitzman' <http://drupal.org/user/23>
- Károly Négyesi 'chx' http://drupal.org/user/9446
- Damien Tournoud 'DamZ' http://drupal.org/user/22211
- Moshe Weitzman 'moshe weitzman' http://drupal.org/user/23
Batch system
- Yves Chedemois 'yched' <http://drupal.org/user/39567>
- Yves Chedemois 'yched' http://drupal.org/user/39567
Cache system
- Damien Tournoud 'DamZ' <http://drupal.org/user/22211>
- Nathaniel Catchpole 'catch' <http://drupal.org/user/35733>
- Damien Tournoud 'DamZ' http://drupal.org/user/22211
- Nathaniel Catchpole 'catch' http://drupal.org/user/35733
Cron system
- Károly Négyesi 'chx' <http://drupal.org/user/9446>
- Derek Wright 'dww' <http://drupal.org/user/46549>
- Károly Négyesi 'chx' http://drupal.org/user/9446
- Derek Wright 'dww' http://drupal.org/user/46549
Database system
- Larry Garfield 'Crell' <http://drupal.org/user/26398>
- Larry Garfield 'Crell' http://drupal.org/user/26398
- MySQL driver
- Larry Garfield 'Crell' <http://drupal.org/user/26398>
- David Strauss 'David Strauss' <http://drupal.org/user/93254>
- Larry Garfield 'Crell' http://drupal.org/user/26398
- David Strauss 'David Strauss' http://drupal.org/user/93254
- PostgreSQL driver
- Damien Tournoud 'DamZ' <http://drupal.org/user/22211>
- Josh Waihi 'fiasco' <http://drupal.org/user/188162>
- Damien Tournoud 'DamZ' http://drupal.org/user/22211
- Josh Waihi 'fiasco' http://drupal.org/user/188162
- Sqlite driver
- Damien Tournoud 'DamZ' <http://drupal.org/user/22211>
- Károly Négyesi 'chx' <http://drupal.org/user/9446>
- Damien Tournoud 'DamZ' http://drupal.org/user/22211
- Károly Négyesi 'chx' http://drupal.org/user/9446
Database update system
- Károly Négyesi 'chx' <http://drupal.org/user/9446>
- Ashok Modi 'btmash' <http://drupal.org/user/60422>
- Károly Négyesi 'chx' http://drupal.org/user/9446
- Ashok Modi 'BTMash' http://drupal.org/user/60422
Entity system
- Wolfgang Ziegler 'fago' <http://drupal.org/user/16747>
- Nathaniel Catchpole 'catch' <http://drupal.org/user/35733>
- Franz Heinzmann 'Frando' <http://drupal.org/user/21850>
- Wolfgang Ziegler 'fago' http://drupal.org/user/16747
- Nathaniel Catchpole 'catch' http://drupal.org/user/35733
- Franz Heinzmann 'Frando' http://drupal.org/user/21850
File system
- Andrew Morton 'drewish' <http://drupal.org/user/34869>
- Aaron Winborn 'aaron' <http://drupal.org/user/33420>
- Andrew Morton 'drewish' http://drupal.org/user/34869
- Aaron Winborn 'aaron' http://drupal.org/user/33420
Form system
- Károly Négyesi 'chx' <http://drupal.org/user/9446>
- Alex Bronstein 'effulgentsia' <http://drupal.org/user/78040>
- Wolfgang Ziegler 'fago' <http://drupal.org/user/16747>
- Daniel F. Kudwien 'sun' <http://drupal.org/user/54136>
- Franz Heinzmann 'Frando' <http://drupal.org/user/21850>
- Károly Négyesi 'chx' http://drupal.org/user/9446
- Alex Bronstein 'effulgentsia' http://drupal.org/user/78040
- Wolfgang Ziegler 'fago' http://drupal.org/user/16747
- Daniel F. Kudwien 'sun' http://drupal.org/user/54136
- Franz Heinzmann 'Frando' http://drupal.org/user/21850
Image system
- Andrew Morton 'drewish' <http://drupal.org/user/34869>
- Nathan Haug 'quicksketch' <http://drupal.org/user/35821>
- Andrew Morton 'drewish' http://drupal.org/user/34869
- Nathan Haug 'quicksketch' http://drupal.org/user/35821
Install system
- David Rothstein 'David_Rothstein' <http://drupal.org/user/124982>
- David Rothstein 'David_Rothstein' http://drupal.org/user/124982
JavaScript
- Théodore Biadala 'nod_' <http://drupal.org/user/598310>
- Théodore Biadala 'nod_' http://drupal.org/user/598310
- Steve De Jonghe 'seutje' http://drupal.org/user/264148
- Jesse Renée Beach 'jessebeach' http://drupal.org/user/748566
Language system
- Francesco Placella 'plach' <http://drupal.org/user/183211>
- Daniel F. Kudwien 'sun' <http://drupal.org/user/54136>
- Francesco Placella 'plach' http://drupal.org/user/183211
- Daniel F. Kudwien 'sun' http://drupal.org/user/54136
Lock system
- Damien Tournoud 'DamZ' <http://drupal.org/user/22211>
- Damien Tournoud 'DamZ' http://drupal.org/user/22211
Mail system
- ?
Markup
- Jacine Luisi 'Jacine' <http://drupal.org/user/88931>
- Daniel F. Kudwien 'sun' <http://drupal.org/user/54136>
- Jacine Luisi 'Jacine' http://drupal.org/user/88931
- Daniel F. Kudwien 'sun' http://drupal.org/user/54136
Menu system
- Peter Wolanin 'pwolanin' <http://drupal.org/user/49851>
- Károly Négyesi 'chx' <http://drupal.org/user/9446>
- Peter Wolanin 'pwolanin' http://drupal.org/user/49851
- Károly Négyesi 'chx' http://drupal.org/user/9446
Path system
- Dave Reid 'davereid' <http://drupal.org/user/53892>
- Nathaniel Catchpole 'catch' <http://drupal.org/user/35733>
- Dave Reid 'davereid' http://drupal.org/user/53892
- Nathaniel Catchpole 'catch' http://drupal.org/user/35733
Render system
- Moshe Weitzman 'moshe weitzman' <http://drupal.org/user/23>
- Alex Bronstein 'effulgentsia' <http://drupal.org/user/78040>
- Franz Heinzmann 'Frando' <http://drupal.org/user/21850>
- Moshe Weitzman 'moshe weitzman' http://drupal.org/user/23
- Alex Bronstein 'effulgentsia' http://drupal.org/user/78040
- Franz Heinzmann 'Frando' http://drupal.org/user/21850
Theme system
- Earl Miles 'merlinofchaos' <http://drupal.org/user/26979>
- Alex Bronstein 'effulgentsia' <http://drupal.org/user/78040>
- Joon Park 'dvessel' <http://drupal.org/user/56782>
- John Albin Wilkins 'JohnAlbin' <http://drupal.org/user/32095>
- Earl Miles 'merlinofchaos' http://drupal.org/user/26979
- Alex Bronstein 'effulgentsia' http://drupal.org/user/78040
- Joon Park 'dvessel' http://drupal.org/user/56782
- John Albin Wilkins 'JohnAlbin' http://drupal.org/user/32095
Token system
- Dave Reid 'davereid' <http://drupal.org/user/53892>
- Dave Reid 'davereid' http://drupal.org/user/53892
XML-RPC system
- Frederic G. Marand 'fgm' <http://drupal.org/user/27985>
- Frederic G. Marand 'fgm' http://drupal.org/user/27985
Topic coordinators
------------------
Accessibility
- Everett Zufelt 'Everett Zufelt' <http://drupal.org/user/406552>
- Brandon Bowersox-Johnson 'bowersox' <http://drupal.org/user/186415>
- Everett Zufelt 'Everett Zufelt' http://drupal.org/user/406552
- Brandon Bowersox-Johnson 'bowersox' http://drupal.org/user/186415
Documentation
- Jennifer Hodgdon 'jhodgdon' <http://drupal.org/user/155601>
- Jennifer Hodgdon 'jhodgdon' http://drupal.org/user/155601
Security
- Heine Deelstra 'Heine' <http://drupal.org/user/17943>
- Greg Knaddison 'greggles' http://drupal.org/user/36762
Translations
- Gerhard Killesreiter 'killes' <http://drupal.org/user/83>
- Gerhard Killesreiter 'killes' http://drupal.org/user/83
User experience and usability
- Roy Scholten 'yoroy' <http://drupal.org/user/41502>
- Bojhan Somers 'Bojhan' <http://drupal.org/user/87969>
- Roy Scholten 'yoroy' http://drupal.org/user/41502
- Bojhan Somers 'Bojhan' http://drupal.org/user/87969
Node Access
- Moshe Weitzman 'moshe weitzman' <http://drupal.org/user/23>
- Ken Rickard 'agentrickard' <http://drupal.org/user/20975>
- Jess Myrbo 'xjm' <http://drupal.org/user/65776>
- Moshe Weitzman 'moshe weitzman' http://drupal.org/user/23
- Ken Rickard 'agentrickard' http://drupal.org/user/20975
- Jess Myrbo 'xjm' http://drupal.org/user/65776
Module maintainers
------------------
@@ -159,145 +161,143 @@ Aggregator module
- ?
Block module
- John Albin Wilkins 'JohnAlbin' <http://drupal.org/user/32095>
- John Albin Wilkins 'JohnAlbin' http://drupal.org/user/32095
Blog module
- ?
Book module
- Peter Wolanin 'pwolanin' <http://drupal.org/user/49851>
- Peter Wolanin 'pwolanin' http://drupal.org/user/49851
Color module
- ?
Comment module
- Nathaniel Catchpole 'catch' <http://drupal.org/user/35733>
- Nathaniel Catchpole 'catch' http://drupal.org/user/35733
Contact module
- Dave Reid 'davereid' <http://drupal.org/user/53892>
- Dave Reid 'davereid' http://drupal.org/user/53892
Contextual module
- Daniel F. Kudwien 'sun' <http://drupal.org/user/54136>
- Daniel F. Kudwien 'sun' http://drupal.org/user/54136
Dashboard module
- ?
Database logging module
- Khalid Baheyeldin 'kbahey' <http://drupal.org/user/4063>
- Khalid Baheyeldin 'kbahey' http://drupal.org/user/4063
Field module
- Yves Chedemois 'yched' <http://drupal.org/user/39567>
- Barry Jaspan 'bjaspan' <http://drupal.org/user/46413>
- Yves Chedemois 'yched' http://drupal.org/user/39567
- Barry Jaspan 'bjaspan' http://drupal.org/user/46413
Field UI module
- Yves Chedemois 'yched' <http://drupal.org/user/39567>
- Yves Chedemois 'yched' http://drupal.org/user/39567
File module
- Aaron Winborn 'aaron' <http://drupal.org/user/33420>
- Aaron Winborn 'aaron' http://drupal.org/user/33420
Filter module
- Daniel F. Kudwien 'sun' <http://drupal.org/user/54136>
- Daniel F. Kudwien 'sun' http://drupal.org/user/54136
Forum module
- Lee Rowlands 'larowlan' <http://drupal.org/user/395439>
- Lee Rowlands 'larowlan' http://drupal.org/user/395439
Help module
- ?
Image module
- Nathan Haug 'quicksketch' <http://drupal.org/user/35821>
- Nathan Haug 'quicksketch' http://drupal.org/user/35821
Locale module
- Gábor Hojtsy 'Gábor Hojtsy' <http://drupal.org/user/4166>
- Gábor Hojtsy 'Gábor Hojtsy' http://drupal.org/user/4166
Menu module
- ?
Node module
- Moshe Weitzman 'moshe weitzman' <http://drupal.org/user/23>
- David Strauss 'David Strauss' <http://drupal.org/user/93254>
- Moshe Weitzman 'moshe weitzman' http://drupal.org/user/23
- David Strauss 'David Strauss' http://drupal.org/user/93254
OpenID module
- Vojtech Kusy 'wojtha' <http://drupal.org/user/56154>
- Heine Deelstra 'Heine' <http://drupal.org/user/17943>
- Christian Schmidt 'c960657' <http://drupal.org/user/216078>
- Damien Tournoud 'DamZ' <http://drupal.org/user/22211>
- Vojtech Kusy 'wojtha' http://drupal.org/user/56154
- Christian Schmidt 'c960657' http://drupal.org/user/216078
- Damien Tournoud 'DamZ' http://drupal.org/user/22211
Overlay module
- Katherine Senzee 'ksenzee' <http://drupal.org/user/139855>
- Katherine Senzee 'ksenzee' http://drupal.org/user/139855
Path module
- Dave Reid 'davereid' <http://drupal.org/user/53892>
- Dave Reid 'davereid' http://drupal.org/user/53892
PHP module
- ?
Poll module
- Andrei Mateescu 'amateescu' <http://drupal.org/user/729614>
- Andrei Mateescu 'amateescu' http://drupal.org/user/729614
Profile module
- ?
RDF module
- Stéphane Corlosquet 'scor' <http://drupal.org/user/52142>
- Stéphane Corlosquet 'scor' http://drupal.org/user/52142
Search module
- Doug Green 'douggreen' <http://drupal.org/user/29191>
- Doug Green 'douggreen' http://drupal.org/user/29191
Shortcut module
- David Rothstein 'David_Rothstein' <http://drupal.org/user/124982>
- Kristof De Jaeger 'swentel' <http://drupal.org/user/107403>
- David Rothstein 'David_Rothstein' http://drupal.org/user/124982
Simpletest module
- Jimmy Berry 'boombatower' <http://drupal.org/user/214218>
- Károly Négyesi 'chx' <http://drupal.org/user/9446>
- Jimmy Berry 'boombatower' http://drupal.org/user/214218
- Károly Négyesi 'chx' http://drupal.org/user/9446
Statistics module
- Tim Millwood 'timmillwood' <http://drupal.org/user/227849>
- Tim Millwood 'timmillwood' http://drupal.org/user/227849
Syslog module
- Khalid Baheyeldin 'kbahey' <http://drupal.org/user/4063>
- Khalid Baheyeldin 'kbahey' http://drupal.org/user/4063
System module
- ?
Taxonomy module
- Jess Myrbo 'xjm' <http://drupal.org/user/65776>
- Nathaniel Catchpole 'catch' <http://drupal.org/user/35733>
- Benjamin Doherty 'bangpound' <http://drupal.org/user/100456>
- Jess Myrbo 'xjm' http://drupal.org/user/65776
- Nathaniel Catchpole 'catch' http://drupal.org/user/35733
- Benjamin Doherty 'bangpound' http://drupal.org/user/100456
Toolbar module
- ?
Tracker module
- David Strauss 'David Strauss' <http://drupal.org/user/93254>
- David Strauss 'David Strauss' http://drupal.org/user/93254
Translation module
- Francesco Placella 'plach' <http://drupal.org/user/183211>
- Francesco Placella 'plach' http://drupal.org/user/183211
Trigger module
- ?
Update module
- Derek Wright 'dww' <http://drupal.org/user/46549>
- Derek Wright 'dww' http://drupal.org/user/46549
User module
- Moshe Weitzman 'moshe weitzman' <http://drupal.org/user/23>
- David Strauss 'David Strauss' <http://drupal.org/user/93254>
- Moshe Weitzman 'moshe weitzman' http://drupal.org/user/23
- David Strauss 'David Strauss' http://drupal.org/user/93254
Theme maintainers
-----------------
Bartik theme
- Jen Simmons 'jensimmons' <http://drupal.org/user/140882>
- Jeff Burns 'Jeff Burnz' <http://drupal.org/user/61393>
- Jen Simmons 'jensimmons' http://drupal.org/user/140882
- Jeff Burns 'Jeff Burnz' http://drupal.org/user/61393
Garland theme
- John Albin Wilkins 'JohnAlbin' <http://drupal.org/user/32095>
- John Albin Wilkins 'JohnAlbin' http://drupal.org/user/32095
Seven theme
- Jeff Burns 'Jeff Burnz' <http://drupal.org/user/61393>
- Jeff Burns 'Jeff Burnz' http://drupal.org/user/61393
Stark theme
- John Albin Wilkins 'JohnAlbin' <http://drupal.org/user/32095>
- John Albin Wilkins 'JohnAlbin' http://drupal.org/user/32095
+35
View File
@@ -4,6 +4,7 @@ CONTENTS OF THIS FILE
* About Drupal
* Configuration and features
* Installation profiles
* Appearance
* Developing for Drupal
@@ -43,6 +44,40 @@ More about configuration:
http://drupal.org/project/modules
* See also: "Developing for Drupal" for writing your own modules, below.
INSTALLATION PROFILES
---------------------
Installation profiles define additional steps (such as enabling modules,
defining content types, etc.) that run after the base installation provided
by core when Drupal is first installed. There are two basic installation
profiles provided with Drupal core.
Installation profiles from the Drupal community modify the installation process
to provide a website for a specific use case, such as a CMS for media
publishers, a web-based project tracking tool, or a full-fledged CRM for
non-profit organizations raising money and accepting donations. They can be
distributed as bare installation profiles or as "distributions". Distributions
include Drupal core, the installation profile, and all other required
extensions, such as contributed and custom modules, themes, and third-party
libraries. Bare installation profiles require you to download Drupal Core and
the required extensions separately; place the downloaded profile in the
/profiles directory before you start the installation process. Note that the
contents of this directory may be overwritten during updates of Drupal core;
it is advised to keep code backups or use a version control system.
Additionally, modules and themes may be placed inside subdirectories in a
specific installation profile such as profiles/your_site_profile/modules and
profiles/your_site_profile/themes respectively to restrict their usage to only
sites that were installed with that specific profile.
More about installation profiles and distributions:
* Read about the difference between installation profiles and distributions:
http://drupal.org/node/1089736
* Download contributed installation profiles and distributions:
http://drupal.org/project/distributions
* Develop your own installation profile or distribution:
http://drupal.org/developing/distributions
APPEARANCE
----------
+30
View File
@@ -0,0 +1,30 @@
diff --git a/misc/autocomplete.js b/misc/autocomplete.js
index 8f7ac60..5679081 100644
--- a/misc/autocomplete.js
+++ b/misc/autocomplete.js
@@ -114,6 +114,7 @@ Drupal.jsAC.prototype.onkeyup = function (input, e) {
*/
Drupal.jsAC.prototype.select = function (node) {
this.input.value = $(node).data('autocompleteValue');
+ $(this.input).trigger('autocompleteSelect', [node]);
};
/**
@@ -167,7 +168,7 @@ Drupal.jsAC.prototype.unhighlight = function (node) {
Drupal.jsAC.prototype.hidePopup = function (keycode) {
// Select item if the right key or mousebutton was pressed.
if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) {
- this.input.value = $(this.selected).data('autocompleteValue');
+ this.select(this.selected);
}
// Hide popup.
var popup = this.popup;
@@ -220,7 +221,7 @@ Drupal.jsAC.prototype.found = function (matches) {
for (key in matches) {
$('<li></li>')
.html($('<div></div>').html(matches[key]))
- .mousedown(function () { ac.select(this); })
+ .mousedown(function () { ac.hidePopup(this); })
.mouseover(function () { ac.highlight(this); })
.mouseout(function () { ac.unhighlight(this); })
.data('autocompleteValue', key)
+18 -17
View File
@@ -4,16 +4,16 @@
* @file
* Administrative script for running authorized file operations.
*
* Using this script, the site owner (the user actually owning the files on
* the webserver) can authorize certain file-related operations to proceed
* with elevated privileges, for example to deploy and upgrade modules or
* themes. Users should not visit this page directly, but instead use an
* administrative user interface which knows how to redirect the user to this
* script as part of a multistep process. This script actually performs the
* selected operations without loading all of Drupal, to be able to more
* gracefully recover from errors. Access to the script is controlled by a
* global killswitch in settings.php ('allow_authorize_operations') and via
* the 'administer software updates' permission.
* Using this script, the site owner (the user actually owning the files on the
* webserver) can authorize certain file-related operations to proceed with
* elevated privileges, for example to deploy and upgrade modules or themes.
* Users should not visit this page directly, but instead use an administrative
* user interface which knows how to redirect the user to this script as part of
* a multistep process. This script actually performs the selected operations
* without loading all of Drupal, to be able to more gracefully recover from
* errors. Access to the script is controlled by a global killswitch in
* settings.php ('allow_authorize_operations') and via the 'administer software
* updates' permission.
*
* There are helper functions for setting up an operation to run via this
* system in modules/system/system.module. For more information, see:
@@ -21,16 +21,17 @@
*/
/**
* Root directory of Drupal installation.
* Defines the root directory of the Drupal installation.
*/
define('DRUPAL_ROOT', getcwd());
/**
* Global flag to identify update.php and authorize.php runs, and so
* avoid various unwanted operations, such as hook_init() and
* hook_exit() invokes, css/js preprocessing and translation, and
* solve some theming issues. This flag is checked on several places
* in Drupal code (not just authorize.php).
* Global flag to identify update.php and authorize.php runs.
*
* Identifies update.php and authorize.php runs, avoiding unwanted operations
* such as hook_init() and hook_exit() invokes, css/js preprocessing and
* translation, and solves some theming issues. The flag is checked in other
* places in Drupal code (not just authorize.php).
*/
define('MAINTENANCE_MODE', 'update');
@@ -51,7 +52,7 @@ function authorize_access_denied_page() {
* have access to the 'administer software updates' permission.
*
* @return
* TRUE if the current user can run authorize.php, otherwise FALSE.
* TRUE if the current user can run authorize.php, and FALSE if not.
*/
function authorize_access_allowed() {
return variable_get('allow_authorize_operations', TRUE) && user_access('administer software updates');
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

+5 -4
View File
@@ -168,7 +168,7 @@
* displayed while awaiting a response from the callback, and add an optional
* message. Possible keys: 'type', 'message', 'url', 'interval'.
* More information is available in the
* @link http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html/7 Form API Reference @endlink
* @link forms_api_reference.html Form API Reference @endlink
*
* In addition to using Form API for doing in-form modification, Ajax may be
* enabled by adding classes to buttons and links. By adding the 'use-ajax'
@@ -251,8 +251,8 @@ function ajax_render($commands = array()) {
// reliably diffed with array_diff_key(), since the number can change
// due to factors unrelated to the inline content, so for now, we strip
// the inline items from Ajax responses, and can add support for them
// when drupal_add_css() and drupal_add_js() are changed to using md5()
// or some other hash of the inline content.
// when drupal_add_css() and drupal_add_js() are changed to use a hash
// of the inline content as the array key.
foreach ($items[$type] as $key => $item) {
if (is_numeric($key)) {
unset($items[$type][$key]);
@@ -836,7 +836,8 @@ function ajax_command_insert($selector, $html, $settings = NULL) {
* @return
* An array suitable for use with the ajax_render() function.
*
* See @link http://docs.jquery.com/Manipulation/replaceWith#content jQuery replaceWith command @endlink
* See
* @link http://docs.jquery.com/Manipulation/replaceWith#content jQuery replaceWith command @endlink
*/
function ajax_command_replace($selector, $html, $settings = NULL) {
return array(
+1 -1
View File
@@ -18,7 +18,7 @@ function authorize_filetransfer_form($form, &$form_state) {
global $base_url, $is_https;
$form = array();
// If possible, we want to post this form securely via https.
// If possible, we want to post this form securely via HTTPS.
$form['#https'] = TRUE;
// CSS we depend on lives in modules/system/maintenance.css, which is loaded
+108 -90
View File
@@ -8,7 +8,7 @@
/**
* The current system version.
*/
define('VERSION', '7.15');
define('VERSION', '7.22');
/**
* Core API compatibility.
@@ -25,6 +25,21 @@ define('DRUPAL_MINIMUM_PHP', '5.2.4');
*/
define('DRUPAL_MINIMUM_PHP_MEMORY_LIMIT', '32M');
/**
* Error reporting level: display no errors.
*/
define('ERROR_REPORTING_HIDE', 0);
/**
* Error reporting level: display errors and warnings.
*/
define('ERROR_REPORTING_DISPLAY_SOME', 1);
/**
* Error reporting level: display all messages.
*/
define('ERROR_REPORTING_DISPLAY_ALL', 2);
/**
* Indicates that the item should never be removed unless explicitly selected.
*
@@ -498,56 +513,12 @@ function timer_stop($name) {
}
/**
* Finds the appropriate configuration directory.
* Returns the appropriate configuration directory.
*
* Finds a matching configuration directory by stripping the website's
* hostname from left to right and pathname from right to left. The first
* configuration file found will be used and the remaining ones will be ignored.
* If no configuration file is found, return a default value '$confdir/default'.
*
* With a site located at http://www.example.com:8080/mysite/test/, the file,
* settings.php, is searched for in the following directories:
*
* - $confdir/8080.www.example.com.mysite.test
* - $confdir/www.example.com.mysite.test
* - $confdir/example.com.mysite.test
* - $confdir/com.mysite.test
*
* - $confdir/8080.www.example.com.mysite
* - $confdir/www.example.com.mysite
* - $confdir/example.com.mysite
* - $confdir/com.mysite
*
* - $confdir/8080.www.example.com
* - $confdir/www.example.com
* - $confdir/example.com
* - $confdir/com
*
* - $confdir/default
*
* If a file named sites.php is present in the $confdir, it will be loaded
* prior to scanning for directories. It should define an associative array
* named $sites, which maps domains to directories. It should be in the form
* of:
* @code
* $sites = array(
* 'The url to alias' => 'A directory within the sites directory'
* );
* @endcode
* For example:
* @code
* $sites = array(
* 'devexample.com' => 'example.com',
* 'localhost.example' => 'example.com',
* );
* @endcode
* The above array will cause Drupal to look for a directory named
* "example.com" in the sites directory whenever a request comes from
* "example.com", "devexample.com", or "localhost/example". That is useful
* on development servers, where the domain name may not be the same as the
* domain of the live server. Since Drupal stores file paths into the database
* (files, system table, etc.) this will ensure the paths are correct while
* accessed on development servers.
* Returns the configuration path based on the site's hostname, port, and
* pathname. Uses find_conf_path() to find the current configuration directory.
* See default.settings.php for examples on how the URL is converted to a
* directory.
*
* @param bool $require_settings
* Only configuration directories with an existing settings.php file
@@ -560,6 +531,8 @@ function timer_stop($name) {
*
* @return
* The path of the matching directory.
*
* @see default.settings.php
*/
function conf_path($require_settings = TRUE, $reset = FALSE) {
$conf = &drupal_static(__FUNCTION__, '');
@@ -731,7 +704,7 @@ function drupal_valid_http_host($host) {
function drupal_settings_initialize() {
global $base_url, $base_path, $base_root;
// Export the following settings.php variables to the global namespace
// Export these settings.php variables to the global namespace.
global $databases, $cookie_domain, $conf, $installed_profile, $update_free_access, $db_url, $db_prefix, $drupal_hash_salt, $is_https, $base_secure_url, $base_insecure_url;
$conf = array();
@@ -743,7 +716,6 @@ function drupal_settings_initialize() {
if (isset($base_url)) {
// Parse fixed base URL from settings.php.
$parts = parse_url($base_url);
$http_protocol = $parts['scheme'];
if (!isset($parts['path'])) {
$parts['path'] = '';
}
@@ -752,7 +724,7 @@ function drupal_settings_initialize() {
$base_root = substr($base_url, 0, strlen($base_url) - strlen($parts['path']));
}
else {
// Create base URL
// Create base URL.
$http_protocol = $is_https ? 'https' : 'http';
$base_root = $http_protocol . '://' . $_SERVER['HTTP_HOST'];
@@ -778,7 +750,7 @@ function drupal_settings_initialize() {
}
else {
// Otherwise use $base_url as session name, without the protocol
// to use the same session identifiers across http and https.
// to use the same session identifiers across HTTP and HTTPS.
list( , $session_name) = explode('://', $base_url, 2);
// HTTP_HOST can be modified by a visitor, but we already sanitized it
// in drupal_settings_initialize().
@@ -838,7 +810,7 @@ function drupal_settings_initialize() {
* than by consulting the database.
*
* @return
* The filename of the requested item.
* The filename of the requested item or NULL if the item is not found.
*/
function drupal_get_filename($type, $name, $filename = NULL) {
// The location of files will not change during the request, so do not use
@@ -1213,10 +1185,11 @@ function _drupal_set_preferred_header_name($name = NULL) {
* Headers are set in drupal_add_http_header(). Default headers are not set
* if they have been replaced or unset using drupal_add_http_header().
*
* @param $default_headers
* An array of headers as name/value pairs.
* @param $single
* If TRUE and headers have already be sent, send only the specified header.
* @param array $default_headers
* (optional) An array of headers as name/value pairs.
* @param bool $only_default
* (optional) If TRUE and headers have already been sent, send only the
* specified headers.
*/
function drupal_send_headers($default_headers = array(), $only_default = FALSE) {
$headers_sent = &drupal_static(__FUNCTION__, FALSE);
@@ -1239,7 +1212,7 @@ function drupal_send_headers($default_headers = array(), $only_default = FALSE)
header($_SERVER['SERVER_PROTOCOL'] . ' ' . $value);
}
// Skip headers that have been unset.
elseif ($value) {
elseif ($value !== FALSE) {
header($header_names[$name_lower] . ': ' . $value);
}
}
@@ -1447,8 +1420,9 @@ function drupal_unpack($obj, $field = 'data') {
* Basically, you can put variables like @name into your string, and t() will
* substitute their sanitized values at translation time. (See the
* Localization API pages referenced above and the documentation of
* format_string() for details.) Translators can then rearrange the string as
* necessary for the language (e.g., in Spanish, it might be "blog de @name").
* format_string() for details about how to define variables in your string.)
* Translators can then rearrange the string as necessary for the language
* (e.g., in Spanish, it might be "blog de @name").
*
* During the Drupal installation phase, some resources used by t() wil not be
* available to code that needs localization. See st() and get_t() for
@@ -1511,21 +1485,34 @@ function t($string, array $args = array(), array $options = array()) {
}
/**
* Replaces placeholders with sanitized values in a string.
* Formats a string for HTML display by replacing variable placeholders.
*
* This function replaces variable placeholders in a string with the requested
* values and escapes the values so they can be safely displayed as HTML. It
* should be used on any unknown text that is intended to be printed to an HTML
* page (especially text that may have come from untrusted users, since in that
* case it prevents cross-site scripting and other security problems).
*
* In most cases, you should use t() rather than calling this function
* directly, since it will translate the text (on non-English-only sites) in
* addition to formatting it.
*
* @param $string
* A string containing placeholders.
* @param $args
* An associative array of replacements to make. Occurrences in $string of
* any key in $args are replaced with the corresponding value, after
* sanitization. The sanitization function depends on the first character of
* the key:
* - !variable: Inserted as is. Use this for text that has already been
* sanitized.
* - @variable: Escaped to HTML using check_plain(). Use this for anything
* displayed on a page on the site.
* - %variable: Escaped as a placeholder for user-submitted content using
* drupal_placeholder(), which shows up as <em>emphasized</em> text.
* any key in $args are replaced with the corresponding value, after optional
* sanitization and formatting. The type of sanitization and formatting
* depends on the first character of the key:
* - @variable: Escaped to HTML using check_plain(). Use this as the default
* choice for anything displayed on a page on the site.
* - %variable: Escaped to HTML and formatted using drupal_placeholder(),
* which makes it display as <em>emphasized</em> text.
* - !variable: Inserted as is, with no sanitization or formatting. Only use
* this for text that has already been prepared for HTML display (for
* example, user-supplied text that has already been run through
* check_plain() previously, or is expected to contain some limited HTML
* tags and has already been run through filter_xss() previously).
*
* @see t()
* @ingroup sanitization
@@ -1732,7 +1719,8 @@ function watchdog($type, $message, $variables = array(), $severity = WATCHDOG_NO
'request_uri' => $base_root . request_uri(),
'referer' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '',
'ip' => ip_address(),
'timestamp' => REQUEST_TIME,
// Request time isn't accurate for long processes, use time() instead.
'timestamp' => time(),
);
// Call the logging hooks to log/process the message
@@ -1798,18 +1786,29 @@ function drupal_set_message($message = NULL, $type = 'status', $repeat = TRUE) {
}
/**
* Returns all messages that have been set.
* Returns all messages that have been set with drupal_set_message().
*
* @param $type
* (optional) Only return messages of this type.
* @param $clear_queue
* (optional) Set to FALSE if you do not want to clear the messages queue
* @param string $type
* (optional) Limit the messages returned by type. Defaults to NULL, meaning
* all types. These values are supported:
* - NULL
* - 'status'
* - 'warning'
* - 'error'
* @param bool $clear_queue
* (optional) If this is TRUE, the queue will be cleared of messages of the
* type specified in the $type parameter. Otherwise the queue will be left
* intact. Defaults to TRUE.
*
* @return
* An associative array, the key is the message type, the value an array
* of messages. If the $type parameter is passed, you get only that type,
* or an empty array if there are no such messages. If $type is not passed,
* all message types are returned, or an empty array if none exist.
* @return array
* A multidimensional array with keys corresponding to the set message types.
* The indexed array values of each contain the set messages for that type.
* The messages returned are limited to the type specified in the $type
* parameter. If there are no messages of the specified type, an empty array
* is returned.
*
* @see drupal_set_message()
* @see theme_status_messages()
*/
function drupal_get_messages($type = NULL, $clear_queue = TRUE) {
if ($messages = drupal_set_message()) {
@@ -2115,14 +2114,26 @@ function drupal_anonymous_user() {
/**
* Ensures Drupal is bootstrapped to the specified phase.
*
* The bootstrap phase is an integer constant identifying a phase of Drupal
* to load. Each phase adds to the previous one, so invoking a later phase
* automatically runs the earlier phases as well. To access the Drupal
* database from a script without loading anything else, include bootstrap.inc
* and call drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE).
* In order to bootstrap Drupal from another PHP script, you can use this code:
* @code
* define('DRUPAL_ROOT', '/path/to/drupal');
* require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
* drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
* @endcode
*
* @param $phase
* A constant. Allowed values are the DRUPAL_BOOTSTRAP_* constants.
* A constant telling which phase to bootstrap to. When you bootstrap to a
* particular phase, all earlier phases are run automatically. Possible
* values:
* - DRUPAL_BOOTSTRAP_CONFIGURATION: Initializes configuration.
* - DRUPAL_BOOTSTRAP_PAGE_CACHE: Tries to serve a cached page.
* - DRUPAL_BOOTSTRAP_DATABASE: Initializes the database layer.
* - DRUPAL_BOOTSTRAP_VARIABLES: Initializes the variable system.
* - DRUPAL_BOOTSTRAP_SESSION: Initializes session handling.
* - DRUPAL_BOOTSTRAP_PAGE_HEADER: Sets up the page header.
* - DRUPAL_BOOTSTRAP_LANGUAGE: Finds out the language of the page.
* - DRUPAL_BOOTSTRAP_FULL: Fully loads Drupal. Validates and fixes input
* data.
* @param $new_phase
* A boolean, set to FALSE if calling drupal_bootstrap from inside a
* function called from drupal_bootstrap (recursion).
@@ -2521,7 +2532,7 @@ function drupal_fast_404() {
$fast_paths = variable_get('404_fast_paths', FALSE);
if ($fast_paths && preg_match($fast_paths, $_GET['q'])) {
drupal_add_http_header('Status', '404 Not Found');
$fast_404_html = variable_get('404_fast_html', '<html xmlns="http://www.w3.org/1999/xhtml"><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "@path" was not found on this server.</p></body></html>');
$fast_404_html = variable_get('404_fast_html', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "@path" was not found on this server.</p></body></html>');
// Replace @path in the variable with the page path.
print strtr($fast_404_html, array('@path' => check_plain(request_uri())));
exit;
@@ -2614,6 +2625,9 @@ function drupal_language_types() {
/**
* Returns TRUE if there is more than one language enabled.
*
* @return
* TRUE if more than one language is enabled.
*/
function drupal_multilingual() {
// The "language_count" variable stores the number of enabled languages to
@@ -2624,6 +2638,10 @@ function drupal_multilingual() {
/**
* Returns an array of the available language types.
*
* @return
* An array of all language types where the keys of each are the language type
* name and its value is its configurability (TRUE/FALSE).
*/
function language_types() {
return array_keys(variable_get('language_types', drupal_language_types()));
+28 -41
View File
@@ -80,43 +80,15 @@ function cache_get_multiple(array &$cids, $bin = 'cache') {
* 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.
* might break functionality or are extremely expensive to recalculate. The
* other bins are expired automatically by core. Contributed modules can add
* additional bins and get them expired automatically by implementing
* hook_flush_caches().
*
* 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
* - 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.
@@ -125,13 +97,27 @@ function cache_get_multiple(array &$cids, $bin = 'cache') {
* 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.
* serialized before insertion. Strings will be stored as plain text and are
* 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.
* The cache bin to store the data in. Valid core values are:
* - cache: (default) Generic cache storage bin (used for theme registry,
* locale date, list of simpletest tests, etc.).
* - cache_block: Stores the content of various blocks.
* - cache_bootstrap: Stores the class registry, the system list of modules,
* the list of which modules implement which hooks, and the Drupal variable
* list.
* - 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. This bin should not be flushed before its expired time.
* - 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 node 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.
* @param $expire
* One of the following values:
* - CACHE_PERMANENT: Indicates that the item should never be removed unless
@@ -141,6 +127,7 @@ function cache_get_multiple(array &$cids, $bin = 'cache') {
* - A Unix timestamp: Indicates that the item should be kept at least until
* the given time, after which it behaves like CACHE_TEMPORARY.
*
* @see _update_cache_set()
* @see cache_get()
*/
function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT) {
+158 -57
View File
@@ -92,14 +92,20 @@ define('JS_THEME', 100);
define('HTTP_REQUEST_TIMEOUT', -1);
/**
* Constants defining cache granularity for blocks and renderable arrays.
* @defgroup block_caching Block Caching
* @{
* Constants that define each block's caching state.
*
* Modules specify the caching patterns for their blocks using binary
* combinations of these constants in their hook_block_info():
* $block[delta]['cache'] = DRUPAL_CACHE_PER_ROLE | DRUPAL_CACHE_PER_PAGE;
* DRUPAL_CACHE_PER_ROLE is used as a default when no caching pattern is
* specified. Use DRUPAL_CACHE_CUSTOM to disable standard block cache and
* implement
* Modules specify how their blocks can be cached in their hook_block_info()
* implementations. Caching can be turned off (DRUPAL_NO_CACHE), managed by the
* module declaring the block (DRUPAL_CACHE_CUSTOM), or managed by the core
* Block module. If the Block module is managing the cache, you can specify that
* the block is the same for every page and user (DRUPAL_CACHE_GLOBAL), or that
* it can change depending on the page (DRUPAL_CACHE_PER_PAGE) or by user
* (DRUPAL_CACHE_PER_ROLE or DRUPAL_CACHE_PER_USER). Page and user settings can
* be combined with a bitwise-binary or operator; for example,
* DRUPAL_CACHE_PER_ROLE | DRUPAL_CACHE_PER_PAGE means that the block can change
* depending on the user role or page it is on.
*
* The block cache is cleared in cache_clear_all(), and uses the same clearing
* policy than page cache (node, comment, user, taxonomy added or updated...).
@@ -123,9 +129,8 @@ define('DRUPAL_NO_CACHE', -1);
/**
* The block is handling its own caching in its hook_block_view().
*
* From the perspective of the block cache system, this is equivalent to
* DRUPAL_NO_CACHE. Useful when time based expiration is needed or a site uses
* a node access which invalidates standard block cache.
* This setting is useful when time based expiration is needed or a site uses a
* node access which invalidates standard block cache.
*/
define('DRUPAL_CACHE_CUSTOM', -2);
@@ -155,6 +160,10 @@ define('DRUPAL_CACHE_PER_PAGE', 0x0004);
*/
define('DRUPAL_CACHE_GLOBAL', 0x0008);
/**
* @} End of "defgroup block_caching".
*/
/**
* Adds content to a specified region.
*
@@ -199,7 +208,7 @@ function drupal_get_region_content($region = NULL, $delimiter = ' ') {
}
/**
* Gets the name of the currently active install profile.
* Gets the name of the currently active installation profile.
*
* When this function is called during Drupal's initial installation process,
* the name of the profile that's about to be installed is stored in the global
@@ -208,7 +217,7 @@ function drupal_get_region_content($region = NULL, $delimiter = ' ') {
* variable_get() to determine what one is active.
*
* @return $profile
* The name of the install profile.
* The name of the installation profile.
*/
function drupal_get_profile() {
global $install_state;
@@ -272,7 +281,7 @@ function drupal_get_rdf_namespaces() {
/**
* Adds output to the HEAD tag of the HTML page.
*
* This function can be called as long the headers aren't sent. Pass no
* This function can be called as long as the headers aren't sent. Pass no
* arguments (or NULL for both) to retrieve the currently stored elements.
*
* @param $data
@@ -443,7 +452,7 @@ function drupal_get_query_parameters(array $query = NULL, array $exclude = array
* The query string to split.
*
* @return
* An array of url decoded couples $param_name => $value.
* An array of URL decoded couples $param_name => $value.
*/
function drupal_get_query_array($query) {
$result = array();
@@ -505,6 +514,12 @@ function drupal_http_build_query(array $query, $parent = '') {
* previous request, that destination is returned. As such, a destination can
* persist across multiple pages.
*
* @return
* An associative array containing the key:
* - destination: The path provided via the destination query string or, if
* not available, the current path.
*
* @see current_path()
* @see drupal_goto()
*/
function drupal_get_destination() {
@@ -770,6 +785,13 @@ function drupal_access_denied() {
* - data: A string containing the response body that was received.
*/
function drupal_http_request($url, array $options = array()) {
// Allow an alternate HTTP client library to replace Drupal's default
// implementation.
$override_function = variable_get('drupal_http_request_function', FALSE);
if (!empty($override_function) && function_exists($override_function)) {
return $override_function($url, $options);
}
$result = new stdClass();
// Parse the URL and make sure we can handle the schema.
@@ -798,10 +820,51 @@ function drupal_http_request($url, array $options = array()) {
'timeout' => 30.0,
'context' => NULL,
);
// Merge the default headers.
$options['headers'] += array(
'User-Agent' => 'Drupal (+http://drupal.org/)',
);
// stream_socket_client() requires timeout to be a float.
$options['timeout'] = (float) $options['timeout'];
// Use a proxy if one is defined and the host is not on the excluded list.
$proxy_server = variable_get('proxy_server', '');
if ($proxy_server && _drupal_http_use_proxy($uri['host'])) {
// Set the scheme so we open a socket to the proxy server.
$uri['scheme'] = 'proxy';
// Set the path to be the full URL.
$uri['path'] = $url;
// Since the URL is passed as the path, we won't use the parsed query.
unset($uri['query']);
// Add in username and password to Proxy-Authorization header if needed.
if ($proxy_username = variable_get('proxy_username', '')) {
$proxy_password = variable_get('proxy_password', '');
$options['headers']['Proxy-Authorization'] = 'Basic ' . base64_encode($proxy_username . (!empty($proxy_password) ? ":" . $proxy_password : ''));
}
// Some proxies reject requests with any User-Agent headers, while others
// require a specific one.
$proxy_user_agent = variable_get('proxy_user_agent', '');
// The default value matches neither condition.
if ($proxy_user_agent === NULL) {
unset($options['headers']['User-Agent']);
}
elseif ($proxy_user_agent) {
$options['headers']['User-Agent'] = $proxy_user_agent;
}
}
switch ($uri['scheme']) {
case 'proxy':
// Make the socket connection to a proxy server.
$socket = 'tcp://' . $proxy_server . ':' . variable_get('proxy_port', 8080);
// The Host header still needs to match the real request.
$options['headers']['Host'] = $uri['host'];
$options['headers']['Host'] .= isset($uri['port']) && $uri['port'] != 80 ? ':' . $uri['port'] : '';
break;
case 'http':
case 'feed':
$port = isset($uri['port']) ? $uri['port'] : 80;
@@ -811,12 +874,14 @@ function drupal_http_request($url, array $options = array()) {
// checking the host that do not take into account the port number.
$options['headers']['Host'] = $uri['host'] . ($port != 80 ? ':' . $port : '');
break;
case 'https':
// Note: Only works when PHP is compiled with OpenSSL support.
$port = isset($uri['port']) ? $uri['port'] : 443;
$socket = 'ssl://' . $uri['host'] . ':' . $port;
$options['headers']['Host'] = $uri['host'] . ($port != 443 ? ':' . $port : '');
break;
default:
$result->error = 'invalid schema ' . $uri['scheme'];
$result->code = -1003;
@@ -853,11 +918,6 @@ function drupal_http_request($url, array $options = array()) {
$path .= '?' . $uri['query'];
}
// Merge the default headers.
$options['headers'] += array(
'User-Agent' => 'Drupal (+http://drupal.org/)',
);
// Only add Content-Length if we actually have any content or if it is a POST
// or PUT request. Some non-standard servers get confused by Content-Length in
// at least HEAD/GET requests, and Squid always requires Content-Length in
@@ -1028,6 +1088,18 @@ function drupal_http_request($url, array $options = array()) {
return $result;
}
/**
* Helper function for determining hosts excluded from needing a proxy.
*
* @return
* TRUE if a proxy should be used for this host.
*/
function _drupal_http_use_proxy($host) {
$proxy_exceptions = variable_get('proxy_exceptions', array('localhost', '127.0.0.1'));
return !in_array(strtolower($host), $proxy_exceptions, TRUE);
}
/**
* @} End of "HTTP handling".
*/
@@ -1102,7 +1174,8 @@ function fix_gpc_magic() {
/**
* Verifies the syntax of the given e-mail address.
*
* See @link http://tools.ietf.org/html/rfc5321 RFC 5321 @endlink for details.
* This uses the
* @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
*
* @param $mail
* A string containing an e-mail address.
@@ -1701,7 +1774,7 @@ function format_xml_elements($array) {
* $output = format_plural($update_count,
* 'Changed the content type of 1 post from %old-type to %new-type.',
* 'Changed the content type of @count posts from %old-type to %new-type.',
* array('%old-type' => $info->old_type, '%new-type' => $info->new_type)));
* array('%old-type' => $info->old_type, '%new-type' => $info->new_type));
* @endcode
*
* @param $count
@@ -2079,7 +2152,7 @@ function format_username($account) {
* for the URL. If $options['language'] is omitted, the global $language_url
* will be used.
* - 'https': Whether this URL should point to a secure location. If not
* defined, the current scheme is used, so the user stays on http or https
* defined, the current scheme is used, so the user stays on HTTP or HTTPS
* respectively. TRUE enforces HTTPS and FALSE enforces HTTP, but HTTPS can
* only be enforced when the variable 'https' is set to TRUE.
* - 'base_url': Only used internally, to modify the base URL when a language
@@ -2309,21 +2382,30 @@ function drupal_attributes(array $attributes = array()) {
/**
* Formats an internal or external URL link as an HTML anchor tag.
*
* This function correctly handles aliased paths, and adds an 'active' class
* This function correctly handles aliased paths and adds an 'active' class
* attribute to links that point to the current page (for theming), so all
* internal links output by modules should be generated by this function if
* possible.
*
* @param $text
* The link text for the anchor tag.
* @param $path
* However, for links enclosed in translatable text you should use t() and
* embed the HTML anchor tag directly in the translated string. For example:
* @code
* t('Visit the <a href="@url">settings</a> page', array('@url' => url('admin')));
* @endcode
* This keeps the context of the link title ('settings' in the example) for
* translators.
*
* @param string $text
* The translated link text for the anchor tag.
* @param string $path
* The internal path or external URL being linked to, such as "node/34" or
* "http://example.com/foo". After the url() function is called to construct
* the URL from $path and $options, the resulting URL is passed through
* check_plain() before it is inserted into the HTML anchor tag, to ensure
* well-formed HTML. See url() for more information and notes.
* @param array $options
* An associative array of additional options, with the following elements:
* An associative array of additional options. Defaults to an empty array. It
* may contain the following elements.
* - 'attributes': An associative array of HTML attributes to apply to the
* anchor tag. If element 'class' is included, it must be an array; 'title'
* must be a string; other elements are more flexible, as they just need
@@ -2339,8 +2421,10 @@ function drupal_attributes(array $attributes = array()) {
* well as the path must match). This element is also used by url().
* - Additional $options elements used by the url() function.
*
* @return
* @return string
* An HTML string containing a link to the given path.
*
* @see url()
*/
function l($text, $path, array $options = array()) {
global $language_url;
@@ -2711,7 +2795,7 @@ function drupal_set_time_limit($time_limit) {
* The name of the item for which the path is requested.
*
* @return
* The path to the requested item.
* The path to the requested item or an empty string if the item is not found.
*/
function drupal_get_path($type, $name) {
return dirname(drupal_get_filename($type, $name));
@@ -3801,7 +3885,16 @@ function drupal_html_id($id) {
// requested id. $_POST['ajax_html_ids'] contains the ids as they were
// returned by this function, potentially with the appended counter, so
// we parse that to reconstruct the $seen_ids array.
foreach ($_POST['ajax_html_ids'] as $seen_id) {
if (is_array($_POST['ajax_html_ids'])) {
$ajax_html_ids = $_POST['ajax_html_ids'];
}
else {
// jquery.form.js may send the server a comma-separated string instead
// of an array (see http://drupal.org/node/1575060), so we need to
// convert it to an array in that case.
$ajax_html_ids = explode(',', $_POST['ajax_html_ids']);
}
foreach ($ajax_html_ids as $seen_id) {
// We rely on '--' being used solely for separating a base id from the
// counter, which this function ensures when returning an id.
$parts = explode('--', $seen_id, 2);
@@ -3927,7 +4020,8 @@ function drupal_region_class($region) {
* actually needed.
*
* @param $data
* (optional) If given, the value depends on the $options parameter:
* (optional) If given, the value depends on the $options parameter, or
* $options['type'] if $options is passed as an associative array:
* - 'file': Path to the file relative to base_path().
* - 'inline': The JavaScript code that should be placed in the given scope.
* - 'external': The absolute path to an external JavaScript file that is not
@@ -4969,6 +5063,11 @@ function drupal_get_private_key() {
*
* @param $value
* An additional value to base the token on.
*
* @return string
* A 43-character URL-safe token for validation, based on the user session ID,
* the global $drupal_hash_salt variable from settings.php, and the
* 'drupal_private_key' configuration variable.
*/
function drupal_get_token($value = '') {
return drupal_hmac_base64($value, session_id() . drupal_get_private_key() . drupal_get_hash_salt());
@@ -5114,6 +5213,7 @@ function drupal_cron_run() {
@ignore_user_abort(TRUE);
// Prevent session information from being saved while cron is running.
$original_session_saving = drupal_save_session();
drupal_save_session(FALSE);
// Force the current user to anonymous to ensure consistent permissions on
@@ -5176,7 +5276,7 @@ function drupal_cron_run() {
}
// Restore the user.
$GLOBALS['user'] = $original_user;
drupal_save_session(TRUE);
drupal_save_session($original_session_saving);
return $return;
}
@@ -5208,7 +5308,7 @@ function drupal_cron_cleanup() {
* drupal_system_listing("/\.module$/", "modules", 'name', 0);
* @endcode
* this function will search the site-wide modules directory (i.e., /modules/),
* your install profile's directory (i.e.,
* your installation profile's directory (i.e.,
* /profiles/your_site_profile/modules/), the all-sites directory (i.e.,
* /sites/all/modules/), and your site-specific directory (i.e.,
* /sites/your_site_dir/modules/), in that order, and return information about
@@ -5498,7 +5598,7 @@ function drupal_pre_render_link($element) {
* @code
* $node->content['links'] = array(
* '#theme' => 'links__node',
* '#pre_render' = array('drupal_pre_render_links'),
* '#pre_render' => array('drupal_pre_render_links'),
* 'comment' => array(
* '#theme' => 'links__node__comment',
* '#links' => array(
@@ -7449,12 +7549,12 @@ function drupal_check_incompatibility($v, $current_version) {
/**
* Get the entity info array of an entity type.
*
* @see hook_entity_info()
* @see hook_entity_info_alter()
*
* @param $entity_type
* The entity type, e.g. node, for which the info shall be returned, or NULL
* to return an array with info about all types.
*
* @see hook_entity_info()
* @see hook_entity_info_alter()
*/
function entity_get_info($entity_type = NULL) {
global $language;
@@ -7542,12 +7642,13 @@ function entity_info_cache_clear() {
* The entity type; e.g. 'node' or 'user'.
* @param $entity
* The entity from which to extract values.
*
* @return
* A numerically indexed array (not a hash table) containing these
* elements:
* 0: primary id of the entity
* 1: revision id of the entity, or NULL if $entity_type is not versioned
* 2: bundle name of the entity
* - 0: Primary ID of the entity.
* - 1: Revision ID of the entity, or NULL if $entity_type is not versioned.
* - 2: Bundle name of the entity, or NULL if $entity_type has no bundles.
*/
function entity_extract_ids($entity_type, $entity) {
$info = entity_get_info($entity_type);
@@ -7580,13 +7681,12 @@ function entity_extract_ids($entity_type, $entity) {
* @param $entity_type
* The entity type; e.g. 'node' or 'user'.
* @param $ids
* A numerically indexed array, as returned by entity_extract_ids(),
* containing these elements:
* 0: primary id of the entity
* 1: revision id of the entity, or NULL if $entity_type is not versioned
* 2: bundle name of the entity, or NULL if $entity_type has no bundles
* A numerically indexed array, as returned by entity_extract_ids().
*
* @return
* An entity structure, initialized with the ids provided.
*
* @see entity_extract_ids()
*/
function entity_create_stub_entity($entity_type, $ids) {
$entity = new stdClass();
@@ -7616,11 +7716,6 @@ function entity_create_stub_entity($entity_type, $ids) {
* DrupalDefaultEntityController class. See node_entity_info() and the
* NodeController in node.module as an example.
*
* @see hook_entity_info()
* @see DrupalEntityControllerInterface
* @see DrupalDefaultEntityController
* @see EntityFieldQuery
*
* @param $entity_type
* The entity type to load, e.g. node or user.
* @param $ids
@@ -7638,6 +7733,11 @@ function entity_create_stub_entity($entity_type, $ids) {
* found, an empty array is returned.
*
* @todo Remove $conditions in Drupal 8.
*
* @see hook_entity_info()
* @see DrupalEntityControllerInterface
* @see DrupalDefaultEntityController
* @see EntityFieldQuery
*/
function entity_load($entity_type, $ids = FALSE, $conditions = array(), $reset = FALSE) {
if ($reset) {
@@ -7657,7 +7757,7 @@ function entity_load($entity_type, $ids = FALSE, $conditions = array(), $reset =
* @param $entity_type
* The entity type to load, e.g. node or user.
* @param $id
* The id of the entity to load.
* The ID of the entity to load.
*
* @return
* The unchanged entity, or FALSE if the entity cannot be loaded.
@@ -7694,7 +7794,6 @@ function entity_get_controller($entity_type) {
* recursion. By convention, entity_prepare_view() is called after
* field_attach_prepare_view() to allow entity level hooks to act on content
* loaded by field API.
* @see hook_entity_prepare_view()
*
* @param $entity_type
* The type of entity, i.e. 'node', 'user'.
@@ -7703,6 +7802,8 @@ function entity_get_controller($entity_type) {
* @param $langcode
* (optional) A language code to be used for rendering. Defaults to the global
* content language of the current request.
*
* @see hook_entity_prepare_view()
*/
function entity_prepare_view($entity_type, $entities, $langcode = NULL) {
if (!isset($langcode)) {
@@ -7729,16 +7830,16 @@ function entity_prepare_view($entity_type, $entities, $langcode = NULL) {
}
/**
* Returns the uri elements of an entity.
* Returns the URI elements of an entity.
*
* @param $entity_type
* The entity type; e.g. 'node' or 'user'.
* @param $entity
* The entity for which to generate a path.
* @return
* An array containing the 'path' and 'options' keys used to build the uri of
* An array containing the 'path' and 'options' keys used to build the URI of
* the entity, and matching the signature of url(). NULL if the entity has no
* uri of its own.
* URI of its own.
*/
function entity_uri($entity_type, $entity) {
$info = entity_get_info($entity_type);
@@ -7833,7 +7934,7 @@ function entity_language($entity_type, $entity) {
}
/**
* Helper function for attaching field API validation to entity forms.
* Attaches field API validation to entity forms.
*/
function entity_form_field_validate($entity_type, $form, &$form_state) {
// All field attach API functions act on an entity object, but during form
@@ -7846,7 +7947,7 @@ function entity_form_field_validate($entity_type, $form, &$form_state) {
}
/**
* Helper function for copying submitted values to entity properties for simple entity forms.
* Copies submitted values to entity properties for simple entity forms.
*
* During the submission handling of an entity form's "Save", "Preview", and
* possibly other buttons, the form state's entity needs to be updated with the
+37 -8
View File
@@ -167,7 +167,7 @@
* }
* @endcode
*
* @link http://drupal.org/developing/api/database
* @see http://drupal.org/developing/api/database
*/
@@ -194,7 +194,7 @@ abstract class DatabaseConnection extends PDO {
/**
* The key representing this connection.
*
*
* The key is a unique string which identifies a database connection. A
* connection can be a single server or a cluster of master and slaves (use
* target to pick between master and slave).
@@ -303,12 +303,28 @@ abstract class DatabaseConnection extends PDO {
// Call PDO::__construct and PDO::setAttribute.
parent::__construct($dsn, $username, $password, $driver_options);
// Set a specific PDOStatement class if the driver requires that.
// Set a Statement class, unless the driver opted out.
if (!empty($this->statementClass)) {
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array($this->statementClass, array($this)));
}
}
/**
* Destroys this Connection object.
*
* PHP does not destruct an object if it is still referenced in other
* variables. In case of PDO database connection objects, PHP only closes the
* connection when the PDO object is destructed, so any references to this
* object may cause the number of maximum allowed connections to be exceeded.
*/
public function destroy() {
// Destroy all references to this connection by setting them to NULL.
// The Statement class attribute only accepts a new value that presents a
// proper callable, so we reset it to PDOStatement.
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDOStatement', array()));
$this->schema = NULL;
}
/**
* Returns the default query options for any given query.
*
@@ -1627,8 +1643,8 @@ abstract class Database {
*/
final public static function removeConnection($key) {
if (isset(self::$databaseInfo[$key])) {
self::closeConnection(NULL, $key);
unset(self::$databaseInfo[$key]);
unset(self::$connections[$key]);
return TRUE;
}
else {
@@ -1694,11 +1710,24 @@ abstract class Database {
if (!isset($key)) {
$key = self::$activeKey;
}
// To close the connection, we need to unset the static variable.
// To close a connection, it needs to be set to NULL and removed from the
// static variable. In all cases, closeConnection() might be called for a
// connection that was not opened yet, in which case the key is not defined
// yet and we just ensure that the connection key is undefined.
if (isset($target)) {
if (isset(self::$connections[$key][$target])) {
self::$connections[$key][$target]->destroy();
self::$connections[$key][$target] = NULL;
}
unset(self::$connections[$key][$target]);
}
else {
if (isset(self::$connections[$key])) {
foreach (self::$connections[$key] as $target => $connection) {
self::$connections[$key][$target]->destroy();
self::$connections[$key][$target] = NULL;
}
}
unset(self::$connections[$key]);
}
}
@@ -1852,8 +1881,8 @@ class DatabaseTransaction {
*/
protected $name;
public function __construct(DatabaseConnection &$connection, $name = NULL) {
$this->connection = &$connection;
public function __construct(DatabaseConnection $connection, $name = NULL) {
$this->connection = $connection;
// If there is no transaction depth, then no transaction has started. Name
// the transaction 'drupal_transaction'.
if (!$depth = $connection->transactionDepth()) {
@@ -2769,7 +2798,7 @@ function _db_create_keys_sql($spec) {
* Renames a table.
*
* @param $table
* The table to be renamed.
* The current name of the table to be renamed.
* @param $new_name
* The new name for the table.
*/
+6 -4
View File
@@ -128,9 +128,10 @@ class DatabaseLog {
* Determine the routine that called this query.
*
* We define "the routine that called this query" as the first entry in
* the call stack that is not inside includes/database. That makes the
* climbing logic very simple, and handles the variable stack depth caused
* by the query builders.
* the call stack that is not inside includes/database and does have a file
* (which excludes call_user_func_array(), anonymous functions and similar).
* That makes the climbing logic very simple, and handles the variable stack
* depth caused by the query builders.
*
* @link http://www.php.net/debug_backtrace
* @return
@@ -144,7 +145,8 @@ class DatabaseLog {
$stack = debug_backtrace();
$stack_count = count($stack);
for ($i = 0; $i < $stack_count; ++$i) {
if (strpos($stack[$i]['file'], 'includes' . DIRECTORY_SEPARATOR . 'database') === FALSE) {
if (!empty($stack[$i]['file']) && strpos($stack[$i]['file'], 'includes' . DIRECTORY_SEPARATOR . 'database') === FALSE) {
$stack[$i] += array('args' => array());
return array(
'file' => $stack[$i]['file'],
'line' => $stack[$i]['line'],
+9 -8
View File
@@ -13,11 +13,11 @@
class DatabaseConnection_mysql extends DatabaseConnection {
/**
* Flag to indicate if we have registered the nextID cleanup function.
* Flag to indicate if the cleanup function in __destruct() should run.
*
* @var boolean
*/
protected $shutdownRegistered = FALSE;
protected $needsCleanup = FALSE;
public function __construct(array $connection_options = array()) {
// This driver defaults to transaction support, except if explicitly passed FALSE.
@@ -78,6 +78,12 @@ class DatabaseConnection_mysql extends DatabaseConnection {
$this->exec(implode('; ', $connection_options['init_commands']));
}
public function __destruct() {
if ($this->needsCleanup) {
$this->nextIdDelete();
}
}
public function queryRange($query, $from, $count, array $args = array(), array $options = array()) {
return $this->query($query . ' LIMIT ' . (int) $from . ', ' . (int) $count, $args, $options);
}
@@ -115,12 +121,7 @@ class DatabaseConnection_mysql extends DatabaseConnection {
$this->query('INSERT INTO {sequences} (value) VALUES (:value) ON DUPLICATE KEY UPDATE value = value', array(':value' => $existing_id));
$new_id = $this->query('INSERT INTO {sequences} () VALUES ()', array(), array('return' => Database::RETURN_INSERT_ID));
}
if (!$this->shutdownRegistered) {
// Use register_shutdown_function() here to keep the database system
// independent of Drupal.
register_shutdown_function(array($this, 'nextIdDelete'));
$shutdownRegistered = TRUE;
}
$this->needsCleanup = TRUE;
return $new_id;
}
+11
View File
@@ -74,6 +74,17 @@ class DatabaseConnection_pgsql extends DatabaseConnection {
}
}
public function prepareQuery($query) {
// mapConditionOperator converts LIKE operations to ILIKE for consistency
// with MySQL. However, Postgres does not support ILIKE on bytea (blobs)
// fields.
// To make the ILIKE operator work, we type-cast bytea fields into text.
// @todo This workaround only affects bytea fields, but the involved field
// types involved in the query are unknown, so there is no way to
// conditionally execute this for affected queries only.
return parent::prepareQuery(preg_replace('/ ([^ ]+) +(I*LIKE|NOT +I*LIKE) /i', ' ${1}::text ${2} ', $query));
}
public function query($query, array $args = array(), $options = array()) {
$options += $this->defaultOptions();
+7 -2
View File
@@ -1898,8 +1898,13 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
function __clone() {
$this->changed = TRUE;
foreach ($this->conditions as $key => $condition) {
if ($key !== '#conjunction' && $condition['field'] instanceOf QueryConditionInterface) {
$this->conditions[$key]['field'] = clone($condition['field']);
if ($key !== '#conjunction') {
if ($condition['field'] instanceOf QueryConditionInterface) {
$this->conditions[$key]['field'] = clone($condition['field']);
}
if ($condition['value'] instanceOf SelectQueryInterface) {
$this->conditions[$key]['value'] = clone($condition['value']);
}
}
}
}
+3 -24
View File
@@ -57,39 +57,18 @@ class InsertQuery_sqlite extends InsertQuery {
* we don't select those rows.
*
* A query like this one:
* UPDATE test SET name = 'newname' WHERE tid = 1
* UPDATE test SET col1 = 'newcol1', col2 = 'newcol2' WHERE tid = 1
* will become:
* UPDATE test SET name = 'newname' WHERE tid = 1 AND name <> 'newname'
* UPDATE test SET col1 = 'newcol1', col2 = 'newcol2' WHERE tid = 1 AND (col1 <> 'newcol1' OR col2 <> 'newcol2')
*/
class UpdateQuery_sqlite extends UpdateQuery {
/**
* Helper function that removes the fields that are already in a condition.
*
* @param $fields
* The fields.
* @param QueryConditionInterface $condition
* A database condition.
*/
protected function removeFieldsInCondition(&$fields, QueryConditionInterface $condition) {
foreach ($condition->conditions() as $child_condition) {
if ($child_condition['field'] instanceof QueryConditionInterface) {
$this->removeFieldsInCondition($fields, $child_condition['field']);
}
else {
unset($fields[$child_condition['field']]);
}
}
}
public function execute() {
if (!empty($this->queryOptions['sqlite_return_matched_rows'])) {
return parent::execute();
}
// Get the fields used in the update query, and remove those that are already
// in the condition.
// Get the fields used in the update query.
$fields = $this->expressionFields + $this->fields;
$this->removeFieldsInCondition($fields, $this->condition);
// Add the inverse of the fields to the condition.
$condition = new DatabaseCondition('OR');
+10 -9
View File
@@ -296,6 +296,7 @@ class DrupalDefaultEntityController implements DrupalEntityControllerInterface {
/**
* Attaches data to entities upon loading.
*
* This will attach fields, if the entity is fieldable. It calls
* hook_entity_load() for modules which need to add data to all entities.
* It also calls hook_TYPE_load() on the loaded entities. For example
@@ -415,13 +416,14 @@ class EntityFieldQueryException extends Exception {}
* an EntityFieldQueryException will be raised if an unsupported condition is
* specified or if the query has field conditions or sorts that are stored in
* different field storage engines. However, this logic can be overridden in
* hook_entity_query().
* hook_entity_query_alter().
*
* Also note that this query does not automatically respect entity access
* restrictions. Node access control is performed by the SQL storage engine but
* other storage engines might not do this.
*/
class EntityFieldQuery {
/**
* Indicates that both deleted and non-deleted fields should be returned.
*
@@ -594,9 +596,7 @@ class EntityFieldQuery {
*
* 'bundle', 'revision_id' and 'entity_id' have no such restrictions.
*
* Note: The "comment" and "taxonomy_term" entity types don't support bundle
* conditions. For "taxonomy_term", propertyCondition('vid') can be used
* instead.
* Note: The "comment" entity type does not support bundle conditions.
*
* @param $name
* 'entity_type', 'bundle', 'revision_id' or 'entity_id'.
@@ -958,7 +958,7 @@ class EntityFieldQuery {
}
/**
* Enable a pager for the query.
* Enables a pager for the query.
*
* @param $limit
* An integer specifying the number of elements per page. If passed a false
@@ -986,10 +986,11 @@ class EntityFieldQuery {
}
/**
* Enable sortable tables for this query.
* Enables sortable tables for this query.
*
* @param $headers
* An EFQ Header array based on which the order clause is added to the query.
* An EFQ Header array based on which the order clause is added to the
* query.
*
* @return EntityFieldQuery
* The called object.
@@ -1272,7 +1273,7 @@ class EntityFieldQuery {
}
/**
* Get the total number of results and initialize a pager for the query.
* Gets the total number of results and initializes a pager for the query.
*
* The pager can be disabled by either setting the pager limit to 0, or by
* setting this query to be a count query.
@@ -1359,6 +1360,6 @@ class EntityFieldQuery {
}
/**
* Exception thrown when a malformed entity is passed.
* Defines an exception thrown when a malformed entity is passed.
*/
class EntityMalformedException extends Exception { }
-15
View File
@@ -5,21 +5,6 @@
* Functions for error handling.
*/
/**
* Error reporting level: display no errors.
*/
define('ERROR_REPORTING_HIDE', 0);
/**
* Error reporting level: display errors and warnings.
*/
define('ERROR_REPORTING_DISPLAY_SOME', 1);
/**
* Error reporting level: display all messages.
*/
define('ERROR_REPORTING_DISPLAY_ALL', 2);
/**
* Maps PHP error constants to watchdog severity levels.
*
+12 -24
View File
@@ -89,7 +89,7 @@ define('FILE_STATUS_PERMANENT', 1);
* wrappers that are appropriate for particular usage. For example, this returns
* only stream wrappers that use local file storage:
* @code
* $local_stream_wrappers = file_get_stream_wrappers(STEAM_WRAPPERS_LOCAL);
* $local_stream_wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_LOCAL);
* @endcode
*
* The $filter parameter can only filter to types containing a particular flag.
@@ -99,7 +99,7 @@ define('FILE_STATUS_PERMANENT', 1);
* array_diff_key() function can be used to help with this. For example, this
* returns only stream wrappers that do not use local file storage:
* @code
* $remote_stream_wrappers = array_diff_key(file_get_stream_wrappers(STREAM_WRAPPERS_ALL), file_get_stream_wrappers(STEAM_WRAPPERS_LOCAL));
* $remote_stream_wrappers = array_diff_key(file_get_stream_wrappers(STREAM_WRAPPERS_ALL), file_get_stream_wrappers(STREAM_WRAPPERS_LOCAL));
* @endcode
*
* @param $filter
@@ -282,10 +282,6 @@ function file_stream_wrapper_uri_normalize($uri) {
$uri = $scheme . '://' . $target;
}
}
else {
// The default scheme is file://
$url = 'file://' . $uri;
}
return $uri;
}
@@ -398,8 +394,8 @@ function file_create_url($uri) {
}
}
elseif ($scheme == 'http' || $scheme == 'https') {
// Check for http so that we don't have to implement getExternalUrl() for
// the http wrapper.
// Check for HTTP so that we don't have to implement getExternalUrl() for
// the HTTP wrapper.
return $uri;
}
else {
@@ -834,9 +830,8 @@ function file_valid_uri($uri) {
* A string specifying the filepath or URI of the source file.
* @param $destination
* A URI containing the destination that $source should be copied to. The
* URI may be a bare filepath (without a scheme) and in that case the default
* scheme (file://) will be used. If this value is omitted, Drupal's default
* files scheme will be used, usually "public://".
* URI may be a bare filepath (without a scheme). If this value is omitted,
* Drupal's default files scheme will be used, usually "public://".
* @param $replace
* Replace behavior when the destination file already exists:
* - FILE_EXISTS_REPLACE - Replace the existing file.
@@ -892,7 +887,7 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
$destination = file_destination($destination, $replace);
if ($destination === FALSE) {
drupal_set_message(t('The file %file could not be copied because a file by that name already exists in the destination directory.', array('%file' => $original_source)), 'error');
watchdog('file', 'File %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $original_source, '%destination' => $destination));
watchdog('file', 'File %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $original_source, '%directory' => $destination));
return FALSE;
}
@@ -1113,6 +1108,9 @@ function file_munge_filename($filename, $extensions, $alerts = TRUE) {
// Allow potentially insecure uploads for very savvy users and admin
if (!variable_get('allow_insecure_uploads', 0)) {
// Remove any null bytes. See http://php.net/manual/en/security.filesystem.nullbytes.php
$filename = str_replace(chr(0), '', $filename);
$whitelist = array_unique(explode(' ', trim($extensions)));
// Split the filename up by periods. The first part becomes the basename
@@ -2236,7 +2234,7 @@ function drupal_realpath($uri) {
if ($wrapper = file_stream_wrapper_get_instance_by_uri($uri)) {
return $wrapper->realpath();
}
// Check that the uri has a value. There is a bug in PHP 5.2 on *BSD systems
// Check that the URI has a value. There is a bug in PHP 5.2 on *BSD systems
// that makes realpath not return FALSE as expected when passing an empty
// variable.
// @todo Remove when Drupal drops support for PHP 5.2.
@@ -2478,20 +2476,10 @@ function file_directory_temp() {
function file_get_content_headers($file) {
$name = mime_header_encode($file->filename);
$type = mime_header_encode($file->filemime);
// Serve images, text, and flash content for display rather than download.
$inline_types = variable_get('file_inline_types', array('^text/', '^image/', 'flash$'));
$disposition = 'attachment';
foreach ($inline_types as $inline_type) {
// Exclamation marks are used as delimiters to avoid escaping slashes.
if (preg_match('!' . $inline_type . '!', $file->filemime)) {
$disposition = 'inline';
}
}
return array(
'Content-Type' => $type . '; name="' . $name . '"',
'Content-Type' => $type,
'Content-Length' => $file->filesize,
'Content-Disposition' => $disposition . '; filename="' . $name . '"',
'Cache-Control' => 'private',
);
}
+11 -1
View File
@@ -381,7 +381,7 @@ interface FileTransferChmodInterface {
* @param string $path
* Path to change permissions of.
* @param long $mode
* @see http://php.net/chmod
* The new file permission mode to be passed to chmod().
* @param boolean $recursive
* Pass TRUE to recursively chmod the entire directory specified in $path.
*/
@@ -406,10 +406,20 @@ class SkipDotsRecursiveDirectoryIterator extends RecursiveDirectoryIterator {
*/
function __construct($path) {
parent::__construct($path);
$this->skipdots();
}
function rewind() {
parent::rewind();
$this->skipdots();
}
function next() {
parent::next();
$this->skipdots();
}
protected function skipdots() {
while ($this->isDot()) {
parent::next();
}
+77 -63
View File
@@ -78,7 +78,7 @@
* the elements and properties of the form. For information on the array
* components and format, and more detailed explanations of the Form API
* workflow, see the
* @link http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html Form API reference @endlink
* @link forms_api_reference.html Form API reference @endlink
* and the
* @link http://drupal.org/node/37775 Form API documentation section. @endlink
* In addition, there is a set of Form API tutorials in
@@ -215,17 +215,15 @@ function drupal_get_form($form_id) {
* set.
* - values: An associative array of values submitted to the form. The
* validation functions and submit functions use this array for nearly all
* their decision making. (Note that
* @link http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html/7#tree #tree @endlink
* determines whether the values are a flat array or an array whose
* structure parallels the $form array.)
* - input: The array of values as they were submitted by the user. These are
* raw and unvalidated, so should not be used without a thorough
* understanding of security implications. In almost all cases, code should
* use the data in the 'values' array exclusively. The most common use of
* this key is for multi-step forms that need to clear some of the user
* input when setting 'rebuild'. The values correspond to $_POST or $_GET,
* depending on the 'method' chosen.
* their decision making. (Note that #tree determines whether the values are
* a flat array or an array whose structure parallels the $form array. See
* @link forms_api_reference.html Form API reference @endlink for more
* information.) These are raw and unvalidated, so should not be used
* without a thorough understanding of security implications. In almost all
* cases, code should use the data in the 'values' array exclusively. The
* most common use of this key is for multi-step forms that need to clear
* some of the user input when setting 'rebuild'. The values correspond to
* $_POST or $_GET, depending on the 'method' chosen.
* - always_process: If TRUE and the method is GET, a form_id is not
* necessary. This should only be used on RESTful GET forms that do NOT
* write data, as this could lead to security issues. It is useful so that
@@ -730,7 +728,7 @@ function drupal_retrieve_form($form_id, &$form_state) {
// the form builder callbacks can be loaded when the form is being rebuilt
// from cache on a different path (such as 'system/ajax'). See
// form_get_cache().
// $menu_get_item() is not available at installation time.
// $menu_get_item() is not available during installation.
if (!isset($form_state['build_info']['files']['menu']) && !defined('MAINTENANCE_MODE')) {
$item = menu_get_item();
if (!empty($item['include_file'])) {
@@ -852,7 +850,10 @@ function drupal_process_form($form_id, &$form, &$form_state) {
// cache when a form is processed, so scenarios that result in
// the form being built behind the scenes and again for the
// browser don't increment all the element IDs needlessly.
drupal_static_reset('drupal_html_id');
if (!form_get_errors()) {
// In case of errors, do not break HTML IDs of other forms.
drupal_static_reset('drupal_html_id');
}
if ($form_state['submitted'] && !form_get_errors() && !$form_state['rebuild']) {
// Execute form submit handlers.
@@ -1177,18 +1178,23 @@ function drupal_validate_form($form_id, &$form, &$form_state) {
/**
* Redirects the user to a URL after a form has been processed.
*
* After a form was executed, the data in $form_state controls whether the form
* is redirected. By default, we redirect to a new destination page. The path
* of the destination page can be set in $form_state['redirect'], as either a
* string containing the destination or an array of arguments compatible with
* drupal_goto(). If that is not set, the user is redirected to the current
* page to display a fresh, unpopulated copy of the form.
* After a form is submitted and processed, normally the user should be
* redirected to a new destination page. This function figures out what that
* destination should be, based on the $form_state array and the 'destination'
* query string in the request URL, and redirects the user there.
*
* For example, to redirect to 'node':
* Usually (for exceptions, see below) $form_state['redirect'] determines where
* to redirect the user. This can be set either to a string (the path to
* redirect to), or an array of arguments for drupal_goto(). If
* $form_state['redirect'] is missing, the user is usually (again, see below for
* exceptions) redirected back to the page they came from, where they should see
* a fresh, unpopulated copy of the form.
*
* Here is an example of how to set up a form to redirect to the path 'node':
* @code
* $form_state['redirect'] = 'node';
* @endcode
* Or to redirect to 'node/123?foo=bar#baz':
* And here is an example of how to redirect to 'node/123?foo=bar#baz':
* @code
* $form_state['redirect'] = array(
* 'node/123',
@@ -1201,29 +1207,27 @@ function drupal_validate_form($form_id, &$form, &$form_state) {
* );
* @endcode
*
* There are several triggers that may prevent a redirection though:
* - If $form_state['redirect'] is FALSE, a form builder function or form
* validation/submit handler does not want a user to be redirected, which
* means that drupal_goto() is not invoked. For most forms, the redirection
* logic will be the same regardless of whether $form_state['redirect'] is
* undefined or FALSE. However, in case it was not defined and the current
* request contains a 'destination' query string, drupal_goto() will redirect
* to that given destination instead. Only setting $form_state['redirect'] to
* FALSE will prevent any redirection.
* - If $form_state['no_redirect'] is TRUE, then the callback that originally
* built the form explicitly disallows any redirection, regardless of the
* redirection value in $form_state['redirect']. For example, ajax_get_form()
* defines $form_state['no_redirect'] when building a form in an Ajax
* callback to prevent any redirection. $form_state['no_redirect'] should NOT
* be altered by form builder functions or form validation/submit handlers.
* There are several exceptions to the "usual" behavior described above:
* - If $form_state['programmed'] is TRUE, the form submission was usually
* invoked via drupal_form_submit(), so any redirection would break the script
* that invoked drupal_form_submit().
* - If $form_state['rebuild'] is TRUE, the form needs to be rebuilt without
* redirection.
* that invoked drupal_form_submit() and no redirection is done.
* - If $form_state['rebuild'] is TRUE, the form is being rebuilt, and no
* redirection is done.
* - If $form_state['no_redirect'] is TRUE, redirection is disabled. This is
* set, for instance, by ajax_get_form() to prevent redirection in Ajax
* callbacks. $form_state['no_redirect'] should never be set or altered by
* form builder functions or form validation/submit handlers.
* - If $form_state['redirect'] is set to FALSE, redirection is disabled.
* - If none of the above conditions has prevented redirection, then the
* redirect is accomplished by calling drupal_goto(), passing in the value of
* $form_state['redirect'] if it is set, or the current path if it is
* not. drupal_goto() preferentially uses the value of $_GET['destination']
* (the 'destination' URL query string) if it is present, so this will
* override any values set by $form_state['redirect']. Note that during
* installation, install_goto() is called in place of drupal_goto().
*
* @param $form_state
* A keyed array containing the current state of the form.
* An associative array containing the current state of the form.
*
* @see drupal_process_form()
* @see drupal_build_form()
@@ -1255,7 +1259,7 @@ function drupal_redirect_form($form_state) {
$function($form_state['redirect']);
}
}
drupal_goto($_GET['q']);
drupal_goto(current_path(), array('query' => drupal_get_query_parameters()));
}
}
@@ -3054,7 +3058,6 @@ function form_process_radios($element) {
*/
function theme_checkbox($variables) {
$element = $variables['element'];
$t = get_t();
$element['#attributes']['type'] = 'checkbox';
element_set_attributes($element, array('id', 'name', '#return_value' => 'value'));
@@ -3251,21 +3254,6 @@ function theme_container($variables) {
/**
* Returns HTML for a table with radio buttons or checkboxes.
*
* An example of per-row options:
* @code
* $options = array();
* $options[0]['title'] = "A red row"
* $options[0]['#attributes'] = array ('class' => array('red-row'));
* $options[1]['title'] = "A blue row"
* $options[1]['#attributes'] = array ('class' => array('blue-row'));
*
* $form['myselector'] = array (
* '#type' => 'tableselect',
* '#title' => 'My Selector'
* '#options' => $options,
* );
* @endcode
*
* @param $variables
* An associative array containing:
* - element: An associative array containing the properties and children of
@@ -3273,7 +3261,35 @@ function theme_container($variables) {
* and #js_select. The #options property is an array of selection options;
* each array element of #options is an array of properties. These
* properties can include #attributes, which is added to the
* table row's HTML attributes; see theme_table().
* table row's HTML attributes; see theme_table(). An example of per-row
* options:
* @code
* $options = array(
* array(
* 'title' => 'How to Learn Drupal',
* 'content_type' => 'Article',
* 'status' => 'published',
* '#attributes' => array('class' => array('article-row')),
* ),
* array(
* 'title' => 'Privacy Policy',
* 'content_type' => 'Page',
* 'status' => 'published',
* '#attributes' => array('class' => array('page-row')),
* ),
* );
* $header = array(
* 'title' => t('Title'),
* 'content_type' => t('Content type'),
* 'status' => t('Status'),
* );
* $form['table'] = array(
* '#type' => 'tableselect',
* '#header' => $header,
* '#options' => $options,
* '#empty' => t('No content available.'),
* );
* @endcode
*
* @ingroup themeable
*/
@@ -3993,8 +4009,6 @@ function theme_file($variables) {
*/
function theme_form_element($variables) {
$element = &$variables['element'];
// This is also used in the installer, pre-database setup.
$t = get_t();
// This function is invoked as theme wrapper, but the rendered form element
// may not necessarily have been processed by form_builder().
@@ -4153,7 +4167,7 @@ function _form_set_class(&$element, $class = array()) {
if (!empty($element['#required'])) {
$element['#attributes']['class'][] = 'required';
}
if (isset($element['#parents']) && form_get_error($element)) {
if (isset($element['#parents']) && form_get_error($element) !== NULL && !empty($element['#validated'])) {
$element['#attributes']['class'][] = 'error';
}
}
@@ -4363,7 +4377,7 @@ function batch_set($batch_definition) {
}
// Base and default properties for the batch set.
// Use get_t() to allow batches at install time.
// Use get_t() to allow batches during installation.
$t = get_t();
$init = array(
'sandbox' => array(),
+13 -14
View File
@@ -34,7 +34,7 @@
*/
/**
* Return a list of available toolkits.
* Gets a list of available toolkits.
*
* @return
* An array with the toolkit names as keys and the descriptions as values.
@@ -55,7 +55,7 @@ function image_get_available_toolkits() {
}
/**
* Retrieve the name of the currently used toolkit.
* Gets the name of the currently used toolkit.
*
* @return
* String containing the name of the selected toolkit, or FALSE on error.
@@ -101,7 +101,7 @@ function image_toolkit_invoke($method, stdClass $image, array $params = array())
}
/**
* Get details about an image.
* Gets details about an image.
*
* Drupal supports GIF, JPG and PNG file formats when used with the GD
* toolkit, and may support others, depending on which toolkits are
@@ -233,11 +233,11 @@ function image_dimensions_scale(array &$dimensions, $width = NULL, $height = NUL
* @param $image
* An image object returned by image_load().
* @param $width
* The target width, in pixels. This value is omitted then the scaling will
* based only on the height value.
* The target width, in pixels. If this value is NULL then the scaling will
* be based only on the height value.
* @param $height
* The target height, in pixels. This value is omitted then the scaling will
* based only on the width value.
* The target height, in pixels. If this value is NULL then the scaling will
* be based only on the width value.
* @param $upscale
* Boolean indicating that files smaller than the dimensions will be scaled
* up. This generally results in a low quality image.
@@ -261,7 +261,7 @@ function image_scale(stdClass $image, $width = NULL, $height = NULL, $upscale =
}
/**
* Resize an image to the given dimensions (ignoring aspect ratio).
* Resizes an image to the given dimensions (ignoring aspect ratio).
*
* @param $image
* An image object returned by image_load().
@@ -284,7 +284,7 @@ function image_resize(stdClass $image, $width, $height) {
}
/**
* Rotate an image by the given number of degrees.
* Rotates an image by the given number of degrees.
*
* @param $image
* An image object returned by image_load().
@@ -308,7 +308,7 @@ function image_rotate(stdClass $image, $degrees, $background = NULL) {
}
/**
* Crop an image to the rectangle specified by the given rectangle.
* Crops an image to a rectangle specified by the given dimensions.
*
* @param $image
* An image object returned by image_load().
@@ -340,7 +340,7 @@ function image_crop(stdClass $image, $x, $y, $width, $height) {
}
/**
* Convert an image to grayscale.
* Converts an image to grayscale.
*
* @param $image
* An image object returned by image_load().
@@ -355,9 +355,8 @@ function image_desaturate(stdClass $image) {
return image_toolkit_invoke('desaturate', $image);
}
/**
* Load an image file and return an image object.
* Loads an image file and returns an image object.
*
* Any changes to the file are not saved until image_save() is called.
*
@@ -400,7 +399,7 @@ function image_load($file, $toolkit = FALSE) {
}
/**
* Close the image and save the changes to a file.
* Closes the image and saves the changes to a file.
*
* @param $image
* An image object returned by image_load(). The object's 'info' property
+89 -44
View File
@@ -6,8 +6,7 @@
*/
/**
* Global flag to indicate that a task should not be run during the current
* installation request.
* Do not run the task during the current installation request.
*
* This can be used to skip running an installation task when certain
* conditions are met, even though the task may still show on the list of
@@ -20,8 +19,7 @@
define('INSTALL_TASK_SKIP', 1);
/**
* Global flag to indicate that a task should be run on each installation
* request that reaches it.
* Run the task on each installation request until the database is set up.
*
* This is primarily used by the Drupal installer for bootstrap-related tasks.
*/
@@ -200,7 +198,7 @@ function install_state_defaults() {
}
/**
* Begin an installation request, modifying the installation state as needed.
* Begins an installation request, modifying the installation state as needed.
*
* This function performs commands that must run at the beginning of every page
* request. It throws an exception if the installation should not proceed.
@@ -295,12 +293,11 @@ function install_begin_request(&$install_state) {
else {
$task = NULL;
// Since previous versions of Drupal stored database connection information
// in the 'db_url' variable, we should never let an installation proceed if
// this variable is defined and the settings file was not verified above
// (otherwise we risk installing over an existing site whose settings file
// has not yet been updated).
if (!empty($GLOBALS['db_url'])) {
// Do not install over a configured settings.php. Check the 'db_url'
// variable in addition to 'databases', since previous versions of Drupal
// used that (and we do not want to allow installations on an existing site
// whose settings file has not yet been updated).
if (!empty($GLOBALS['databases']) || !empty($GLOBALS['db_url'])) {
throw new Exception(install_already_done_error());
}
}
@@ -525,7 +522,7 @@ function install_tasks($install_state) {
$needs_translations = count($install_state['locales']) > 1 && !empty($install_state['parameters']['locale']) && $install_state['parameters']['locale'] != 'en';
// Start with the core installation tasks that run before handing control
// to the install profile.
// to the installation profile.
$tasks = array(
'install_select_profile' => array(
'display_name' => st('Choose profile'),
@@ -709,7 +706,7 @@ function install_display_output($output, $install_state) {
}
/**
* Installation task; verify the requirements for installing Drupal.
* Verifies the requirements for installing Drupal.
*
* @param $install_state
* An array of information about the current installation state.
@@ -777,7 +774,7 @@ function install_system_module(&$install_state) {
// variable_set() can be used now that system.module is installed.
$modules = $install_state['profile_info']['dependencies'];
// The install profile is also a module, which needs to be installed
// The installation profile is also a module, which needs to be installed
// after all the dependencies have been installed.
$modules[] = drupal_get_profile();
@@ -786,7 +783,7 @@ function install_system_module(&$install_state) {
}
/**
* Verify and return the last installation task that was completed.
* Verifies and returns the last installation task that was completed.
*
* @return
* The last completed task, if there is one. An exception is thrown if Drupal
@@ -830,7 +827,7 @@ function install_verify_settings() {
}
/**
* Verify PDO library.
* Verifies the PDO library.
*/
function install_verify_pdo() {
// PDO was moved to PHP core in 5.2.0, but the old extension (targeting 5.0
@@ -842,15 +839,14 @@ function install_verify_pdo() {
}
/**
* Installation task; define a form to configure and rewrite settings.php.
* Form constructor for a form to configure and rewrite settings.php.
*
* @param $form_state
* An associative array containing the current state of the form.
* @param $install_state
* An array of information about the current installation state.
*
* @return
* The form API definition for the database configuration form.
* @see install_settings_form_validate()
* @see install_settings_form_submit()
* @ingroup forms
*/
function install_settings_form($form, &$form_state, &$install_state) {
global $databases;
@@ -913,7 +909,9 @@ function install_settings_form($form, &$form_state, &$install_state) {
}
/**
* Form API validate for install_settings form.
* Form validation handler for install_settings_form().
*
* @see install_settings_form_submit()
*/
function install_settings_form_validate($form, &$form_state) {
$driver = $form_state['values']['driver'];
@@ -970,7 +968,9 @@ function install_database_errors($database, $settings_file) {
}
/**
* Form API submit for install_settings form.
* Form submission handler for install_settings_form().
*
* @see install_settings_form_validate()
*/
function install_settings_form_submit($form, &$form_state) {
global $install_state;
@@ -1001,7 +1001,7 @@ function install_find_profiles() {
}
/**
* Installation task; select which profile to install.
* Selects which profile to install.
*
* @param $install_state
* An array of information about the current installation state. The chosen
@@ -1041,8 +1041,21 @@ function install_select_profile(&$install_state) {
}
/**
* Helper function for automatically selecting an installation profile from a
* list or from a selection passed in via $_POST.
* Selects an installation profile.
*
* A profile will be selected if:
* - Only one profile is available,
* - A profile was submitted through $_POST,
* - Exactly one of the profiles is marked as "exclusive".
* If multiple profiles are marked as "exclusive" then no profile will be
* selected.
*
* @param array $profiles
* An associative array of profiles with the machine-readable names as keys.
*
* @return
* The machine-readable name of the selected profile or NULL if no profile was
* selected.
*/
function _install_select_profile($profiles) {
if (sizeof($profiles) == 0) {
@@ -1062,15 +1075,34 @@ function _install_select_profile($profiles) {
}
}
}
// Check for a profile marked as "exclusive" and ensure that only one
// profile is marked as such.
$exclusive_profile = NULL;
foreach ($profiles as $profile) {
$profile_info = install_profile_info($profile->name);
if (!empty($profile_info['exclusive'])) {
if (empty($exclusive_profile)) {
$exclusive_profile = $profile->name;
}
else {
// We found a second "exclusive" profile. There's no way to choose
// between them, so we ignore the property.
return;
}
}
}
return $exclusive_profile;
}
/**
* Form API array definition for the profile selection form.
* Form constructor for the profile selection form.
*
* @param $form_state
* Array of metadata about state of form processing.
* @param $profile_files
* Array of .profile files, as returned from file_scan_directory().
*
* @ingroup forms
*/
function install_select_profile_form($form, &$form_state, $profile_files) {
$profiles = array();
@@ -1247,7 +1279,9 @@ function install_select_locale(&$install_state) {
}
/**
* Form API array definition for language selection.
* Form constructor for the language selection form.
*
* @ingroup forms
*/
function install_select_locale_form($form, &$form_state, $locales, $profilename) {
include_once DRUPAL_ROOT . '/includes/iso.inc';
@@ -1297,7 +1331,7 @@ function install_already_done_error() {
}
/**
* Installation task; load information about the chosen profile.
* Loads information about the chosen profile during installation.
*
* @param $install_state
* An array of information about the current installation state. The loaded
@@ -1316,7 +1350,7 @@ function install_load_profile(&$install_state) {
}
/**
* Installation task; perform a full bootstrap of Drupal.
* Performs a full bootstrap of Drupal during installation.
*
* @param $install_state
* An array of information about the current installation state.
@@ -1326,7 +1360,7 @@ function install_bootstrap_full(&$install_state) {
}
/**
* Installation task; install required modules via a batch process.
* Installs required modules via a batch process.
*
* @param $install_state
* An array of information about the current installation state.
@@ -1379,7 +1413,7 @@ function install_profile_modules(&$install_state) {
}
/**
* Installation task; import languages via a batch process.
* Imports languages via a batch process during installation.
*
* @param $install_state
* An array of information about the current installation state.
@@ -1413,15 +1447,14 @@ function install_import_locales(&$install_state) {
}
/**
* Installation task; configure settings for the new site.
* Form constructor for a form to configure the new site.
*
* @param $form_state
* An associative array containing the current state of the form.
* @param $install_state
* An array of information about the current installation state.
*
* @return
* The form API definition for the site configuration form.
* @see install_configure_form_validate()
* @see install_configure_form_submit()
* @ingroup forms
*/
function install_configure_form($form, &$form_state, &$install_state) {
drupal_set_title(st('Configure site'));
@@ -1444,7 +1477,7 @@ function install_configure_form($form, &$form_state, &$install_state) {
// Add JavaScript time zone detection.
drupal_add_js('misc/timezone.js');
// We add these strings as settings because JavaScript translation does not
// work on install time.
// work during installation.
drupal_add_js(array('copyFieldValue' => array('edit-site-mail' => array('edit-account-mail'))), 'setting');
drupal_add_js('jQuery(function () { Drupal.cleanURLsInstallCheck(); });', 'inline');
// Add JS to show / hide the 'Email administrator about site updates' elements
@@ -1487,7 +1520,7 @@ function install_import_locales_remaining(&$install_state) {
}
/**
* Installation task; perform final steps and display a 'finished' page.
* Finishes importing files at end of installation.
*
* @param $install_state
* An array of information about the current installation state.
@@ -1503,13 +1536,13 @@ function install_finished(&$install_state) {
// Flush all caches to ensure that any full bootstraps during the installer
// do not leave stale cached data, and that any content types or other items
// registered by the install profile are registered correctly.
// registered by the installation profile are registered correctly.
drupal_flush_all_caches();
// Remember the profile which was used.
variable_set('install_profile', drupal_get_profile());
// Install profiles are always loaded last
// Installation profiles are always loaded last
db_update('system')
->fields(array('weight' => 1000))
->condition('type', 'module')
@@ -1674,7 +1707,15 @@ function install_check_requirements($install_state) {
}
/**
* Forms API array definition for site configuration.
* Form constructor for a site configuration form.
*
* @param $install_state
* An array of information about the current installation state.
*
* @see install_configure_form()
* @see install_configure_form_validate()
* @see install_configure_form_submit()
* @ingroup forms
*/
function _install_configure_form($form, &$form_state, &$install_state) {
include_once DRUPAL_ROOT . '/includes/locale.inc';
@@ -1787,7 +1828,9 @@ function _install_configure_form($form, &$form_state, &$install_state) {
}
/**
* Forms API validate for the site configuration form.
* Form validation handler for install_configure_form().
*
* @see install_configure_form_submit()
*/
function install_configure_form_validate($form, &$form_state) {
if ($error = user_validate_name($form_state['values']['account']['name'])) {
@@ -1802,7 +1845,9 @@ function install_configure_form_validate($form, &$form_state) {
}
/**
* Forms API submit for the site configuration form.
* Form submission handler for install_configure_form().
*
* @see install_configure_form_validate()
*/
function install_configure_form_submit($form, &$form_state) {
global $user;
+44 -25
View File
@@ -1,5 +1,10 @@
<?php
/**
* @file
* API functions for installing modules and themes.
*/
/**
* Indicates that a module has not been installed yet.
*/
@@ -71,7 +76,7 @@ define('FILE_NOT_WRITABLE', 64);
define('FILE_NOT_EXECUTABLE', 128);
/**
* Initialize the update system by loading all installed module's .install files.
* Loads .install files for installed modules to initialize the update system.
*/
function drupal_load_updates() {
foreach (drupal_get_installed_schema_version(NULL, FALSE, TRUE) as $module => $schema_version) {
@@ -180,11 +185,11 @@ function drupal_set_installed_schema_version($module, $version) {
}
/**
* Loads the install profile, extracting its defined distribution name.
* Loads the installation profile, extracting its defined distribution name.
*
* @return
* The distribution name defined in the profile's .info file. Defaults to
* "Drupal" if none is explicitly provided by the install profile.
* "Drupal" if none is explicitly provided by the installation profile.
*
* @see install_profile_info()
*/
@@ -204,11 +209,12 @@ function drupal_install_profile_distribution_name() {
}
/**
* Auto detect the base_url with PHP predefined variables.
* Detects the base URL using the PHP $_SERVER variables.
*
* @param $file
* The name of the file calling this function so we can strip it out of
* the URI when generating the base_url.
*
* @return
* The auto-detected $base_url that should be configured in settings.php
*/
@@ -223,7 +229,7 @@ function drupal_detect_baseurl($file = 'install.php') {
}
/**
* Detect all supported databases that are compiled into PHP.
* Detects all supported databases that are compiled into PHP.
*
* @return
* An array of database types compiled into PHP.
@@ -239,7 +245,7 @@ function drupal_detect_database_types() {
}
/**
* Return all supported database installer objects that are compiled into PHP.
* Returns all supported database installer objects that are compiled into PHP.
*
* @return
* An array of database installer objects compiled into PHP.
@@ -576,7 +582,7 @@ class DatabaseTaskException extends Exception {
}
/**
* Replace values in settings.php with values in the submitted array.
* Replaces values in settings.php with values in the submitted array.
*
* @param $settings
* An array of settings that need to be updated.
@@ -654,10 +660,11 @@ function drupal_rewrite_settings($settings = array(), $prefix = '') {
}
/**
* Verify an install profile for installation.
* Verifies an installation profile for installation.
*
* @param $install_state
* An array of information about the current installation state.
*
* @return
* The list of modules to install.
*/
@@ -681,8 +688,8 @@ function drupal_verify_profile($install_state) {
$present_modules[] = $present_module->name;
}
// The install profile is also a module, which needs to be installed after all the other dependencies
// have been installed.
// The installation profile is also a module, which needs to be installed
// after all the other dependencies have been installed.
$present_modules[] = drupal_get_profile();
// Verify that all of the profile's required modules are present.
@@ -706,7 +713,7 @@ function drupal_verify_profile($install_state) {
}
/**
* Callback to install the system module.
* Installs the system module.
*
* Separated from the installation of other modules so core system
* functions can be made available while other modules are installed.
@@ -800,7 +807,7 @@ function drupal_uninstall_modules($module_list = array(), $uninstall_dependents
}
/**
* Verify the state of the specified file.
* Verifies the state of the specified file.
*
* @param $file
* The file to check for.
@@ -808,6 +815,7 @@ function drupal_uninstall_modules($module_list = array(), $uninstall_dependents
* An optional bitmask created from various FILE_* constants.
* @param $type
* The type of file. Can be file (default), dir, or link.
*
* @return
* TRUE on success or FALSE on failure. A message is set for the latter.
*/
@@ -879,7 +887,7 @@ function drupal_verify_install_file($file, $mask = NULL, $type = 'file') {
}
/**
* Create a directory with specified permissions.
* Creates a directory with the specified permissions.
*
* @param $file
* The name of the directory to create;
@@ -887,6 +895,7 @@ function drupal_verify_install_file($file, $mask = NULL, $type = 'file') {
* The permissions of the directory to create.
* @param $message
* (optional) Whether to output messages. Defaults to TRUE.
*
* @return
* TRUE/FALSE whether or not the directory was successfully created.
*/
@@ -918,7 +927,7 @@ function drupal_install_mkdir($file, $mask, $message = TRUE) {
}
/**
* Attempt to fix file permissions.
* Attempts to fix file permissions.
*
* The general approach here is that, because we do not know the security
* setup of the webserver, we apply our permission changes to all three
@@ -935,6 +944,7 @@ function drupal_install_mkdir($file, $mask, $message = TRUE) {
* The desired permissions for the file.
* @param $message
* (optional) Whether to output messages. Defaults to TRUE.
*
* @return
* TRUE/FALSE whether or not we were able to fix the file's permissions.
*/
@@ -1000,7 +1010,7 @@ function drupal_install_fix_file($file, $mask, $message = TRUE) {
}
/**
* Send the user to a different installer page.
* Sends the user to a different installer page.
*
* This issues an on-site HTTP redirect. Messages (and errors) are erased.
*
@@ -1078,7 +1088,7 @@ function drupal_requirements_url($severity) {
}
/**
* Functional equivalent of t(), used when some systems are not available.
* Translates a string when some systems are not available.
*
* Used during the install process, when database, theme, and localization
* system is possibly not yet available.
@@ -1138,12 +1148,12 @@ function st($string, array $args = array(), array $options = array()) {
}
/**
* Check an install profile's requirements.
* Checks an installation profile's requirements.
*
* @param $profile
* Name of install profile to check.
* Name of installation profile to check.
* @return
* Array of the install profile's requirements.
* Array of the installation profile's requirements.
*/
function drupal_check_profile($profile) {
include_once DRUPAL_ROOT . '/includes/file.inc';
@@ -1169,11 +1179,12 @@ function drupal_check_profile($profile) {
}
/**
* Extract highest severity from requirements array.
* Extracts the highest severity from the requirements array.
*
* @param $requirements
* An array of requirements, in the same format as is returned by
* hook_requirements().
*
* @return
* The highest severity in the array.
*/
@@ -1188,12 +1199,13 @@ function drupal_requirements_severity(&$requirements) {
}
/**
* Check a module's requirements.
* Checks a module's requirements.
*
* @param $module
* Machine name of module to check.
*
* @return
* TRUE/FALSE depending on the requirements are in place.
* TRUE or FALSE, depending on whether the requirements are met.
*/
function drupal_check_module($module) {
module_load_install($module);
@@ -1218,19 +1230,26 @@ function drupal_check_module($module) {
}
/**
* Retrieve info about an install profile from its .info file.
* Retrieves information about an installation profile from its .info file.
*
* The information stored in a profile .info file is similar to that stored in
* a normal Drupal module .info file. For example:
* - name: The real name of the install profile for display purposes.
* - name: The real name of the installation profile for display purposes.
* - description: A brief description of the profile.
* - dependencies: An array of shortnames of other modules this install profile requires.
* - dependencies: An array of shortnames of other modules that this install
* profile requires.
*
* Additional, less commonly-used information that can appear in a profile.info
* file but not in a normal Drupal module .info file includes:
* - distribution_name: The name of the Drupal distribution that is being
* installed, to be shown throughout the installation process. Defaults to
* 'Drupal'.
* - exclusive: If the install profile is intended to be the only eligible
* choice in a distribution, setting exclusive = TRUE will auto-select it
* during installation, and the install profile selection screen will be
* skipped. If more than one profile is found where exclusive = TRUE then
* this property will have no effect and the profile selection screen will
* be shown as normal with all available profiles shown.
*
* Note that this function does an expensive file system scan to get info file
* information for dependencies. If you only need information from the info
+1 -1
View File
@@ -461,7 +461,7 @@ function _locale_get_predefined_list() {
'tt' => array('Tatar', 'Tatarça'),
'tw' => array('Twi'),
'ty' => array('Tahitian'),
'ug' => array('Uighur'),
'ug' => array('Uyghur'),
'uk' => array('Ukrainian', 'Українська'),
'ur' => array('Urdu', /* Left-to-right marker "" */ 'اردو', LANGUAGE_RTL),
'uz' => array('Uzbek', "o'zbek"),
+152 -44
View File
@@ -2,7 +2,9 @@
/**
* @file
* Multiple language handling functionality.
* Language Negotiation API.
*
* @see http://drupal.org/node/1497272
*/
/**
@@ -11,7 +13,96 @@
define('LANGUAGE_NEGOTIATION_DEFAULT', 'language-default');
/**
* Return all the defined language types.
* @defgroup language_negotiation Language Negotiation API functionality
* @{
* Functions to customize the language types and the negotiation process.
*
* The language negotiation API is based on two major concepts:
* - Language types: types of translatable data (the types of data that a user
* can view or request).
* - Language negotiation providers: functions for determining which language to
* use to present a particular piece of data to the user.
* Both language types and language negotiation providers are customizable.
*
* Drupal defines three built-in language types:
* - Interface language: The page's main language, used to present translated
* user interface elements such as titles, labels, help text, and messages.
* - Content language: The language used to present content that is available
* in more than one language (see
* @link field_language Field Language API @endlink for details).
* - URL language: The language associated with URLs. When generating a URL,
* this value will be used by url() as a default if no explicit preference is
* provided.
* Modules can define additional language types through
* hook_language_types_info(), and alter existing language type definitions
* through hook_language_types_info_alter().
*
* Language types may be configurable or fixed. The language negotiation
* providers associated with a configurable language type can be explicitly
* set through the user interface. A fixed language type has predetermined
* (module-defined) language negotiation settings and, thus, does not appear in
* the configuration page. Here is a code snippet that makes the content
* language (which by default inherits the interface language's values)
* configurable:
* @code
* function mymodule_language_types_info_alter(&$language_types) {
* unset($language_types[LANGUAGE_TYPE_CONTENT]['fixed']);
* }
* @endcode
*
* Every language type can have a different set of language negotiation
* providers assigned to it. Different language types often share the same
* language negotiation settings, but they can have independent settings if
* needed. If two language types are configured the same way, their language
* switcher configuration will be functionally identical and the same settings
* will act on both language types.
*
* Drupal defines the following built-in language negotiation providers:
* - URL: Determine the language from the URL (path prefix or domain).
* - Session: Determine the language from a request/session parameter.
* - User: Follow the user's language preference.
* - Browser: Determine the language from the browser's language settings.
* - Default language: Use the default site language.
* Language negotiation providers are simple callback functions that implement a
* particular logic to return a language code. For instance, the URL provider
* searches for a valid path prefix or domain name in the current request URL.
* If a language negotiation provider does not return a valid language code, the
* next provider associated to the language type (based on provider weight) is
* invoked.
*
* Modules can define additional language negotiation providers through
* hook_language_negotiation_info(), and alter existing providers through
* hook_language_negotiation_info_alter(). Here is an example snippet that lets
* path prefixes be ignored for administrative paths:
* @code
* function mymodule_language_negotiation_info_alter(&$negotiation_info) {
* // Replace the core function with our own function.
* module_load_include('language', 'inc', 'language.negotiation');
* $negotiation_info[LANGUAGE_NEGOTIATION_URL]['callbacks']['negotiation'] = 'mymodule_from_url';
* $negotiation_info[LANGUAGE_NEGOTIATION_URL]['file'] = drupal_get_path('module', 'mymodule') . '/mymodule.module';
* }
*
* function mymodule_from_url($languages) {
* // Use the core URL language negotiation provider to get a valid language
* // code.
* module_load_include('language', 'inc', 'language.negotiation');
* $langcode = language_from_url($languages);
*
* // If we are on an administrative path, override with the default language.
* if (isset($_GET['q']) && strtok($_GET['q'], '/') == 'admin') {
* return language_default()->langcode;
* }
* return $langcode;
* }
* ?>
* @endcode
*
* For more information, see
* @link http://drupal.org/node/1497272 Language Negotiation API @endlink
*/
/**
* Returns all the defined language types.
*
* @return
* An array of language type names. The name will be used as the global
@@ -30,11 +121,11 @@ function language_types_info() {
}
/**
* Return only the configurable language types.
* Returns only the configurable language types.
*
* A language type maybe configurable or fixed. A fixed language type is a type
* whose negotiation values are unchangeable and defined while defining the
* language type itself.
* whose language negotiation providers are module-defined and not altered
* through the user interface.
*
* @param $stored
* Optional. By default retrieves values from the 'language_types' variable to
@@ -68,7 +159,7 @@ function language_types_configurable($stored = TRUE) {
}
/**
* Disable the given language types.
* Disables the given language types.
*
* @param $types
* An array of language types.
@@ -122,16 +213,17 @@ function language_types_set() {
}
/**
* Check if a language provider is enabled.
* Checks whether a language negotiation provider is enabled for a language type.
*
* This has two possible behaviors:
* - If $provider_id is given return its ID if enabled, FALSE otherwise.
* - If no ID is passed the first enabled language provider is returned.
* - If no ID is passed the first enabled language negotiation provider is
* returned.
*
* @param $type
* The language negotiation type.
* The language negotiation provider type.
* @param $provider_id
* The language provider ID.
* The language negotiation provider ID.
*
* @return
* The provider ID if it is enabled, FALSE otherwise.
@@ -155,14 +247,13 @@ function language_negotiation_get($type, $provider_id = NULL) {
}
/**
* Check if the given language provider is enabled for any configurable language
* type.
* Checks if the language negotiation provider is enabled for any language type.
*
* @param $provider_id
* The language provider ID.
* The language negotiation provider ID.
*
* @return
* TRUE if there is at least one language type for which the give language
* TRUE if there is at least one language type for which the given language
* provider is enabled, FALSE otherwise.
*/
function language_negotiation_get_any($provider_id) {
@@ -176,7 +267,7 @@ function language_negotiation_get_any($provider_id) {
}
/**
* Return the language switch links for the given language.
* Returns the language switch links for the given language.
*
* @param $type
* The language negotiation type.
@@ -190,6 +281,11 @@ function language_negotiation_get_switch_links($type, $path) {
$links = FALSE;
$negotiation = variable_get("language_negotiation_$type", array());
// Only get the languages if we have more than one.
if (count(language_list()) >= 2) {
$language = language_initialize($type);
}
foreach ($negotiation as $id => $provider) {
if (isset($provider['callbacks']['switcher'])) {
if (isset($provider['file'])) {
@@ -199,6 +295,12 @@ function language_negotiation_get_switch_links($type, $path) {
$callback = $provider['callbacks']['switcher'];
$result = $callback($type, $path);
// Add support for WCAG 2.0's Language of Parts to add language identifiers.
// http://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html
foreach ($result as $langcode => $link) {
$result[$langcode]['attributes']['lang'] = $langcode;
}
if (!empty($result)) {
// Allow modules to provide translations for specific links.
drupal_alter('language_switch_links', $result, $type, $path);
@@ -212,7 +314,7 @@ function language_negotiation_get_switch_links($type, $path) {
}
/**
* Updates language configuration to remove any language provider that is no longer defined.
* Removes any unused language negotation providers from the configuration.
*/
function language_negotiation_purge() {
// Ensure that we are getting the defined language negotiation information. An
@@ -235,12 +337,12 @@ function language_negotiation_purge() {
}
/**
* Save a list of language providers.
* Saves a list of language negotiation providers.
*
* @param $type
* The language negotiation type.
* @param $language_providers
* An array of language provider weights keyed by id.
* An array of language negotiation provider weights keyed by provider ID.
* @see language_provider_weight()
*/
function language_negotiation_set($type, $language_providers) {
@@ -266,7 +368,7 @@ function language_negotiation_set($type, $language_providers) {
// If the provider does not express any preference about types, make it
// available for any configurable type.
$types = array_flip(isset($provider['types']) ? $provider['types'] : $default_types);
// Check if the provider is defined and has the right type.
// Check whether the provider is defined and has the right type.
if (isset($types[$type])) {
$provider_data = array();
foreach ($provider_fields as $field) {
@@ -283,10 +385,10 @@ function language_negotiation_set($type, $language_providers) {
}
/**
* Return all the defined language providers.
* Returns all the defined language negotiation providers.
*
* @return
* An array of language providers.
* An array of language negotiation providers.
*/
function language_negotiation_info() {
$language_providers = &drupal_static(__FUNCTION__);
@@ -295,7 +397,7 @@ function language_negotiation_info() {
// Collect all the module-defined language negotiation providers.
$language_providers = module_invoke_all('language_negotiation_info');
// Add the default language provider.
// Add the default language negotiation provider.
$language_providers[LANGUAGE_NEGOTIATION_DEFAULT] = array(
'callbacks' => array('language' => 'language_from_default'),
'weight' => 10,
@@ -303,7 +405,7 @@ function language_negotiation_info() {
'description' => t('Use the default site language (@language_name).', array('@language_name' => language_default()->native)),
);
// Let other modules alter the list of language providers.
// Let other modules alter the list of language negotiation providers.
drupal_alter('language_negotiation_info', $language_providers);
}
@@ -311,16 +413,17 @@ function language_negotiation_info() {
}
/**
* Helper function used to cache the language providers results.
* Helper function used to cache the language negotiation providers results.
*
* @param $provider_id
* The language provider ID.
* The language negotiation provider's identifier.
* @param $provider
* The language provider to be invoked. If not passed it will be explicitly
* loaded through language_negotiation_info().
* (optional) An associative array of information about the provider to be
* invoked (see hook_language_negotiation_info() for details). If not passed
* in, it will be loaded through language_negotiation_info().
*
* @return
* The language provider's return value.
* A language object representing the language chosen by the provider.
*/
function language_provider_invoke($provider_id, $provider = NULL) {
$results = &drupal_static(__FUNCTION__);
@@ -341,25 +444,26 @@ function language_provider_invoke($provider_id, $provider = NULL) {
require_once DRUPAL_ROOT . '/' . $provider['file'];
}
// If the language provider has no cache preference or this is satisfied
// we can execute the callback.
// If the language negotiation provider has no cache preference or this is
// satisfied we can execute the callback.
$cache = !isset($provider['cache']) || $user->uid || $provider['cache'] == variable_get('cache', 0);
$callback = isset($provider['callbacks']['language']) ? $provider['callbacks']['language'] : FALSE;
$langcode = $cache && function_exists($callback) ? $callback($languages) : FALSE;
$results[$provider_id] = isset($languages[$langcode]) ? $languages[$langcode] : FALSE;
}
// Since objects are resources we need to return a clone to prevent the
// provider cache to be unintentionally altered. The same providers might be
// used with different language types based on configuration.
// Since objects are resources, we need to return a clone to prevent the
// language negotiation provider cache from being unintentionally altered. The
// same providers might be used with different language types based on
// configuration.
return !empty($results[$provider_id]) ? clone($results[$provider_id]) : $results[$provider_id];
}
/**
* Return the passed language provider weight or a default value.
* Returns the passed language negotiation provider weight or a default value.
*
* @param $provider
* A language provider data structure.
* A language negotiation provider data structure.
*
* @return
* A numeric weight.
@@ -370,16 +474,16 @@ function language_provider_weight($provider) {
}
/**
* Choose a language for the given type based on language negotiation settings.
* Chooses a language based on language negotiation provider settings.
*
* @param $type
* The language type.
* The language type key to find the language for.
*
* @return
* The negotiated language object.
*/
function language_initialize($type) {
// Execute the language providers in the order they were set up and return the
// Execute the language negotiation providers in the order they were set up and return the
// first valid language found.
$negotiation = variable_get("language_negotiation_$type", array());
@@ -398,7 +502,7 @@ function language_initialize($type) {
}
/**
* Default language provider.
* Returns the default language negotiation provider.
*
* @return
* The default language code.
@@ -408,10 +512,10 @@ function language_from_default() {
}
/**
* Split the given path into prefix and actual path.
* Splits the given path into prefix and actual path.
*
* Parse the given path and return the language object identified by the
* prefix and the actual path.
* Parse the given path and return the language object identified by the prefix
* and the actual path.
*
* @param $path
* The path to split.
@@ -440,10 +544,10 @@ function language_url_split_prefix($path, $languages) {
}
/**
* Return the possible fallback languages ordered by language weight.
* Returns the possible fallback languages ordered by language weight.
*
* @param
* The language type.
* (optional) The language type. Defaults to LANGUAGE_TYPE_CONTENT.
*
* @return
* An array of language codes.
@@ -471,3 +575,7 @@ function language_fallback_get_candidates($type = LANGUAGE_TYPE_CONTENT) {
return $fallback_candidates;
}
/**
* @} End of "language_negotiation"
*/
+31 -25
View File
@@ -13,7 +13,7 @@
define('MAIL_LINE_ENDINGS', isset($_SERVER['WINDIR']) || strpos($_SERVER['SERVER_SOFTWARE'], 'Win32') !== FALSE ? "\r\n" : "\n");
/**
* Compose and optionally send an e-mail message.
* Composes and optionally sends an e-mail message.
*
* Sending an e-mail works with defining an e-mail template (subject, text
* and possibly e-mail headers) and the replacement values to use in the
@@ -93,7 +93,9 @@ define('MAIL_LINE_ENDINGS', isset($_SERVER['WINDIR']) || strpos($_SERVER['SERVER
* will be {$module}_{$key}.
* @param $to
* The e-mail address or addresses where the message will be sent to. The
* formatting of this string must comply with RFC 2822. Some examples are:
* formatting of this string will be validated with the
* @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
* Some examples are:
* - user@example.com
* - user@example.com, anotheruser@example.com
* - User <user@example.com>
@@ -191,7 +193,7 @@ function drupal_mail($module, $key, $to, $language, $params = array(), $from = N
}
/**
* Returns an object that implements the MailSystemInterface.
* Returns an object that implements the MailSystemInterface interface.
*
* Allows for one or more custom mail backends to format and send mail messages
* composed using drupal_mail().
@@ -212,9 +214,9 @@ function drupal_mail($module, $key, $to, $language, $params = array(), $from = N
* 'mail_system', which is a keyed array. The default implementation
* is the class whose name is the value of 'default-system' key. A more specific
* match first to key and then to module will be used in preference to the
* default. To specificy a different class for all mail sent by one module, set
* default. To specify a different class for all mail sent by one module, set
* the class name as the value for the key corresponding to the module name. To
* specificy a class for a particular message sent by one module, set the class
* specify a class for a particular message sent by one module, set the class
* name as the value for the array key that is the message id, which is
* "${module}_${key}".
*
@@ -307,19 +309,21 @@ interface MailSystemInterface {
* - id: A unique identifier of the e-mail type. Examples: 'contact_user_copy',
* 'user_password_reset'.
* - to: The mail address or addresses where the message will be sent to.
* The formatting of this string must comply with RFC 2822. Some examples:
* The formatting of this string will be validated with the
* @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
* Some examples are:
* - user@example.com
* - user@example.com, anotheruser@example.com
* - User <user@example.com>
* - User <user@example.com>, Another User <anotheruser@example.com>
* - subject: Subject of the e-mail to be sent. This must not contain any
* newline characters, or the mail may not be sent properly.
* - body: Message to be sent. Accepts both CRLF and LF line-endings.
* E-mail bodies must be wrapped. You can use drupal_wrap_mail() for
* smart plain text wrapping.
* - headers: Associative array containing all additional mail headers not
* defined by one of the other parameters. PHP's mail() looks for Cc
* and Bcc headers and sends the mail to addresses in these headers too.
* - subject: Subject of the e-mail to be sent. This must not contain any
* newline characters, or the mail may not be sent properly.
* - body: Message to be sent. Accepts both CRLF and LF line-endings.
* E-mail bodies must be wrapped. You can use drupal_wrap_mail() for
* smart plain text wrapping.
* - headers: Associative array containing all additional mail headers not
* defined by one of the other parameters. PHP's mail() looks for Cc and
* Bcc headers and sends the mail to addresses in these headers too.
*
* @return
* TRUE if the mail was successfully accepted for delivery, otherwise FALSE.
@@ -328,7 +332,7 @@ interface MailSystemInterface {
}
/**
* Perform format=flowed soft wrapping for mail (RFC 3676).
* Performs format=flowed soft wrapping for mail (RFC 3676).
*
* We use delsp=yes wrapping, but only break non-spaced languages when
* absolutely necessary to avoid compatibility issues.
@@ -340,6 +344,9 @@ interface MailSystemInterface {
* @param $indent (optional)
* A string to indent the text with. Only '>' characters are repeated on
* subsequent wrapped lines. Others are replaced by spaces.
*
* @return
* The content of the email as a string with formatting applied.
*/
function drupal_wrap_mail($text, $indent = '') {
// Convert CRLF into LF.
@@ -371,8 +378,7 @@ function drupal_wrap_mail($text, $indent = '') {
}
/**
* Transform an HTML string into plain text, preserving the structure of the
* markup. Useful for preparing the body of a node to be sent by e-mail.
* Transforms an HTML string into plain text, preserving its structure.
*
* The output will be suitable for use as 'format=flowed; delsp=yes' text
* (RFC 3676) and can be passed directly to drupal_mail() for sending.
@@ -551,9 +557,9 @@ function drupal_html_to_text($string, $allowed_tags = NULL) {
}
/**
* Helper function for array_walk in drupal_wrap_mail().
*
* Wraps words on a single line.
*
* Callback for array_walk() winthin drupal_wrap_mail().
*/
function _drupal_wrap_mail_line(&$line, $key, $values) {
// Use soft-breaks only for purely quoted or unindented text.
@@ -563,9 +569,9 @@ function _drupal_wrap_mail_line(&$line, $key, $values) {
}
/**
* Helper function for drupal_html_to_text().
*
* Keeps track of URLs and replaces them with placeholder tokens.
*
* Callback for preg_replace_callback() within drupal_html_to_text().
*/
function _drupal_html_to_mail_urls($match = NULL, $reset = FALSE) {
global $base_url, $base_path;
@@ -590,18 +596,18 @@ function _drupal_html_to_mail_urls($match = NULL, $reset = FALSE) {
}
/**
* Helper function for drupal_wrap_mail() and drupal_html_to_text().
* Replaces non-quotation markers from a given piece of indentation with spaces.
*
* Replace all non-quotation markers from a given piece of indentation with spaces.
* Callback for array_map() within drupal_html_to_text().
*/
function _drupal_html_to_text_clean($indent) {
return preg_replace('/[^>]/', ' ', $indent);
}
/**
* Helper function for drupal_html_to_text().
* Pads the last line with the given character.
*
* Pad the last line with the given character.
* @see drupal_html_to_text()
*/
function _drupal_html_to_text_pad($text, $pad, $prefix = '') {
// Remove last line break.
+88 -72
View File
@@ -417,9 +417,9 @@ function menu_unserialize($data, $map) {
* @param $path
* The path.
* @param $router_item
* The router item. Usually you take a router entry from menu_get_item and
* set it back either modified or to a different path. This lets you modify the
* navigation block, the page title, the breadcrumb and the page help in one
* The router item. Usually a router entry from menu_get_item() is either
* modified or set to a different path. This allows the navigation block,
* the page title, the breadcrumb, and the page help to be modified in one
* call.
*/
function menu_set_item($path, $router_item) {
@@ -427,7 +427,7 @@ function menu_set_item($path, $router_item) {
}
/**
* Get a router item.
* Gets a router item.
*
* @param $path
* The path, for example node/5. The function will find the corresponding
@@ -436,12 +436,13 @@ function menu_set_item($path, $router_item) {
* Internal use only.
*
* @return
* The router item, an associate array corresponding to one row in the
* menu_router table. The value of key map holds the loaded objects. The
* value of key access is TRUE if the current user can access this page.
* The values for key title, page_arguments, access_arguments, and
* theme_arguments will be filled in based on the database values and the
* objects loaded.
* The router item or, if an error occurs in _menu_translate(), FALSE. A
* router item is an associative array corresponding to one row in the
* menu_router table. The value corresponding to the key 'map' holds the
* loaded objects. The value corresponding to the key 'access' is TRUE if the
* current user can access this page. The values corresponding to the keys
* 'title', 'page_arguments', 'access_arguments', and 'theme_arguments' will
* be filled in based on the database values and the objects loaded.
*/
function menu_get_item($path = NULL, $router_item = NULL) {
$router_items = &drupal_static(__FUNCTION__);
@@ -606,7 +607,7 @@ function _menu_load_objects(&$item, &$map) {
}
/**
* Check access to a menu item using the access callback
* Checks access to a menu item using the access callback.
*
* @param $item
* A menu router or menu link item
@@ -617,6 +618,7 @@ function _menu_load_objects(&$item, &$map) {
* $item['access'] becomes TRUE if the item is accessible, FALSE otherwise.
*/
function _menu_check_access(&$item, $map) {
$item['access'] = FALSE;
// Determine access callback, which will decide whether or not the current
// user has access to this path.
$callback = empty($item['access_callback']) ? 0 : trim($item['access_callback']);
@@ -638,7 +640,7 @@ function _menu_check_access(&$item, $map) {
}
/**
* Localize the router item title using t() or another callback.
* Localizes the router item title using t() or another callback.
*
* Translate the title and description to allow storage of English title
* strings in the database, yet display of them in the language required
@@ -746,7 +748,7 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
* $item['load_functions']. $item['access'] becomes TRUE if the item is
* accessible, FALSE otherwise. $item['href'] is set according to the map.
* If an error occurs during calling the load_functions (like trying to load
* a non existing node) then this function return FALSE.
* a non-existent node) then this function returns FALSE.
*/
function _menu_translate(&$router_item, $map, $to_arg = FALSE) {
if ($to_arg && !empty($router_item['to_arg_functions'])) {
@@ -796,14 +798,14 @@ function _menu_translate(&$router_item, $map, $to_arg = FALSE) {
}
/**
* This function translates the path elements in the map using any to_arg
* helper function. These functions take an argument and return an object.
* See http://drupal.org/node/109153 for more information.
* Translates the path elements in the map using any to_arg helper function.
*
* @param $map
* An array of path arguments (ex: array('node', '5'))
* @param $to_arg_functions
* An array of helper function (ex: array(2 => 'menu_tail_to_arg'))
*
* @see hook_menu()
*/
function _menu_link_map_translate(&$map, $to_arg_functions) {
$to_arg_functions = unserialize($to_arg_functions);
@@ -820,14 +822,14 @@ function _menu_link_map_translate(&$map, $to_arg_functions) {
}
/**
* Returns path as one string from the argument we are currently at.
* Returns a string containing the path relative to the current index.
*/
function menu_tail_to_arg($arg, $map, $index) {
return implode('/', array_slice($map, $index));
}
/**
* Loads path as one string from the argument we are currently at.
* Loads the path as one string relative to the current index.
*
* To use this load function, you must specify the load arguments
* in the router item as:
@@ -844,8 +846,10 @@ function menu_tail_load($arg, &$map, $index) {
}
/**
* This function is similar to _menu_translate() but does link-specific
* preparation such as always calling to_arg functions
* Provides menu link access control, translation, and argument handling.
*
* This function is similar to _menu_translate(), but it also does
* link-specific preparation (such as always calling to_arg() functions).
*
* @param $item
* A menu link.
@@ -939,7 +943,7 @@ function _menu_link_translate(&$item, $translate = FALSE) {
}
/**
* Get a loaded object from a router item.
* Gets a loaded object from a router item.
*
* menu_get_object() provides access to objects loaded by the current router
* item. For example, on the page node/%node, the router loads the %node object,
@@ -1079,7 +1083,7 @@ function menu_tree_output($tree) {
}
/**
* Get the data structure representing a named menu tree.
* Gets the data structure representing a named menu tree.
*
* Since this can be the full tree including hidden items, the data returned
* may be used for generating an an admin interface or a select.
@@ -1147,7 +1151,7 @@ function menu_tree_all_data($menu_name, $link = NULL, $max_depth = NULL) {
}
/**
* Set the path for determining the active trail of the specified menu tree.
* Sets the path for determining the active trail of the specified menu tree.
*
* This path will also affect the breadcrumbs under some circumstances.
* Breadcrumbs are built using the preferred link returned by
@@ -1172,7 +1176,7 @@ function menu_tree_set_path($menu_name, $path = NULL) {
}
/**
* Get the path for determining the active trail of the specified menu tree.
* Gets the path for determining the active trail of the specified menu tree.
*
* @param $menu_name
* The menu name of the requested tree.
@@ -1186,7 +1190,7 @@ function menu_tree_get_path($menu_name) {
}
/**
* Get the data structure representing a named menu tree, based on the current page.
* Gets the data structure for a named menu tree, based on the current page.
*
* The tree order is maintained by storing each parent in an individual
* field, see http://drupal.org/node/141866 for more.
@@ -1320,7 +1324,7 @@ function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail =
}
/**
* Build a menu tree, translate links, and check access.
* Builds a menu tree, translates links, and checks access.
*
* @param $menu_name
* The name of the menu.
@@ -1335,8 +1339,8 @@ function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail =
* trail. This option is ignored, if 'expanded' is non-empty. Internally
* used for breadcrumbs.
* - min_depth: The minimum depth of menu links in the resulting tree.
* Defaults to 1, which is the default to build a whole tree for a menu, i.e.
* excluding menu container itself.
* Defaults to 1, which is the default to build a whole tree for a menu
* (excluding menu container itself).
* - max_depth: The maximum depth of menu links in the resulting tree.
* - conditions: An associative array of custom database select query
* condition key/value pairs; see _menu_build_tree() for the actual query.
@@ -1353,7 +1357,7 @@ function menu_build_tree($menu_name, array $parameters = array()) {
}
/**
* Build a menu tree.
* Builds a menu tree.
*
* This function may be used build the data for a menu tree only, for example
* to further massage the data manually before further processing happens.
@@ -1449,7 +1453,7 @@ function _menu_build_tree($menu_name, array $parameters = array()) {
}
/**
* Recursive helper function - collect node links.
* Collects node links from a given menu tree recursively.
*
* @param $tree
* The menu tree you wish to collect node links from.
@@ -1472,7 +1476,7 @@ function menu_tree_collect_node_links(&$tree, &$node_links) {
}
/**
* Check access and perform other dynamic operations for each link in the tree.
* Checks access and performs dynamic operations for each link in the tree.
*
* @param $tree
* The menu tree you wish to operate on.
@@ -1499,7 +1503,7 @@ function menu_tree_check_access(&$tree, $node_links = array()) {
}
/**
* Recursive helper function for menu_tree_check_access()
* Sorts the menu tree and recursively checks access for each item.
*/
function _menu_tree_check_access(&$tree) {
$new_tree = array();
@@ -1522,7 +1526,7 @@ function _menu_tree_check_access(&$tree) {
}
/**
* Builds the data representing a menu tree.
* Sorts and returns the built data representing a menu tree.
*
* @param $links
* A flat array of menu links that are part of the menu. Each array element
@@ -1554,7 +1558,7 @@ function menu_tree_data(array $links, array $parents = array(), $depth = 1) {
}
/**
* Recursive helper function to build the data representing a menu tree.
* Builds the data representing a menu tree.
*
* The function is a bit complex because the rendering of a link depends on
* the next menu link.
@@ -1589,7 +1593,7 @@ function _menu_tree_data(&$links, $parents, $depth) {
}
/**
* Preprocesses the rendered tree for theme_menu_tree().
* Implements template_preprocess_HOOK() for theme_menu_tree().
*/
function template_preprocess_menu_tree(&$variables) {
$variables['tree'] = $variables['tree']['#children'];
@@ -1783,7 +1787,7 @@ function menu_get_names() {
}
/**
* Return an array containing the names of system-defined (default) menus.
* Returns an array containing the names of system-defined (default) menus.
*/
function menu_list_system_menus() {
return array(
@@ -1795,14 +1799,14 @@ function menu_list_system_menus() {
}
/**
* Return an array of links to be rendered as the Main menu.
* Returns an array of links to be rendered as the Main menu.
*/
function menu_main_menu() {
return menu_navigation_links(variable_get('menu_main_links_source', 'main-menu'));
}
/**
* Return an array of links to be rendered as the Secondary links.
* Returns an array of links to be rendered as the Secondary links.
*/
function menu_secondary_menu() {
@@ -1817,7 +1821,7 @@ function menu_secondary_menu() {
}
/**
* Return an array of links for a navigation menu.
* Returns an array of links for a navigation menu.
*
* @param $menu_name
* The name of the menu.
@@ -2109,14 +2113,12 @@ function menu_local_tasks($level = 0) {
}
/**
* Retrieve contextual links for a system object based on registered local tasks.
* Retrieves contextual links for a path based on registered local tasks.
*
* This leverages the menu system to retrieve the first layer of registered
* local tasks for a given system path. All local tasks of the tab type
* MENU_CONTEXT_INLINE are taken into account.
*
* @see hook_menu()
*
* For example, when considering the following registered local tasks:
* - node/%node/view (default local task) with no 'context' defined
* - node/%node/edit with context: MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE
@@ -2144,6 +2146,7 @@ function menu_local_tasks($level = 0) {
* A list of menu router items that are local tasks for the passed-in path.
*
* @see contextual_links_preprocess()
* @see hook_menu()
*/
function menu_contextual_links($module, $parent_path, $args) {
static $path_empty = array();
@@ -2237,7 +2240,7 @@ function menu_local_actions() {
}
/**
* Returns the router path, or the path of the parent tab of a default local task.
* Returns the router path, or the path for a default local task's parent.
*/
function menu_tab_root_path() {
$links = menu_local_tasks();
@@ -2258,7 +2261,13 @@ function menu_local_tabs() {
/**
* Returns HTML for primary and secondary local tasks.
*
* @param $variables
* An associative array containing:
* - primary: (optional) An array of local tasks (tabs).
* - secondary: (optional) An array of local tasks (tabs).
*
* @ingroup themeable
* @see menu_local_tasks()
*/
function theme_menu_local_tasks(&$variables) {
$output = '';
@@ -2280,7 +2289,9 @@ function theme_menu_local_tasks(&$variables) {
}
/**
* Set (or get) the active menu for the current page - determines the active trail.
* Sets (or gets) the active menu for the current page.
*
* The active menu for the page determines the active trail.
*
* @return
* An array of menu machine names, in order of preference. The
@@ -2302,17 +2313,17 @@ function menu_set_active_menu_names($menu_names = NULL) {
}
/**
* Get the active menu for the current page - determines the active trail.
* Gets the active menu for the current page.
*/
function menu_get_active_menu_names() {
return menu_set_active_menu_names();
}
/**
* Set the active path, which determines which page is loaded.
* Sets the active path, which determines which page is loaded.
*
* Note that this may not have the desired effect unless invoked very early
* in the page load, such as during hook_boot, or unless you call
* in the page load, such as during hook_boot(), or unless you call
* menu_execute_active_handler() to generate your page output.
*
* @param $path
@@ -2326,7 +2337,7 @@ function menu_set_active_item($path) {
}
/**
* Sets the active trail (path to menu tree root) of the current page.
* Sets the active trail (path to the menu tree root) of the current page.
*
* Any trail set by this function will only be used for functionality that calls
* menu_get_active_trail(). Drupal core only uses trails set here for
@@ -2416,7 +2427,7 @@ function menu_set_active_trail($new_trail = NULL) {
}
/**
* Lookup the preferred menu link for a given system path.
* Looks up the preferred menu link for a given system path.
*
* @param $path
* The path, for example 'node/5'. The function will find the corresponding
@@ -2536,7 +2547,7 @@ function menu_get_active_trail() {
}
/**
* Get the breadcrumb for the current page, as determined by the active trail.
* Gets the breadcrumb for the current page, as determined by the active trail.
*
* @see menu_set_active_trail()
*/
@@ -2587,7 +2598,7 @@ function menu_get_active_breadcrumb() {
}
/**
* Get the title of the current page, as determined by the active trail.
* Gets the title of the current page, as determined by the active trail.
*/
function menu_get_active_title() {
$active_trail = menu_get_active_trail();
@@ -2600,7 +2611,7 @@ function menu_get_active_title() {
}
/**
* Get a menu link by its mlid, access checked and link translated for rendering.
* Gets a translated, access-checked menu link that is ready for rendering.
*
* This function should never be called from within node_load() or any other
* function used as a menu object load function since an infinite recursion may
@@ -2651,7 +2662,9 @@ function menu_cache_clear($menu_name = 'navigation') {
}
/**
* Clears all cached menu data. This should be called any time broad changes
* Clears all cached menu data.
*
* This should be called any time broad changes
* might have been made to the router items or menu links.
*/
function menu_cache_clear_all() {
@@ -2672,10 +2685,10 @@ function menu_reset_static_cache() {
}
/**
* (Re)populate the database tables used by various menu functions.
* Populates the database tables used by various menu functions.
*
* This function will clear and populate the {menu_router} table, add entries
* to {menu_links} for new router items, then remove stale items from
* to {menu_links} for new router items, and then remove stale items from
* {menu_links}. If called from update.php or install.php, it will also
* schedule a call to itself on the first real page load from
* menu_execute_active_handler(), because the maintenance page environment
@@ -2721,7 +2734,7 @@ function menu_rebuild() {
}
/**
* Collect and alter the menu definitions.
* Collects and alters the menu definitions.
*/
function menu_router_build() {
// We need to manually call each module so that we can know which module
@@ -2745,7 +2758,7 @@ function menu_router_build() {
}
/**
* Helper function to store the menu router if we have it in memory.
* Stores the menu router if we have it in memory.
*/
function _menu_router_cache($new_menu = NULL) {
$menu = &drupal_static(__FUNCTION__);
@@ -2757,7 +2770,7 @@ function _menu_router_cache($new_menu = NULL) {
}
/**
* Get the menu router.
* Gets the menu router.
*/
function menu_get_router() {
// Check first if we have it in memory already.
@@ -2794,7 +2807,7 @@ function _menu_link_build($item) {
}
/**
* Helper function to build menu links for the items in the menu router.
* Builds menu links for the items in the menu router.
*/
function _menu_navigation_links_rebuild($menu) {
// Add normal and suggested items as links.
@@ -2894,7 +2907,7 @@ function _menu_navigation_links_rebuild($menu) {
}
/**
* Clone an array of menu links.
* Clones an array of menu links.
*
* @param $links
* An array of menu links to clone.
@@ -2985,12 +2998,14 @@ function menu_link_delete($mlid, $path = NULL) {
}
/**
* Helper function for menu_link_delete; deletes a single menu link.
* Deletes a single menu link.
*
* @param $item
* Item to be deleted.
* @param $force
* Forces deletion. Internal use only, setting to TRUE is discouraged.
*
* @see menu_link_delete()
*/
function _menu_delete_item($item, $force = FALSE) {
$item = is_object($item) ? get_object_vars($item) : $item;
@@ -3202,7 +3217,7 @@ function menu_link_save(&$item, $existing_item = array(), $parent_candidates = a
}
/**
* Find a possible parent for a given menu link.
* Finds a possible parent for a given menu link.
*
* Because the parent of a given link might not exist anymore in the database,
* we apply a set of heuristics to determine a proper parent:
@@ -3216,6 +3231,7 @@ function menu_link_save(&$item, $existing_item = array(), $parent_candidates = a
* A menu link.
* @param $parent_candidates
* An array of menu links keyed by mlid.
*
* @return
* A menu link structure of the possible parent or FALSE if no valid parent
* has been found.
@@ -3281,7 +3297,7 @@ function _menu_link_find_parent($menu_link, $parent_candidates = array()) {
}
/**
* Helper function to clear the page and block caches at most twice per page load.
* Clears the page and block caches at most twice per page load.
*/
function _menu_clear_page_cache() {
$cache_cleared = &drupal_static(__FUNCTION__, 0);
@@ -3303,7 +3319,7 @@ function _menu_clear_page_cache() {
}
/**
* Helper function to update a list of menus with expanded items
* Updates a list of menus with expanded items.
*/
function _menu_set_expanded_menus() {
$names = db_query("SELECT menu_name FROM {menu_links} WHERE expanded <> 0 GROUP BY menu_name")->fetchCol();
@@ -3311,7 +3327,7 @@ function _menu_set_expanded_menus() {
}
/**
* Find the router path which will serve this path.
* Finds the router path which will serve this path.
*
* @param $link_path
* The path for we are looking up its router path.
@@ -3353,7 +3369,7 @@ function _menu_find_router_path($link_path) {
}
/**
* Insert, update or delete an uncustomized menu link related to a module.
* Inserts, updates, or deletes an uncustomized menu link related to a module.
*
* @param $module
* The name of the module.
@@ -3393,7 +3409,7 @@ function menu_link_maintain($module, $op, $link_path, $link_title) {
}
/**
* Find the depth of an item's children relative to its depth.
* Finds the depth of an item's children relative to its depth.
*
* For example, if the item has a depth of 2, and the maximum of any child in
* the menu link tree is 5, the relative depth is 3.
@@ -3425,7 +3441,7 @@ function menu_link_children_relative_depth($item) {
}
/**
* Update the children of a menu link that's being moved.
* Updates the children of a menu link that is being moved.
*
* The menu name, parents (p1 - p6), and depth are updated for all children of
* the link, and the has_children status of the previous parent is updated.
@@ -3474,7 +3490,7 @@ function _menu_link_move_children($item, $existing_item) {
}
/**
* Check and update the has_children status for the parent of a link.
* Checks and updates the 'has_children' status for the parent of a link.
*/
function _menu_update_parental_status($item, $exclude = FALSE) {
// If plid == 0, there is nothing to update.
@@ -3498,7 +3514,7 @@ function _menu_update_parental_status($item, $exclude = FALSE) {
}
/**
* Helper function that sets the p1..p9 values for a menu link being saved.
* Sets the p1 through p9 values for a menu link being saved.
*/
function _menu_link_parents_set(&$item, $parent) {
$i = 1;
@@ -3516,7 +3532,7 @@ function _menu_link_parents_set(&$item, $parent) {
}
/**
* Helper function to build the router table based on the data from hook_menu.
* Builds the router table based on the data from hook_menu().
*/
function _menu_router_build($callbacks) {
// First pass: separate callbacks from paths, making paths ready for
@@ -3743,7 +3759,7 @@ function _menu_router_build($callbacks) {
}
/**
* Helper function to save data from menu_router_build() to the router table.
* Saves data from menu_router_build() to the router table.
*/
function _menu_router_save($menu, $masks) {
// Delete the existing router since we have some data to replace it.
+37 -23
View File
@@ -6,7 +6,7 @@
*/
/**
* Load all the modules that have been enabled in the system table.
* Loads all the modules that have been enabled in the system table.
*
* @param $bootstrap
* Whether to load only the reduced set of modules loaded in "bootstrap mode"
@@ -102,7 +102,7 @@ function module_list($refresh = FALSE, $bootstrap_refresh = FALSE, $sort = FALSE
}
/**
* Build a list of bootstrap modules and enabled modules and themes.
* Builds a list of bootstrap modules and enabled modules and themes.
*
* @param $type
* The type of list to return:
@@ -181,6 +181,7 @@ function system_list($type) {
foreach ($lists['theme'] as $key => $theme) {
if (!empty($theme->info['base theme'])) {
// Make a list of the theme's base themes.
require_once DRUPAL_ROOT . '/includes/theme.inc';
$lists['theme'][$key]->base_themes = drupal_find_base_themes($lists['theme'], $key);
// Don't proceed if there was a problem with the root base theme.
if (!current($lists['theme'][$key]->base_themes)) {
@@ -218,7 +219,7 @@ function system_list($type) {
}
/**
* Reset all system_list() caches.
* Resets all system_list() caches.
*/
function system_list_reset() {
drupal_static_reset('system_list');
@@ -229,7 +230,7 @@ function system_list_reset() {
}
/**
* Find dependencies any level deep and fill in required by information too.
* Determines which modules require and are required by each module.
*
* @param $files
* The array of filesystem objects used to rebuild the cache.
@@ -262,7 +263,7 @@ function _module_build_dependencies($files) {
}
/**
* Determine whether a given module exists.
* Determines whether a given module exists.
*
* @param $module
* The name of the module (without the .module extension).
@@ -276,7 +277,7 @@ function module_exists($module) {
}
/**
* Load a module's installation hooks.
* Loads a module's installation hooks.
*
* @param $module
* The name of the module (without the .module extension).
@@ -292,7 +293,7 @@ function module_load_install($module) {
}
/**
* Load a module include file.
* Loads a module include file.
*
* Examples:
* @code
@@ -334,8 +335,7 @@ function module_load_include($type, $module, $name = NULL) {
}
/**
* Load an include file for each of the modules that have been enabled in
* the system table.
* Loads an include file for each module enabled in the {system} table.
*/
function module_load_all_includes($type, $name = NULL) {
$modules = module_list();
@@ -503,7 +503,7 @@ function module_enable($module_list, $enable_dependencies = TRUE) {
}
/**
* Disable a given set of modules.
* Disables a given set of modules.
*
* @param $module_list
* An array of module names.
@@ -614,7 +614,7 @@ function module_disable($module_list, $disable_dependents = TRUE) {
*/
/**
* Determine whether a module implements a hook.
* Determines whether a module implements a hook.
*
* @param $module
* The name of the module (without the .module extension).
@@ -643,7 +643,7 @@ function module_hook($module, $hook) {
}
/**
* Determine which modules are implementing a hook.
* Determines which modules are implementing a hook.
*
* @param $hook
* The name of the hook (e.g. "help" or "menu").
@@ -744,7 +744,14 @@ function module_implements($hook, $sort = FALSE, $reset = FALSE) {
}
/**
* Retrieve a list of what hooks are explicitly declared.
* Retrieves a list of hooks that are declared through hook_hook_info().
*
* @return
* An associative array whose keys are hook names and whose values are an
* associative array containing a group name. The structure of the array
* is the same as the return value of hook_hook_info().
*
* @see hook_hook_info()
*/
function module_hook_info() {
// This function is indirectly invoked from bootstrap_invoke_all(), in which
@@ -806,7 +813,7 @@ function module_implements_write_cache() {
}
/**
* Invoke a hook in a particular module.
* Invokes a hook in a particular module.
*
* @param $module
* The name of the module (without the .module extension).
@@ -828,7 +835,7 @@ function module_invoke($module, $hook) {
}
/**
* Invoke a hook in all enabled modules that implement it.
* Invokes a hook in all enabled modules that implement it.
*
* @param $hook
* The name of the hook to invoke.
@@ -865,13 +872,13 @@ function module_invoke_all($hook) {
*/
/**
* Array of modules required by core.
* Returns an array of modules required by core.
*/
function drupal_required_modules() {
$files = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info$/', 'modules', 'name', 0);
$required = array();
// An install profile is required and one must always be loaded.
// An installation profile is required and one must always be loaded.
$required[] = drupal_get_profile();
foreach ($files as $name => $file) {
@@ -885,15 +892,16 @@ function drupal_required_modules() {
}
/**
* Hands off alterable variables to type-specific *_alter implementations.
* Passes alterable variables to specific hook_TYPE_alter() implementations.
*
* This dispatch function hands off the passed-in variables to type-specific
* hook_TYPE_alter() implementations in modules. It ensures a consistent
* interface for all altering operations.
*
* A maximum of 2 alterable arguments is supported. In case more arguments need
* to be passed and alterable, modules provide additional variables assigned by
* reference in the last $context argument:
* A maximum of 2 alterable arguments is supported (a third is supported for
* legacy reasons, but should not be used in new code). In case more arguments
* need to be passed and alterable, modules provide additional variables
* assigned by reference in the last $context argument:
* @code
* $context = array(
* 'alterable' => &$alterable,
@@ -932,8 +940,14 @@ function drupal_required_modules() {
* (optional) An additional variable that is passed by reference. If more
* context needs to be provided to implementations, then this should be an
* associative array as described above.
* @param $context3
* (optional) An additional variable that is passed by reference. This
* parameter is deprecated and will not exist in Drupal 8; consequently, it
* should not be used for new Drupal 7 code either. It is here only for
* backwards compatibility with older code that passed additional arguments
* to drupal_alter().
*/
function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL, &$context3 = NULL) {
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static_fast;
if (!isset($drupal_static_fast)) {
@@ -1046,6 +1060,6 @@ function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
}
foreach ($functions[$cid] as $function) {
$function($data, $context1, $context2);
$function($data, $context1, $context2, $context3);
}
}
+1 -1
View File
@@ -43,7 +43,7 @@ function _password_itoa64() {
}
/**
* Encode bytes into printable base 64 using the *nix standard from crypt().
* Encodes bytes into printable base 64 using the *nix standard from crypt().
*
* @param $input
* The string containing bytes to encode.
+6 -6
View File
@@ -386,7 +386,7 @@ function drupal_path_alias_whitelist_rebuild($source = NULL) {
}
/**
* Fetch a specific URL alias from the database.
* Fetches a specific URL alias from the database.
*
* @param $conditions
* A string representing the source, a number representing the pid, or an
@@ -475,11 +475,11 @@ function path_delete($criteria) {
}
/**
* Determine whether a path is in the administrative section of the site.
* Determines whether a path is in the administrative section of the site.
*
* By default, paths are considered to be non-administrative. If a path does not
* match any of the patterns in path_get_admin_paths(), or if it matches both
* administrative and non-administrative patterns, it is considered
* By default, paths are considered to be non-administrative. If a path does
* not match any of the patterns in path_get_admin_paths(), or if it matches
* both administrative and non-administrative patterns, it is considered
* non-administrative.
*
* @param $path
@@ -503,7 +503,7 @@ function path_is_admin($path) {
}
/**
* Get a list of administrative and non-administrative paths.
* Gets a list of administrative and non-administrative paths.
*
* @return array
* An associative array containing the following keys:
+20 -2
View File
@@ -274,7 +274,7 @@ function drupal_session_initialize() {
}
/**
* Forcefully starts a session, preserving already set session data.
* Starts a session forcefully, preserving already set session data.
*
* @ingroup php_wrappers
*/
@@ -349,6 +349,11 @@ function drupal_session_started($set = NULL) {
*/
function drupal_session_regenerate() {
global $user, $is_https;
// Nothing to do if we are not allowed to change the session.
if (!drupal_save_session()) {
return;
}
if ($is_https && variable_get('https', FALSE)) {
$insecure_session_name = substr(session_name(), 1);
if (!isset($GLOBALS['lazy_session']) && isset($_COOKIE[$insecure_session_name])) {
@@ -418,6 +423,11 @@ function drupal_session_regenerate() {
function _drupal_session_destroy($sid) {
global $user, $is_https;
// Nothing to do if we are not allowed to change the session.
if (!drupal_save_session()) {
return;
}
// Delete session data.
db_delete('sessions')
->condition($is_https ? 'ssid' : 'sid', $sid)
@@ -465,6 +475,11 @@ function _drupal_session_delete_cookie($name, $secure = NULL) {
* User ID.
*/
function drupal_session_destroy_uid($uid) {
// Nothing to do if we are not allowed to change the session.
if (!drupal_save_session()) {
return;
}
db_delete('sessions')
->condition('uid', $uid)
->execute();
@@ -507,7 +522,10 @@ function _drupal_session_garbage_collection($lifetime) {
* FALSE if writing session data has been disabled. Otherwise, TRUE.
*/
function drupal_save_session($status = NULL) {
$save_session = &drupal_static(__FUNCTION__, TRUE);
// PHP session ID, session, and cookie handling happens in the global scope.
// This value has to persist across calls to drupal_static_reset(), since a
// potentially wrong or disallowed session would be written otherwise.
static $save_session = TRUE;
if (isset($status)) {
$save_session = $status;
}
+3 -3
View File
@@ -553,7 +553,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
* Support for unlink().
*
* @param $uri
* A string containing the uri to the resource to delete.
* A string containing the URI to the resource to delete.
*
* @return
* TRUE if resource was successfully deleted.
@@ -569,9 +569,9 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
* Support for rename().
*
* @param $from_uri,
* The uri to the file to rename.
* The URI to the file to rename.
* @param $to_uri
* The new uri for file.
* The new URI for file.
*
* @return
* TRUE if file was successfully renamed.
+10 -6
View File
@@ -55,7 +55,7 @@ class TableSort extends SelectQueryExtender {
}
/**
* Initialize the table sort context.
* Initializes the table sort context.
*/
protected function init() {
$ts = $this->order();
@@ -115,7 +115,7 @@ function tablesort_init($header) {
}
/**
* Format a column header.
* Formats a column header.
*
* If the cell in question is the column header for the current sort criterion,
* it gets special formatting. All possible sort criteria become links.
@@ -126,6 +126,7 @@ function tablesort_init($header) {
* An array of column headers in the format described in theme_table().
* @param $ts
* The current table sort context as returned from tablesort_init().
*
* @return
* A properly formatted cell, ready for _theme_table_cell().
*/
@@ -151,7 +152,7 @@ function tablesort_header($cell, $header, $ts) {
}
/**
* Format a table cell.
* Formats a table cell.
*
* Adds a class attribute to all cells in the currently active column.
*
@@ -163,6 +164,7 @@ function tablesort_header($cell, $header, $ts) {
* The current table sort context as returned from tablesort_init().
* @param $i
* The index of the cell's table column.
*
* @return
* A properly formatted cell, ready for _theme_table_cell().
*/
@@ -179,7 +181,7 @@ function tablesort_cell($cell, $header, $ts, $i) {
}
/**
* Compose a URL query parameter array for table sorting links.
* Composes a URL query parameter array for table sorting links.
*
* @return
* A URL query parameter array that consists of all components of the current
@@ -190,10 +192,11 @@ function tablesort_get_query_parameters() {
}
/**
* Determine the current sort criterion.
* Determines the current sort criterion.
*
* @param $headers
* An array of column headers in the format described in theme_table().
*
* @return
* An associative array describing the criterion, containing the keys:
* - "name": The localized title of the table column.
@@ -226,10 +229,11 @@ function tablesort_get_order($headers) {
}
/**
* Determine the current sort direction.
* Determines the current sort direction.
*
* @param $headers
* An array of column headers in the format described in theme_table().
*
* @return
* The current sort direction ("asc" or "desc").
*/
+93 -72
View File
@@ -65,7 +65,7 @@ function _drupal_theme_access($theme) {
}
/**
* Initialize the theme system by loading the theme.
* Initializes the theme system by loading the theme.
*/
function drupal_theme_initialize() {
global $theme, $user, $theme_key;
@@ -113,8 +113,9 @@ function drupal_theme_initialize() {
}
/**
* Initialize the theme system given already loaded information. This
* function is useful to initialize a theme when no database is present.
* Initializes the theme system given already loaded information.
*
* This function is useful to initialize a theme when no database is present.
*
* @param $theme
* An object with the following information:
@@ -235,7 +236,7 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb
}
/**
* Get the theme registry.
* Gets the theme registry.
*
* @param $complete
* Optional boolean to indicate whether to return the complete theme registry
@@ -280,7 +281,7 @@ function theme_get_registry($complete = TRUE) {
}
/**
* Set the callback that will be used by theme_get_registry() to fetch the registry.
* Sets the callback that will be used by theme_get_registry().
*
* @param $callback
* The name of the callback function.
@@ -296,7 +297,7 @@ function _theme_registry_callback($callback = NULL, array $arguments = array())
}
/**
* Get the theme_registry cache; if it doesn't exist, build it.
* Gets the theme_registry cache; if it doesn't exist, builds it.
*
* @param $theme
* The loaded $theme object as returned by list_themes().
@@ -336,16 +337,17 @@ function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL,
}
/**
* Write the theme_registry cache into the database.
* Writes the theme_registry cache into the database.
*/
function _theme_save_registry($theme, $registry) {
cache_set("theme_registry:$theme->name", $registry);
}
/**
* Force the system to rebuild the theme registry; this should be called
* when modules are added to the system, or when a dynamic system needs
* to add more theme hooks.
* Forces the system to rebuild the theme registry.
*
* This function should be called when modules are added to the system, or when
* a dynamic system needs to add more theme hooks.
*/
function drupal_theme_rebuild() {
drupal_static_reset('theme_get_registry');
@@ -635,7 +637,8 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
$cache = $result + $cache;
}
// Let themes have variable processors even if they didn't register a template.
// Let themes have variable processors even if they didn't register a
// template.
if ($type == 'theme' || $type == 'base_theme') {
foreach ($cache as $hook => $info) {
// Check only if not registered by the theme or engine.
@@ -662,7 +665,7 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
}
/**
* Build the theme registry cache.
* Builds the theme registry cache.
*
* @param $theme
* The loaded $theme object as returned by list_themes().
@@ -724,7 +727,7 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) {
}
/**
* Return a list of all currently available themes.
* Returns a list of all currently available themes.
*
* Retrieved from the database, if available and the site is not in maintenance
* mode; otherwise compiled freshly from the filesystem.
@@ -766,7 +769,7 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) {
* their base theme), direct sub-themes of sub-themes, etc. The keys are
* the themes' machine names, and the values are the themes' human-readable
* names. This element is not set if there are no themes on the system that
* declare this theme as their base theme.
* declare this theme as their base theme.
*/
function list_themes($refresh = FALSE) {
$list = &drupal_static(__FUNCTION__, array());
@@ -900,15 +903,15 @@ function drupal_find_base_themes($themes, $key, $used_keys = array()) {
* executed (if they exist), in the following order (note that in the following
* list, HOOK indicates the theme hook name, MODULE indicates a module name,
* THEME indicates a theme name, and ENGINE indicates a theme engine name):
* - template_preprocess(&$variables, $hook): Creates a default set of variables
* for all theme hooks with template implementations.
* - template_preprocess(&$variables, $hook): Creates a default set of
* variables for all theme hooks with template implementations.
* - template_preprocess_HOOK(&$variables): Should be implemented by the module
* that registers the theme hook, to set up default variables.
* - MODULE_preprocess(&$variables, $hook): hook_preprocess() is invoked on all
* implementing modules.
* - MODULE_preprocess_HOOK(&$variables): hook_preprocess_HOOK() is invoked on
* all implementing modules, so that modules that didn't define the theme hook
* can alter the variables.
* all implementing modules, so that modules that didn't define the theme
* hook can alter the variables.
* - ENGINE_engine_preprocess(&$variables, $hook): Allows the theme engine to
* set necessary variables for all theme hooks with template implementations.
* - ENGINE_engine_preprocess_HOOK(&$variables): Allows the theme engine to set
@@ -963,10 +966,10 @@ function drupal_find_base_themes($themes, $key, $used_keys = array()) {
* @param $hook
* The name of the theme hook to call. If the name contains a
* double-underscore ('__') and there isn't an implementation for the full
* name, the part before the '__' is checked. This allows a fallback to a more
* generic implementation. For example, if theme('links__node', ...) is
* called, but there is no implementation of that theme hook, then the 'links'
* implementation is used. This process is iterative, so if
* name, the part before the '__' is checked. This allows a fallback to a
* more generic implementation. For example, if theme('links__node', ...) is
* called, but there is no implementation of that theme hook, then the
* 'links' implementation is used. This process is iterative, so if
* theme('links__contextual__node', ...) is called, theme() checks for the
* following implementations, and uses the first one that exists:
* - links__contextual__node
@@ -1030,7 +1033,7 @@ function theme($hook, $variables = array()) {
// Only log a message when not trying theme suggestions ($hook being an
// array).
if (!isset($candidate)) {
watchdog('theme', 'Theme key "@key" not found.', array('@key' => $hook), WATCHDOG_WARNING);
watchdog('theme', 'Theme hook %hook not found.', array('%hook' => $hook), WATCHDOG_WARNING);
}
return '';
}
@@ -1042,7 +1045,8 @@ function theme($hook, $variables = array()) {
// point path_to_theme() to the currently used theme path:
$theme_path = $info['theme path'];
// Include a file if the theme function or variable processor is held elsewhere.
// Include a file if the theme function or variable processor is held
// elsewhere.
if (!empty($info['includes'])) {
foreach ($info['includes'] as $include_file) {
include_once DRUPAL_ROOT . '/' . $include_file;
@@ -1191,14 +1195,14 @@ function theme($hook, $variables = array()) {
}
/**
* Return the path to the current themed element.
* Returns the path to the current themed element.
*
* It can point to the active theme or the module handling a themed implementation.
* For example, when invoked within the scope of a theming call it will depend
* on where the theming function is handled. If implemented from a module, it
* will point to the module. If implemented from the active theme, it will point
* to the active theme. When called outside the scope of a theming call, it will
* always point to the active theme.
* It can point to the active theme or the module handling a themed
* implementation. For example, when invoked within the scope of a theming call
* it will depend on where the theming function is handled. If implemented from
* a module, it will point to the module. If implemented from the active theme,
* it will point to the active theme. When called outside the scope of a
* theming call, it will always point to the active theme.
*/
function path_to_theme() {
global $theme_path;
@@ -1211,7 +1215,7 @@ function path_to_theme() {
}
/**
* Allow themes and/or theme engines to easily discover overridden theme functions.
* Allows themes and/or theme engines to discover overridden theme functions.
*
* @param $cache
* The existing cache of theme hooks to test against.
@@ -1268,7 +1272,7 @@ function drupal_find_theme_functions($cache, $prefixes) {
}
/**
* Allow themes and/or theme engines to easily discover overridden templates.
* Allows themes and/or theme engines to easily discover overridden templates.
*
* @param $cache
* The existing cache of theme hooks to test against.
@@ -1345,7 +1349,8 @@ function drupal_find_theme_templates($cache, $extension, $path) {
if ($matches) {
foreach ($matches as $match) {
$file = substr($match, 0, strpos($match, '.'));
// Put the underscores back in for the hook name and register this pattern.
// Put the underscores back in for the hook name and register this
// pattern.
$arg_name = isset($info['variables']) ? 'variables' : 'render element';
$implementations[strtr($file, '-', '_')] = array(
'template' => $file,
@@ -1361,7 +1366,7 @@ function drupal_find_theme_templates($cache, $extension, $path) {
}
/**
* Retrieve a setting for the current theme or for a given theme.
* Retrieves a setting for the current theme or for a given theme.
*
* The final setting is obtained from the last value found in the following
* sources:
@@ -1479,7 +1484,7 @@ function theme_get_setting($setting_name, $theme = NULL) {
}
/**
* Render a system default template, which is essentially a PHP template.
* Renders a system default template, which is essentially a PHP template.
*
* @param $template_file
* The filename of the template to render.
@@ -1490,14 +1495,21 @@ function theme_get_setting($setting_name, $theme = NULL) {
* The output generated by the template.
*/
function theme_render_template($template_file, $variables) {
extract($variables, EXTR_SKIP); // Extract the variables to a local namespace
ob_start(); // Start output buffering
include DRUPAL_ROOT . '/' . $template_file; // Include the template file
return ob_get_clean(); // End buffering and return its contents
// Extract the variables to a local namespace
extract($variables, EXTR_SKIP);
// Start output buffering
ob_start();
// Include the template file
include DRUPAL_ROOT . '/' . $template_file;
// End buffering and return its contents
return ob_get_clean();
}
/**
* Enable a given list of themes.
* Enables a given list of themes.
*
* @param $theme_list
* An array of theme names.
@@ -1522,7 +1534,7 @@ function theme_enable($theme_list) {
}
/**
* Disable a given list of themes.
* Disables a given list of themes.
*
* @param $theme_list
* An array of theme names.
@@ -1608,13 +1620,13 @@ function theme_status_messages($variables) {
* theme('link') for rendering the anchor tag.
*
* To optimize performance for sites that don't need custom theming of links,
* the l() function includes an inline copy of this function, and uses that copy
* if none of the enabled modules or the active theme implement any preprocess
* or process functions or override this theme implementation.
* the l() function includes an inline copy of this function, and uses that
* copy if none of the enabled modules or the active theme implement any
* preprocess or process functions or override this theme implementation.
*
* @param $variables
* An associative array containing the keys 'text', 'path', and 'options'. See
* the l() function for information about these variables.
* An associative array containing the keys 'text', 'path', and 'options'.
* See the l() function for information about these variables.
*
* @see l()
*/
@@ -1635,15 +1647,16 @@ function theme_link($variables) {
* item in the links list.
* - html: (optional) Whether or not 'title' is HTML. If set, the title
* will not be passed through check_plain().
* - attributes: (optional) Attributes for the anchor, or for the <span> tag
* used in its place if no 'href' is supplied. If element 'class' is
* - attributes: (optional) Attributes for the anchor, or for the <span>
* tag used in its place if no 'href' is supplied. If element 'class' is
* included, it must be an array of one or more class names.
* If the 'href' element is supplied, the entire link array is passed to l()
* as its $options parameter.
* If the 'href' element is supplied, the entire link array is passed to
* l() as its $options parameter.
* - attributes: A keyed array of attributes for the UL containing the
* list of links.
* - heading: (optional) A heading to precede the links. May be an associative
* array or a string. If it's an array, it can have the following elements:
* - heading: (optional) A heading to precede the links. May be an
* associative array or a string. If it's an array, it can have the
* following elements:
* - text: The heading text.
* - level: The heading level (e.g. 'h2', 'h3').
* - class: (optional) An array of the CSS classes for the heading.
@@ -1747,8 +1760,8 @@ function theme_links($variables) {
* attribute to be omitted in some cases. Therefore, this variable defaults
* to an empty string, but can be set to NULL for the attribute to be
* omitted. Usually, neither omission nor an empty string satisfies
* accessibility requirements, so it is strongly encouraged for code calling
* theme('image') to pass a meaningful value for this variable.
* accessibility requirements, so it is strongly encouraged for code
* calling theme('image') to pass a meaningful value for this variable.
* - http://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8
* - http://www.w3.org/TR/xhtml1/dtds.html
* - http://dev.w3.org/html5/spec/Overview.html#alt
@@ -2005,7 +2018,8 @@ function theme_table($variables) {
*
* @param $variables
* An associative array containing:
* - style: Set to either 'asc' or 'desc', this determines which icon to show.
* - style: Set to either 'asc' or 'desc', this determines which icon to
* show.
*/
function theme_tablesort_indicator($variables) {
if ($variables['style'] == "asc") {
@@ -2069,10 +2083,12 @@ function theme_item_list($variables) {
if (!empty($items)) {
$output .= "<$type" . drupal_attributes($attributes) . '>';
$num_items = count($items);
foreach ($items as $i => $item) {
$i = 0;
foreach ($items as $item) {
$attributes = array();
$children = array();
$data = '';
$i++;
if (is_array($item)) {
foreach ($item as $key => $value) {
if ($key == 'data') {
@@ -2093,10 +2109,10 @@ function theme_item_list($variables) {
// Render nested list.
$data .= theme_item_list(array('items' => $children, 'title' => NULL, 'type' => $type, 'attributes' => $attributes));
}
if ($i == 0) {
if ($i == 1) {
$attributes['class'][] = 'first';
}
if ($i == $num_items - 1) {
if ($i == $num_items) {
$attributes['class'][] = 'last';
}
$output .= '<li' . drupal_attributes($attributes) . '>' . $data . "</li>\n";
@@ -2112,7 +2128,7 @@ function theme_item_list($variables) {
*
* @param $variables
* An associative array containing:
* - url: The url for the link.
* - url: The URL for the link.
*/
function theme_more_help_link($variables) {
return '<div class="more-help-link">' . l(t('More help'), $variables['url']) . '</div>';
@@ -2128,7 +2144,7 @@ function theme_more_help_link($variables) {
* - title: A descriptive title of the feed.
*/
function theme_feed_icon($variables) {
$text = t('Subscribe to @feed-title', array('@feed-title' => $variables['title']));
$text = t('Subscribe to !feed-title', array('!feed-title' => $variables['title']));
if ($image = theme('image', array('path' => 'misc/feed.png', 'width' => 16, 'height' => 16, 'alt' => $text))) {
return l($image, $variables['url'], array('html' => TRUE, 'attributes' => array('class' => array('feed-icon'), 'title' => $text)));
}
@@ -2146,7 +2162,8 @@ function theme_feed_icon($variables) {
* - script: To load JavaScript.
* - #attributes: (optional) An array of HTML attributes to apply to the
* tag.
* - #value: (optional) A string containing tag content, such as inline CSS.
* - #value: (optional) A string containing tag content, such as inline
* CSS.
* - #value_prefix: (optional) A string to prepend to #value, e.g. a CDATA
* wrapper prefix.
* - #value_suffix: (optional) A string to append to #value, e.g. a CDATA
@@ -2177,7 +2194,7 @@ function theme_html_tag($variables) {
*
* @param $variables
* An associative array containing:
* - url: The url of the main page.
* - url: The URL of the main page.
* - title: A descriptive verb for the link, like 'Read more'.
*/
function theme_more_link($variables) {
@@ -2314,8 +2331,9 @@ function template_preprocess(&$variables, $hook) {
global $user;
static $count = array();
// Track run count for each hook to provide zebra striping.
// See "template_preprocess_block()" which provides the same feature specific to blocks.
// Track run count for each hook to provide zebra striping. See
// "template_preprocess_block()" which provides the same feature specific to
// blocks.
$count[$hook] = isset($count[$hook]) && is_int($count[$hook]) ? $count[$hook] : 1;
$variables['zebra'] = ($count[$hook] % 2) ? 'odd' : 'even';
$variables['id'] = $count[$hook]++;
@@ -2675,13 +2693,13 @@ function theme_get_suggestions($args, $base, $delimiter = '__') {
}
/**
* The variables array generated here is a mirror of template_preprocess_page().
* This preprocessor will run its course when theme_maintenance_page() is
* invoked.
* Process variables for maintenance-page.tpl.php.
*
* An alternate template file of "maintenance-page--offline.tpl.php" can be
* used when the database is offline to hide errors and completely replace the
* content.
* The variables array generated here is a mirror of
* template_preprocess_page(). This preprocessor will run its course when
* theme_maintenance_page() is invoked. An alternate template file of
* maintenance-page--offline.tpl.php can be used when the database is offline to
* hide errors and completely replace the content.
*
* The $variables array contains the following arguments:
* - $content
@@ -2775,10 +2793,13 @@ function template_preprocess_maintenance_page(&$variables) {
}
/**
* Theme process function for theme_maintenance_field().
*
* The variables array generated here is a mirror of template_process_html().
* This processor will run its course when theme_maintenance_page() is invoked.
*
* @see maintenance-page.tpl.php
* @see template_process_html()
*/
function template_process_maintenance_page(&$variables) {
$variables['head'] = drupal_get_html_head();
@@ -2790,7 +2811,7 @@ function template_process_maintenance_page(&$variables) {
/**
* Preprocess variables for region.tpl.php
*
* Prepare the values passed to the theme_region function to be passed into a
* Prepares the values passed to the theme_region function to be passed into a
* pluggable template engine. Uses the region name to generate a template file
* suggestions. If none are found, the default region.tpl.php is used.
*
+5 -5
View File
@@ -10,9 +10,9 @@
*
* Used for site installs, updates and when the site is in maintenance mode.
* It also applies when the database is unavailable or bootstrap was not
* complete. Seven is always used for the initial install and update operations.
* In other cases, Bartik is used, but this can be overridden by setting a
* "maintenance_theme" key in the $conf variable in settings.php.
* complete. Seven is always used for the initial install and update
* operations. In other cases, Bartik is used, but this can be overridden by
* setting a "maintenance_theme" key in the $conf variable in settings.php.
*/
function _drupal_maintenance_theme() {
global $theme, $theme_key, $conf;
@@ -85,7 +85,7 @@ function _drupal_maintenance_theme() {
}
/**
* This builds the registry when the site needs to bypass any database calls.
* Builds the registry when the site needs to bypass any database calls.
*/
function _theme_load_offline_registry($theme, $base_theme = NULL, $theme_engine = NULL) {
return _theme_build_registry($theme, $base_theme, $theme_engine);
@@ -160,7 +160,7 @@ function theme_update_page($variables) {
}
/**
* Returns HTML for a report of the results from an operation run via authorize.php.
* Returns HTML for a results report of an operation run by authorize.php.
*
* @param $variables
* An associative array containing:
+10 -8
View File
@@ -113,13 +113,13 @@ function token_replace($text, array $data = array(), array $options = array()) {
*/
function token_scan($text) {
// Matches tokens with the following pattern: [$type:$name]
// $type and $name may not contain [ ] or whitespace characters.
// $type may not contain : characters, but $name may.
// $type and $name may not contain [ ] characters.
// $type may not contain : or whitespace characters, but $name may.
preg_match_all('/
\[ # [ - pattern start
([^\s\[\]:]*) # match $type not containing whitespace : [ or ]
: # : - separator
([^\s\[\]]*) # match $name not containing whitespace [ or ]
([^\[\]]*) # match $name not containing [ or ]
\] # ] - pattern end
/x', $text, $matches);
@@ -190,10 +190,10 @@ function token_generate($type, array $tokens, array $data = array(), array $opti
}
/**
* Given a list of tokens, returns those that begin with a specific prefix.
* Returns a list of tokens that begin with a specific prefix.
*
* Used to extract a group of 'chained' tokens (such as [node:author:name]) from
* the full list of tokens found in text. For example:
* Used to extract a group of 'chained' tokens (such as [node:author:name])
* from the full list of tokens found in text. For example:
* @code
* $data = array(
* 'author:name' => '[node:author:name]',
@@ -230,8 +230,10 @@ function token_find_with_prefix(array $tokens, $prefix, $delimiter = ':') {
/**
* Returns metadata describing supported tokens.
*
* The metadata array contains token type, name, and description data as well as
* an optional pointer indicating that the token chains to another set of tokens.
* The metadata array contains token type, name, and description data as well
* as an optional pointer indicating that the token chains to another set of
* tokens.
*
* For example:
* @code
* $data['types']['node'] = array(
+105 -34
View File
@@ -1,5 +1,10 @@
<?php
/**
* @file
* Provides Unicode-related conversions and operations.
*/
/**
* Indicates an error during check for PHP unicode support.
*/
@@ -19,8 +24,6 @@ define('UNICODE_MULTIBYTE', 1);
/**
* Matches Unicode characters that are word boundaries.
*
* @see http://unicode.org/glossary
*
* Characters with the following General_category (gc) property values are used
* as word boundaries. While this does not fully conform to the Word Boundaries
* algorithm described in http://unicode.org/reports/tr29, as PCRE does not
@@ -39,6 +42,8 @@ define('UNICODE_MULTIBYTE', 1);
* Note that the PCRE property matcher is not used because we wanted to be
* compatible with Unicode 5.2.0 regardless of the PCRE version used (and any
* bugs in PCRE property tables).
*
* @see http://unicode.org/glossary
*/
define('PREG_CLASS_UNICODE_WORD_BOUNDARY',
'\x{0}-\x{2F}\x{3A}-\x{40}\x{5B}-\x{60}\x{7B}-\x{A9}\x{AB}-\x{B1}\x{B4}' .
@@ -96,7 +101,7 @@ function unicode_check() {
* Whether to report any fatal errors with form_set_error().
*/
function _unicode_check() {
// Ensure translations don't break at install time
// Ensure translations don't break during installation.
$t = get_t();
// Check for mbstring extension
@@ -125,10 +130,10 @@ function _unicode_check() {
}
/**
* Return Unicode library status and errors.
* Returns Unicode library status and errors.
*/
function unicode_requirements() {
// Ensure translations don't break at install time
// Ensure translations don't break during installation.
$t = get_t();
$libraries = array(
@@ -157,14 +162,14 @@ function unicode_requirements() {
}
/**
* Prepare a new XML parser.
* Prepares a new XML parser.
*
* This is a wrapper around xml_parser_create() which extracts the encoding from
* the XML data first and sets the output encoding to UTF-8. This function should
* be used instead of xml_parser_create(), because PHP 4's XML parser doesn't
* check the input encoding itself. "Starting from PHP 5, the input encoding is
* automatically detected, so that the encoding parameter specifies only the
* output encoding."
* This is a wrapper around xml_parser_create() which extracts the encoding
* from the XML data first and sets the output encoding to UTF-8. This function
* should be used instead of xml_parser_create(), because PHP 4's XML parser
* doesn't check the input encoding itself. "Starting from PHP 5, the input
* encoding is automatically detected, so that the encoding parameter specifies
* only the output encoding."
*
* This is also where unsupported encodings will be converted. Callers should
* take this into account: $data might have been changed after the call.
@@ -213,7 +218,7 @@ function drupal_xml_parser_create(&$data) {
}
/**
* Convert data to UTF-8
* Converts data to UTF-8.
*
* Requires the iconv, GNU recode or mbstring PHP extension.
*
@@ -244,15 +249,15 @@ function drupal_convert_to_utf8($data, $encoding) {
}
/**
* Truncate a UTF-8-encoded string safely to a number of bytes.
* Truncates a UTF-8-encoded string safely to a number of bytes.
*
* If the end position is in the middle of a UTF-8 sequence, it scans backwards
* until the beginning of the byte sequence.
*
* Use this function whenever you want to chop off a string at an unsure
* location. On the other hand, if you're sure that you're splitting on a
* character boundary (e.g. after using strpos() or similar), you can safely use
* substr() instead.
* character boundary (e.g. after using strpos() or similar), you can safely
* use substr() instead.
*
* @param $string
* The string to truncate.
@@ -306,7 +311,7 @@ function drupal_truncate_bytes($string, $len) {
* boundaries, giving you "See myverylongurl..." (assuming you had set
* $add_ellipses to TRUE).
*
* @return
* @return string
* The truncated string.
*/
function truncate_utf8($string, $max_length, $wordsafe = FALSE, $add_ellipsis = FALSE, $min_wordsafe_length = 1) {
@@ -356,8 +361,7 @@ function truncate_utf8($string, $max_length, $wordsafe = FALSE, $add_ellipsis =
}
/**
* Encodes MIME/HTTP header values that contain non-ASCII, UTF-8 encoded
* characters.
* Encodes MIME/HTTP header values that contain incorrectly encoded characters.
*
* For example, mime_header_encode('tést.txt') returns "=?UTF-8?B?dMOpc3QudHh0?=".
*
@@ -369,6 +373,14 @@ function truncate_utf8($string, $max_length, $wordsafe = FALSE, $add_ellipsis =
* each chunk starts and ends on a character boundary.
* - Using \n as the chunk separator may cause problems on some systems and may
* have to be changed to \r\n or \r.
*
* @param $string
* The header to encode.
*
* @return string
* The mime-encoded header.
*
* @see mime_header_decode()
*/
function mime_header_encode($string) {
if (preg_match('/[^\x20-\x7E]/', $string)) {
@@ -388,7 +400,15 @@ function mime_header_encode($string) {
}
/**
* Complement to mime_header_encode
* Decodes MIME/HTTP encoded header values.
*
* @param $header
* The header to decode.
*
* @return string
* The mime-decoded header.
*
* @see mime_header_encode()
*/
function mime_header_decode($header) {
// First step: encoded chunks followed by other encoded chunks (need to collapse whitespace)
@@ -398,7 +418,17 @@ function mime_header_decode($header) {
}
/**
* Helper function to mime_header_decode
* Decodes encoded header data passed from mime_header_decode().
*
* Callback for preg_replace_callback() within mime_header_decode().
*
* @param $matches
* The array of matches from preg_replace_callback().
*
* @return string
* The mime-decoded string.
*
* @see mime_header_decode()
*/
function _mime_header_decode($matches) {
// Regexp groups:
@@ -415,9 +445,9 @@ function _mime_header_decode($matches) {
/**
* Decodes all HTML entities (including numerical ones) to regular UTF-8 bytes.
*
* Double-escaped entities will only be decoded once ("&amp;lt;" becomes "&lt;",
* not "<"). Be careful when using this function, as decode_entities can revert
* previous sanitization efforts (&lt;script&gt; will become <script>).
* Double-escaped entities will only be decoded once ("&amp;lt;" becomes "&lt;"
* , not "<"). Be careful when using this function, as decode_entities can
* revert previous sanitization efforts (&lt;script&gt; will become <script>).
*
* @param $text
* The text to decode entities in.
@@ -430,8 +460,15 @@ function decode_entities($text) {
}
/**
* Count the amount of characters in a UTF-8 string. This is less than or
* equal to the byte count.
* Counts the number of characters in a UTF-8 string.
*
* This is less than or equal to the byte count.
*
* @param $text
* The string to run the operation on.
*
* @return integer
* The length of the string.
*
* @ingroup php_wrappers
*/
@@ -449,6 +486,12 @@ function drupal_strlen($text) {
/**
* Uppercase a UTF-8 string.
*
* @param $text
* The string to run the operation on.
*
* @return string
* The string in uppercase.
*
* @ingroup php_wrappers
*/
function drupal_strtoupper($text) {
@@ -468,6 +511,12 @@ function drupal_strtoupper($text) {
/**
* Lowercase a UTF-8 string.
*
* @param $text
* The string to run the operation on.
*
* @return string
* The string in lowercase.
*
* @ingroup php_wrappers
*/
function drupal_strtolower($text) {
@@ -485,15 +534,28 @@ function drupal_strtolower($text) {
}
/**
* Helper function for case conversion of Latin-1.
* Used for flipping U+C0-U+DE to U+E0-U+FD and back.
* Flips U+C0-U+DE to U+E0-U+FD and back.
*
* @param $matches
* An array of matches.
*
* @return array
* The Latin-1 version of the array of matches.
*
* @see drupal_strtolower()
*/
function _unicode_caseflip($matches) {
return $matches[0][0] . chr(ord($matches[0][1]) ^ 32);
}
/**
* Capitalize the first letter of a UTF-8 string.
* Capitalizes the first letter of a UTF-8 string.
*
* @param $text
* The string to convert.
*
* @return
* The string with the first letter as uppercase.
*
* @ingroup php_wrappers
*/
@@ -503,12 +565,21 @@ function drupal_ucfirst($text) {
}
/**
* Cut off a piece of a string based on character indices and counts. Follows
* the same behavior as PHP's own substr() function.
* Cuts off a piece of a string based on character indices and counts.
*
* Note that for cutting off a string at a known character/substring
* location, the usage of PHP's normal strpos/substr is safe and
* much faster.
* Follows the same behavior as PHP's own substr() function. Note that for
* cutting off a string at a known character/substring location, the usage of
* PHP's normal strpos/substr is safe and much faster.
*
* @param $text
* The input string.
* @param $start
* The position at which to start reading.
* @param $length
* The number of characters to read.
*
* @return
* The shortened string.
*
* @ingroup php_wrappers
*/
+16 -29
View File
@@ -38,7 +38,7 @@ function update_fix_compatibility() {
}
/**
* Helper function to test compatibility of a module or theme.
* Tests the compatibility of a module or theme.
*/
function update_check_incompatibility($name, $type = 'module') {
static $themes, $modules;
@@ -785,12 +785,12 @@ function update_fix_d7_requirements() {
/**
* Register the currently installed profile in the system table.
*
* Install profiles are now treated as modules by Drupal, and have an upgrade
* path based on their schema version in the system table.
* Installation profiles are now treated as modules by Drupal, and have an
* upgrade path based on their schema version in the system table.
*
* The install profile will be set to schema_version 0, as it has already been
* installed. Any other hook_update_N functions provided by the install profile
* will be run by update.php.
* The installation profile will be set to schema_version 0, as it has already
* been installed. Any other hook_update_N functions provided by the
* installation profile will be run by update.php.
*/
function update_fix_d7_install_profile() {
$profile = drupal_get_profile();
@@ -828,10 +828,10 @@ function update_fix_d7_install_profile() {
'owner' => '',
);
// Install profile hooks are always executed last by the module system
// Installation profile hooks are always executed last by the module system
$values['weight'] = 1000;
// Initializing the system table entry for the install profile
// Initializing the system table entry for the installation profile
db_insert('system')
->fields(array_keys($values))
->values($values)
@@ -840,7 +840,8 @@ function update_fix_d7_install_profile() {
// Reset the cached schema version.
drupal_get_installed_schema_version($profile, TRUE);
// Load the updates again to make sure the install profile updates are loaded
// Load the updates again to make sure the installation profile updates
// are loaded.
drupal_load_updates();
}
}
@@ -895,7 +896,7 @@ function update_get_d6_session_name() {
}
else {
// Otherwise use $base_url as session name, without the protocol
// to use the same session identifiers across http and https.
// to use the same session identifiers across HTTP and HTTPS.
list( , $session_name) = explode('://', $base_url, 2);
}
@@ -907,7 +908,7 @@ function update_get_d6_session_name() {
}
/**
* Perform one update and store the results for display on finished page.
* Performs one update and stores the results for display on the results page.
*
* If an update function completes successfully, it should return a message
* as a string indicating success, for example:
@@ -1007,7 +1008,7 @@ function update_do_one($module, $number, $dependency_map, &$context) {
class DrupalUpdateException extends Exception { }
/**
* Start the database update batch process.
* Starts the database update batch process.
*
* @param $start
* An array whose keys contain the names of modules to be updated during the
@@ -1077,7 +1078,7 @@ function update_batch($start, $redirect = NULL, $url = NULL, $batch = array(), $
}
/**
* Finish the update process and store results for eventual display.
* Finishes the update process and stores the results for eventual display.
*
* After the updates run, all caches are flushed. The update results are
* stored into the session (for example, to be displayed on the update results
@@ -1114,7 +1115,7 @@ function update_finished($success, $results, $operations) {
}
/**
* Return a list of all the pending database updates.
* Returns a list of all the pending database updates.
*
* @return
* An associative array keyed by module name which contains all information
@@ -1408,7 +1409,7 @@ function update_already_performed($module, $number) {
}
/**
* Invoke hook_update_dependencies() in all installed modules.
* Invokes hook_update_dependencies() in all installed modules.
*
* This function is similar to module_invoke_all(), with the main difference
* that it does not require that a module be enabled to invoke its hook, only
@@ -1474,17 +1475,3 @@ function update_retrieve_dependencies() {
return $return;
}
/**
* @defgroup update-api-6.x-to-7.x Update versions of API functions
* @{
* Functions similar to normal API function but not firing hooks.
*
* During update, it is impossible to judge the consequences of firing a hook
* as it might hit a module not yet updated. So simplified versions of some
* core APIs are provided.
*/
/**
* @} End of "defgroup update-api-6.x-to-7.x".
*/
+1
View File
@@ -12,6 +12,7 @@
* The variable to export.
* @param $prefix
* A prefix that will be added at the beginning of every lines of the output.
*
* @return
* The variable exported in a way compatible to Drupal's coding standards.
*/
+2 -2
View File
@@ -6,12 +6,12 @@
*/
/**
* Root directory of Drupal installation.
* Defines the root directory of the Drupal installation.
*/
define('DRUPAL_ROOT', getcwd());
/**
* Global flag to indicate that site is in installation mode.
* Global flag to indicate the site is in installation mode.
*/
define('MAINTENANCE_MODE', 'install');
-8
View File
@@ -1,8 +0,0 @@
{
"folders":
[
{
"path": "/Users/bachir/Sites/materio/base_d7"
}
]
}
-807
View File
@@ -1,807 +0,0 @@
{
"auto_complete":
{
"selected_items":
[
[
"font",
"font-size"
],
[
"mat",
"matches"
],
[
"preg",
"preg_match"
],
[
"ima",
"images"
],
[
"alt",
"images_alts"
],
[
"titles",
"images_titles"
],
[
"for",
"foreach foreach …"
],
[
"field",
"field_imago_list"
],
[
"query",
"query_translated"
],
[
"que",
"query_neu"
],
[
"su",
"summary"
],
[
"ti",
"title"
],
[
"ar",
"args"
],
[
"materio",
"materio_search_api"
],
[
"key",
"keys"
],
[
"form",
"form_state"
],
[
"mater",
"materiobase"
],
[
"cal",
"callback"
],
[
"fo",
"form"
],
[
"ty",
"typed"
],
[
"fun",
"function"
],
[
"min",
"min-width"
],
[
"ba",
"background-position"
]
]
},
"buffers":
[
{
"file": "sites/all/themes/gui/materiobasetheme/less/layout.less",
"settings":
{
"buffer_size": 704,
"line_ending": "Unix"
}
},
{
"file": "sites/all/themes/gui/materiobasetheme/less/styles.less",
"settings":
{
"buffer_size": 1269,
"line_ending": "Unix"
}
},
{
"file": "sites/all/modules/gui/materiobasemod/materio_search_api_ajax.module",
"settings":
{
"buffer_size": 1075,
"line_ending": "Unix"
}
},
{
"file": "sites/all/modules/gui/materiobasemod/js/materio_search_api_ajax.js",
"settings":
{
"buffer_size": 3132,
"line_ending": "Unix"
}
},
{
"file": "sites/all/modules/contrib/search/search_api_page/search_api_page.pages.inc",
"settings":
{
"buffer_size": 8151,
"line_ending": "Unix"
}
},
{
"file": "sites/all/modules/contrib/search/search_api_ajax/search_api_ajax.pages.inc",
"settings":
{
"buffer_size": 3972,
"line_ending": "Unix"
}
},
{
"file": "sites/all/modules/contrib/search/search_api_autocomplete/search_api_autocomplete.pages.inc",
"settings":
{
"buffer_size": 3419,
"line_ending": "Unix"
}
},
{
"file": "sites/all/themes/gui/materiobasetheme/js/script.js",
"settings":
{
"buffer_size": 1120,
"line_ending": "Unix"
}
}
],
"build_system": "",
"command_palette":
{
"height": 49.0,
"selected_items":
[
[
"docu",
"Goto Documentation"
],
[
"todo",
"Show TODOs: Open files only"
],
[
"install",
"Package Control: Install Package"
],
[
"package",
"Package Control: Install Package"
],
[
"in",
"Package Control: Install Package"
],
[
"pack",
"Package Control: Install Package"
],
[
"goto",
"Goto Documentation"
],
[
"packa",
"Package Control: List Packages"
],
[
"do",
"Goto Documentation"
],
[
"doc",
"Goto Documentation"
],
[
"inst",
"Package Control: Install Package"
],
[
"go",
"Goto Documentation"
],
[
"packe",
"Package Control: Remove Package"
],
[
"insta",
"Package Control: Install Package"
],
[
"side",
"View: Toggle Side Bar"
],
[
"pac",
"Package Control: Install Package"
],
[
"git",
"Git: Fetch"
],
[
"pa",
"Package Control: Install Package"
],
[
"Package CO",
"Package Control: Install Package"
]
],
"width": 588.0
},
"console":
{
"height": 132.0
},
"distraction_free":
{
"menu_visible": true,
"show_minimap": false,
"show_open_files": false,
"show_tabs": false,
"side_bar_visible": false,
"status_bar_visible": false
},
"file_history":
[
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/users/ajax_register/ajax_register.module",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/users/ajax_register/ajax_register.pages.inc",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/materiobasemod/materio_search_api.info",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/materiobasemod/materio_search_api_ajax.info",
"/Users/bachir/Sites/materio/base_d7/sites/all/themes/gui/materiobasetheme/materiobasetheme.info",
"/Users/bachir/Sites/materio/base_d7/sites/all/themes/gui/materiobasetheme/less/misc.less",
"/Users/bachir/Sites/materio/base_d7/sites/all/themes/gui/materiobasetheme/templates/page.tpl.php",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/materiobasemod/materio_search_api.pages.inc",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/materiobasemod/js/materio_search_api_ajax.js",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/materiobasemod/materio_search_api_ajax.module",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/materiobasemod/materio_search_api_ajax.pages.inc",
"/Users/bachir/Sites/materio/base_d7/sites/all/themes/gui/materiobasetheme/js/script.js",
"/Users/bachir/Sites/materio/base_d7/sites/all/themes/gui/materiobasetheme/less/layout.less",
"/Users/bachir/Sites/materio/base_d7/sites/all/themes/gui/materiobasetheme/less/styles.less",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/materiobasemod/materio_search_api.module",
"/Users/bachir/Library/Application Support/Sublime Text 2/Packages/User/Default (OSX).sublime-keymap",
"/Users/bachir/Sites/materio/base_d7/ac_select_event-365241-54.patch",
"/Users/bachir/Sites/materio/base_d7/sites/all/themes/gui/materiobasetheme/preprocess/page.pre.php",
"/Users/bachir/Sites/materio/base_d7/sites/all/themes/gui/materiobasetheme/css/styles.css",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/materiobasemod/js/materiobaseajax-ck.js",
"/Users/bachir/Library/Application Support/Sublime Text 2/Packages/User/Preferences.sublime-settings",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/fields/entityreference-1.0-rc1/plugins/selection/EntityReference_SelectionHandler_Generic.class.php",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/fields/entityreference/entityreference-user-role-status-filters-1354482-9.patch",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/fields/entityreference/plugins/selection/EntityReference_SelectionHandler_Generic.class.php",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/fields/entityreference/plugins/behavior/EntityReferenceBehavior_ViewsFilterSelect.class.php",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/fields/entityreference/patch url.txt",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/fields/entityreference/patch url",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/fields/entityreference/README.txt",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/materiobasemod/materio_search_api.admin.inc",
"/Users/bachir/Library/Application Support/Sublime Text 2/Packages/Default/Default (OSX).sublime-keymap",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/search/search_api_solr/service.inc",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/migrate_materio/migrate_materio.module",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/migrate_materio/migrate_materio.info",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/migrate_materio/migrate_materio.company.inc",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/migrate_materio/migrate_materio.basic.inc",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/migrate_materio/migrate_materio.materiau.inc",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/migrate_materio/migrate_materio.breves.inc",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/migrate_materio/print-query.php",
"/Users/bachir/Sites/materio/base_d7/sites/sb.basebeta.materio.com/settings.php",
"/Users/bachir/Sites/materio/base_d7/sites/default/settings.php",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/migrate_materio/migrate_materio.admin.inc",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/materiobasemod/js/materiobaseajax.js",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/materiobasemod/materiobaseajax.pages.inc",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/search/search_api_page/search_api_page.pages.inc",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/search/search_api/search_api.module",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/search/search_api_page/search_api_page.module",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/materiobasemod/materiobaseajax.module",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/search/search_api_page/search_api_page.admin.inc",
"/Users/bachir/Sites/materio/base_d7/materio.sublime-project",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/editmenu/editmenu.admin.inc",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/editmenu/editmenu.module",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/contrib/search/search_api/search_api.api.php",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/materiobasemod/templates/materiobase-results.tpl.php",
"/Users/bachir/Sites/materio/base_d7/sites/all/themes/gui/materiobasetheme/templates/search-api-page-results.tpl.php",
"/Users/bachir/Sites/materio/base_d7/sites/all/modules/gui/materiobasemod/templates/materiobase-search-block.tpl.php",
"/Users/bachir/Sites/materio/base_d7/sites/all/themes/gui/materiobasetheme/inc/template.theme-overrides.inc",
"/Users/bachir/Sites/kadist.org/sites/all/modules/contrib/views/views_field_view/views_field_view_handler_field_view.inc",
"/Users/bachir/Sites/kadist.org/_kadist.sublime-project",
"/System/Library/Extensions/GeForce.kext/Contents/PkgInfo",
"/System/Library/Extensions/GeForce.kext/Contents/version.plist",
"/System/Library/Extensions/GeForce.kext/Contents/Info.plist",
"/System/Library/Extensions/GeForce.kext/Contents/MacOS/GeForce",
"/System/Library/Extensions/GeForce.kext/Contents/_CodeSignature/CodeDirectory",
"/System/Library/Extensions/GeForce.kext/Contents/_CodeSignature/CodeRequirements",
"/System/Library/Extensions/GeForce.kext/Contents/_CodeSignature/CodeResources",
"/Users/bachir/Sites/apache.tmproj",
"/Users/bachir/Sites/lesveilleursderennes.com/sites/all/themes/custom/lesveilleursderennes/templates/calendar-month-node.tpl.php",
"/Users/bachir/Sites/lesveilleursderennes.com/_leslveilleursderennes.sublime-project",
"/Volumes/mbp_bach_72hd/Documents/__taff/leslabos/2012/backup kimsufi/mysqldumps/cleanroom.sql",
"/Users/bachir/Sites/kadist.org/sites/all/modules/gui/location_filter/location_filter.module",
"/Users/bachir/Sites/kadist.org/sites/all/modules/gui/kadistqueries/plugins/content_types/kadistqueries_medium_pane.inc",
"/Users/bachir/Sites/kadist.org/sites/all/themes/gui/kadist/less/kadist.less",
"/Users/bachir/Sites/kadist.org/sites/all/modules/gui/kadistqueries/plugins/content_types/kadistqueries_artistes_pane.inc",
"/Users/bachir/Sites/kadist.org/sites/all/modules/gui/kadistqueries/kadistqueries.module",
"/Users/bachir/Library/Application Support/Sublime Text 2/Packages/User/goToSideBar.py",
"/Users/bachir/Sites/kadist.org/sites/kadist.org/drushrc.php",
"/Users/bachir/Library/Application Support/Sublime Text 2/Packages/Default/Preferences.sublime-settings",
"/Users/bachir/Sites/kadist.org/.htaccess",
"/Users/bachir/Sites/kadist.org/sites/all/themes/gui/kadist/templates/block--menu-bar.tpl.php",
"/Users/bachir/Sites/kadist.org/sites/all/themes/gui/kadist/templates/block--search.tpl.php",
"/Users/bachir/Sites/kadist.org/sites/all/themes/gui/kadist/preprocess/block.pre.php",
"/Users/bachir/Sites/kadist.org/MAINTAINERS.txt",
"/Users/bachir/Sites/kadist.org/sites/all/themes/gui/kadist/preprocess/search-result.pre.php",
"/Users/bachir/Sites/kadist.org/sites/all/themes/gui/kadist/preprocess/page.pre.php"
],
"find":
{
"height": 35.0
},
"find_in_files":
{
"height": 0.0,
"where_history":
[
""
]
},
"find_state":
{
"case_sensitive": false,
"find_history":
[
"materiobaseajax",
"sublime",
"materio_search_api",
"page",
"width",
"An",
"function materiobasemod",
"hello world",
"location_filter_item",
"dsm",
"leslabos",
"leslabosblock-typo",
"block-typo",
"\n()",
"location_filter_block_info",
"function",
"super+k",
"super+alt+0",
"f1",
"fold",
"width",
"focus",
"side",
"file",
"reve",
"reveal",
"side"
],
"highlight": true,
"in_selection": false,
"preserve_case": false,
"regex": false,
"replace_history":
[
"materio_search_api_ajax",
"function materio_search_api"
],
"reverse": false,
"show_context": true,
"use_buffer2": true,
"whole_word": false,
"wrap": true
},
"groups":
[
{
"selected": 5,
"sheets":
[
{
"buffer": 0,
"file": "sites/all/themes/gui/materiobasetheme/less/layout.less",
"settings":
{
"buffer_size": 704,
"regions":
{
},
"selection":
[
[
704,
704
]
],
"settings":
{
"buffer_scroll_name": "ca87ca81",
"incomplete_sync": null,
"remote_loading": false,
"synced": false,
"syntax": "Packages/LESS/LESS.tmLanguage",
"tab_size": 2,
"translate_tabs_to_spaces": true
},
"translation.x": 0.0,
"translation.y": 0.0,
"zoom_level": 1.0
},
"type": "text"
},
{
"buffer": 1,
"file": "sites/all/themes/gui/materiobasetheme/less/styles.less",
"settings":
{
"buffer_size": 1269,
"regions":
{
},
"selection":
[
[
422,
422
]
],
"settings":
{
"buffer_scroll_name": "9ad02ee5",
"incomplete_sync": null,
"remote_loading": false,
"synced": false,
"syntax": "Packages/LESS/LESS.tmLanguage",
"tab_size": 2,
"translate_tabs_to_spaces": true
},
"translation.x": 0.0,
"translation.y": 0.0,
"zoom_level": 1.0
},
"type": "text"
},
{
"buffer": 2,
"file": "sites/all/modules/gui/materiobasemod/materio_search_api_ajax.module",
"settings":
{
"buffer_size": 1075,
"regions":
{
},
"selection":
[
[
487,
487
]
],
"settings":
{
"buffer_scroll_name": "7c9ae530",
"incomplete_sync": null,
"remote_loading": false,
"synced": false,
"syntax": "Packages/HTML/HTML.tmLanguage",
"tab_size": 2,
"translate_tabs_to_spaces": true
},
"translation.x": 0.0,
"translation.y": 0.0,
"zoom_level": 1.0
},
"type": "text"
},
{
"buffer": 3,
"file": "sites/all/modules/gui/materiobasemod/js/materio_search_api_ajax.js",
"settings":
{
"buffer_size": 3132,
"regions":
{
},
"selection":
[
[
2039,
2039
]
],
"settings":
{
"buffer_scroll_name": "afdc4774",
"incomplete_sync": null,
"remote_loading": false,
"synced": false,
"syntax": "Packages/JavaScript/JavaScript.tmLanguage",
"tab_size": 2,
"translate_tabs_to_spaces": true
},
"translation.x": 0.0,
"translation.y": 768.0,
"zoom_level": 1.0
},
"type": "text"
},
{
"buffer": 4,
"file": "sites/all/modules/contrib/search/search_api_page/search_api_page.pages.inc",
"settings":
{
"buffer_size": 8151,
"regions":
{
},
"selection":
[
[
3168,
3168
]
],
"settings":
{
"buffer_scroll_name": "7e3a7836",
"incomplete_sync": null,
"remote_loading": false,
"synced": false,
"syntax": "Packages/HTML/HTML.tmLanguage",
"tab_size": 2,
"translate_tabs_to_spaces": true
},
"translation.x": 0.0,
"translation.y": 0.0,
"zoom_level": 1.0
},
"type": "text"
},
{
"buffer": 5,
"file": "sites/all/modules/contrib/search/search_api_ajax/search_api_ajax.pages.inc",
"settings":
{
"buffer_size": 3972,
"regions":
{
},
"selection":
[
[
2007,
2040
]
],
"settings":
{
"buffer_scroll_name": "b86e8334",
"incomplete_sync": null,
"remote_loading": false,
"synced": false,
"syntax": "Packages/HTML/HTML.tmLanguage",
"tab_size": 2,
"translate_tabs_to_spaces": true
},
"translation.x": 0.0,
"translation.y": 581.0,
"zoom_level": 1.0
},
"type": "text"
},
{
"buffer": 6,
"file": "sites/all/modules/contrib/search/search_api_autocomplete/search_api_autocomplete.pages.inc",
"settings":
{
"buffer_size": 3419,
"regions":
{
},
"selection":
[
[
0,
0
]
],
"settings":
{
"buffer_scroll_name": "72908de8",
"incomplete_sync": null,
"remote_loading": false,
"synced": false,
"syntax": "Packages/HTML/HTML.tmLanguage",
"tab_size": 2,
"translate_tabs_to_spaces": true
},
"translation.x": 0.0,
"translation.y": 615.0,
"zoom_level": 1.0
},
"type": "text"
},
{
"buffer": 7,
"file": "sites/all/themes/gui/materiobasetheme/js/script.js",
"settings":
{
"buffer_size": 1120,
"regions":
{
},
"selection":
[
[
21,
21
]
],
"settings":
{
"buffer_scroll_name": "6067f9fe",
"incomplete_sync": null,
"remote_loading": false,
"synced": false,
"syntax": "Packages/JavaScript/JavaScript.tmLanguage",
"tab_size": 2,
"translate_tabs_to_spaces": true
},
"translation.x": 0.0,
"translation.y": 0.0,
"zoom_level": 1.0
},
"type": "text"
}
]
}
],
"incremental_find":
{
"height": 0.0
},
"input":
{
"height": 35.0
},
"layout":
{
"cells":
[
[
0,
0,
1,
1
]
],
"cols":
[
0.0,
1.0
],
"rows":
[
0.0,
1.0
]
},
"menu_visible": true,
"output.exec":
{
"height": 124.0
},
"output.git":
{
"height": 106.0
},
"output.sftp":
{
"height": 0.0
},
"replace":
{
"height": 66.0
},
"save_all_on_build": true,
"select_file":
{
"height": 0.0,
"selected_items":
[
[
"select",
"ac_select_event-365241-54.patch"
],
[
"service",
"sites/all/modules/contrib/search/search_api_solr/service.inc"
],
[
".less",
"sites/all/themes/gui/kadist/less/kadist.less"
],
[
"progra",
"sites/all/modules/gui/location_filter/programs.module"
],
[
"font",
"sites/all/themes/gui/kadist/less/fonts.less"
],
[
"less",
"sites/all/themes/gui/kadist/less/kadist.less"
],
[
"querie",
"sites/all/modules/gui/kadistqueries/plugins/content_types/kadistqueries_artistes_pane.inc"
],
[
"kadist.less",
"sites/all/themes/gui/kadist/less/kadist.less"
],
[
"block--menu",
"sites/all/themes/gui/kadist/templates/block--menu-bar.tpl.php"
],
[
"prepro",
"sites/all/themes/gui/kadist/preprocess/block.pre.php"
],
[
"kadist.le",
"sites/all/themes/gui/kadist/less/kadist.less"
],
[
"",
".htaccess"
],
[
"preprocess",
"sites/all/themes/gui/kadist/preprocess/search-result.pre.php"
],
[
"kadis.less",
"sites/all/themes/gui/kadist/less/kadist.less"
]
],
"width": 0.0
},
"select_project":
{
"height": 500.0,
"selected_items":
[
[
"",
"/Users/bachir/Sites/kadist.org/kadist.sublime-project"
]
],
"width": 380.0
},
"show_minimap": true,
"show_open_files": false,
"show_tabs": true,
"side_bar_visible": true,
"side_bar_width": 357.0,
"status_bar_visible": true
}
+1 -1
View File
@@ -396,7 +396,7 @@ Drupal.ajax.prototype.success = function (response, status) {
Drupal.freezeHeight();
for (var i in response) {
if (response[i]['command'] && this.commands[response[i]['command']]) {
if (response.hasOwnProperty(i) && response[i]['command'] && this.commands[response[i]['command']]) {
this.commands[response[i]['command']](this, response[i], status);
}
}
+2 -2
View File
@@ -58,9 +58,9 @@ Drupal.behaviors.collapse = {
$('fieldset.collapsible', context).once('collapse', function () {
var $fieldset = $(this);
// Expand fieldset if there are errors inside, or if it contains an
// element that is targeted by the uri fragment identifier.
// element that is targeted by the URI fragment identifier.
var anchor = location.hash && location.hash != '#' ? ', ' + location.hash : '';
if ($('.error' + anchor, $fieldset).length) {
if ($fieldset.find('.error' + anchor).length) {
$fieldset.removeClass('collapsed');
}
+21
View File
@@ -6,6 +6,27 @@ jQuery.noConflict();
(function ($) {
/**
* Override jQuery.fn.init to guard against XSS attacks.
*
* See http://bugs.jquery.com/ticket/9521
*/
var jquery_init = $.fn.init;
$.fn.init = function (selector, context, rootjQuery) {
// If the string contains a "#" before a "<", treat it as invalid HTML.
if (selector && typeof selector === 'string') {
var hash_position = selector.indexOf('#');
if (hash_position >= 0) {
var bracket_position = selector.indexOf('<');
if (bracket_position > hash_position) {
throw 'Syntax error, unrecognized expression: ' + selector;
}
}
}
return jquery_init.call(this, selector, context, rootjQuery);
};
$.fn.init.prototype = jquery_init.prototype;
/**
* Attach all registered behaviors to a page element.
*
+1 -1
View File
@@ -80,7 +80,7 @@ Drupal.behaviors.machineName = {
// changes, but only if there is no machine name yet; i.e., only upon
// initial creation, not when editing.
if ($target.val() == '') {
$source.bind('keyup.machineName change.machineName', function () {
$source.bind('keyup.machineName change.machineName input.machineName', function () {
machine = self.transliterate($(this).val(), options);
// Set the machine name to the transliterated value.
if (machine != '') {
+2 -2
View File
@@ -482,8 +482,8 @@ $(document).bind('state:disabled', function(e) {
if (e.trigger) {
$(e.target)
.attr('disabled', e.value)
.filter('.form-element')
.closest('.form-item, .form-submit, .form-wrapper').toggleClass('form-disabled', e.value);
.closest('.form-item, .form-submit, .form-wrapper').toggleClass('form-disabled', e.value)
.find('select, input, textarea').attr('disabled', e.value);
// Note: WebKit nightlies don't reflect that change correctly.
// See https://bugs.webkit.org/show_bug.cgi?id=23789
+1 -1
View File
@@ -126,7 +126,7 @@ Drupal.tableHeader.prototype.eventhandlerRecalculateStickyHeader = function (eve
$stickyCell.css('display', 'none');
}
}
this.stickyTable.css('width', this.originalTable.css('width'));
this.stickyTable.css('width', this.originalTable.outerWidth());
}
};
+2 -2
View File
@@ -50,8 +50,8 @@ Drupal.behaviors.verticalTabs = {
if (!tab_focus) {
// If the current URL has a fragment and one of the tabs contains an
// element that matches the URL fragment, activate that tab.
if (window.location.hash && $(window.location.hash, this).length) {
tab_focus = $(window.location.hash, this).closest('.vertical-tabs-pane');
if (window.location.hash && $(this).find(window.location.hash).length) {
tab_focus = $(this).find(window.location.hash).closest('.vertical-tabs-pane');
}
else {
tab_focus = $('> .vertical-tabs-pane:first', this);
+3
View File
@@ -1,3 +1,6 @@
/**
* Right-to-Left styles for theme in the Aggregator module.
*/
#aggregator .feed-source .feed-icon {
float: left;
+9 -7
View File
@@ -2,11 +2,11 @@
/**
* @file
* Admin page callbacks for the aggregator module.
* Administration page callbacks for the Aggregator module.
*/
/**
* Menu callback; displays the aggregator administration page.
* Page callback: Displays the Aggregator module administration page.
*/
function aggregator_admin_overview() {
return aggregator_view();
@@ -16,7 +16,7 @@ function aggregator_admin_overview() {
* Displays the aggregator administration page.
*
* @return
* The page HTML.
* A HTML-formatted string with administration page content.
*/
function aggregator_view() {
$result = db_query('SELECT f.fid, f.title, f.url, f.refresh, f.checked, f.link, f.description, f.hash, f.etag, f.modified, f.image, f.block, COUNT(i.iid) AS items FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.url, f.refresh, f.checked, f.link, f.description, f.hash, f.etag, f.modified, f.image, f.block ORDER BY f.title');
@@ -56,8 +56,8 @@ function aggregator_view() {
* Form constructor for adding and editing feed sources.
*
* @param $feed
* If editing a feed, the feed to edit as a PHP stdClass value; if adding a
* new feed, NULL.
* (optional) If editing a feed, the feed to edit as a PHP stdClass value; if
* adding a new feed, NULL. Defaults to NULL.
*
* @ingroup forms
* @see aggregator_form_feed_validate()
@@ -77,7 +77,7 @@ function aggregator_form_feed($form, &$form_state, stdClass $feed = NULL) {
$form['url'] = array('#type' => 'textfield',
'#title' => t('URL'),
'#default_value' => isset($feed->url) ? $feed->url : '',
'#maxlength' => 255,
'#maxlength' => NULL,
'#description' => t('The fully-qualified URL of the feed.'),
'#required' => TRUE,
);
@@ -165,6 +165,7 @@ function aggregator_form_feed_validate($form, &$form_state) {
* Form submission handler for aggregator_form_feed().
*
* @see aggregator_form_feed_validate()
*
* @todo Add delete confirmation dialog.
*/
function aggregator_form_feed_submit($form, &$form_state) {
@@ -398,7 +399,7 @@ function _aggregator_parse_opml($opml) {
}
/**
* Menu callback; refreshes a feed, then redirects to the overview page.
* Page callback: Refreshes a feed, then redirects to the overview page.
*
* @param $feed
* An object describing the feed to be refreshed.
@@ -590,6 +591,7 @@ function aggregator_form_category_validate($form, &$form_state) {
* Form submission handler for aggregator_form_category().
*
* @see aggregator_form_category_validate()
*
* @todo Add delete confirmation dialog.
*/
function aggregator_form_category_submit($form, &$form_state) {
+15 -18
View File
@@ -19,8 +19,8 @@
* parser; and finally, it is passed to all active processors, which manipulate
* or store the data.
*
* Modules that define this hook can be set as active fetcher on
* admin/config/services/aggregator. Only one fetcher can be active at a time.
* Modules that define this hook can be set as the active fetcher within the
* configuration page. Only one fetcher can be active at a time.
*
* @param $feed
* A feed object representing the resource to be downloaded. $feed->url
@@ -43,10 +43,9 @@ function hook_aggregator_fetch($feed) {
/**
* Specify the title and short description of your fetcher.
*
* The title and the description provided are shown on
* admin/config/services/aggregator among other places. Use as title the human
* readable name of the fetcher and as description a brief (40 to 80 characters)
* explanation of the fetcher's functionality.
* The title and the description provided are shown within the configuration
* page. Use as title the human readable name of the fetcher and as description
* a brief (40 to 80 characters) explanation of the fetcher's functionality.
*
* This hook is only called if your module implements hook_aggregator_fetch().
* If this hook is not implemented aggregator will use your module's file name
@@ -75,8 +74,8 @@ function hook_aggregator_fetch_info() {
* active parser; and finally, it is passed to all active processors which
* manipulate or store the data.
*
* Modules that define this hook can be set as the active parser on
* admin/config/services/aggregator. Only one parser can be active at a time.
* Modules that define this hook can be set as the active parser within the
* configuration page. Only one parser can be active at a time.
*
* @param $feed
* An object describing the resource to be parsed. $feed->source_string
@@ -119,10 +118,9 @@ function hook_aggregator_parse($feed) {
/**
* Specify the title and short description of your parser.
*
* The title and the description provided are shown on
* admin/config/services/aggregator among other places. Use as title the human
* readable name of the parser and as description a brief (40 to 80 characters)
* explanation of the parser's functionality.
* The title and the description provided are shown within the configuration
* page. Use as title the human readable name of the parser and as description
* a brief (40 to 80 characters) explanation of the parser's functionality.
*
* This hook is only called if your module implements hook_aggregator_parse().
* If this hook is not implemented aggregator will use your module's file name
@@ -151,8 +149,8 @@ function hook_aggregator_parse_info() {
* parser; and finally, it is passed to all active processors that manipulate or
* store the data.
*
* Modules that define this hook can be activated as processor on
* admin/config/services/aggregator.
* Modules that define this hook can be activated as a processor within the
* configuration page.
*
* @param $feed
* A feed object representing the resource to be processed. $feed->items
@@ -176,10 +174,9 @@ function hook_aggregator_process($feed) {
/**
* Specify the title and short description of your processor.
*
* The title and the description provided are shown most importantly on
* admin/config/services/aggregator. Use as title the natural name of the
* processor and as description a brief (40 to 80 characters) explanation of the
* functionality.
* The title and the description provided are shown within the configuration
* page. Use as title the natural name of the processor and as description a
* brief (40 to 80 characters) explanation of the functionality.
*
* This hook is only called if your module implements hook_aggregator_process().
* If this hook is not implemented aggregator will use your module's file name
+3
View File
@@ -1,3 +1,6 @@
/**
* Styles for theme in the Aggregator module.
*/
#aggregator .feed-source .feed-title {
margin-top: 0;
+3 -3
View File
@@ -7,8 +7,8 @@ files[] = aggregator.test
configure = admin/config/services/aggregator/settings
stylesheets[all][] = aggregator.css
; Information added by drupal.org packaging script on 2012-08-01
version = "7.15"
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
project = "drupal"
datestamp = "1343839327"
datestamp = "1365027012"
+38 -16
View File
@@ -130,10 +130,8 @@ function aggregator_schema() {
'description' => 'Title of the feed.',
),
'url' => array(
'type' => 'varchar',
'length' => 255,
'type' => 'text',
'not null' => TRUE,
'default' => '',
'description' => 'URL to the feed.',
),
'refresh' => array(
@@ -155,10 +153,8 @@ function aggregator_schema() {
'description' => 'Time when this feed was queued for refresh, 0 if not queued.',
),
'link' => array(
'type' => 'varchar',
'length' => 255,
'type' => 'text',
'not null' => TRUE,
'default' => '',
'description' => 'The parent website of the feed; comes from the <link> element in the feed.',
),
'description' => array(
@@ -202,13 +198,13 @@ function aggregator_schema() {
)
),
'primary key' => array('fid'),
'unique keys' => array(
'url' => array('url'),
'title' => array('title'),
),
'indexes' => array(
'url' => array(array('url', 255)),
'queued' => array('queued'),
),
'unique keys' => array(
'title' => array('title'),
),
);
$schema['aggregator_item'] = array(
@@ -233,10 +229,8 @@ function aggregator_schema() {
'description' => 'Title of the feed item.',
),
'link' => array(
'type' => 'varchar',
'length' => 255,
'type' => 'text',
'not null' => TRUE,
'default' => '',
'description' => 'Link to the feed item.',
),
'author' => array(
@@ -258,9 +252,8 @@ function aggregator_schema() {
'description' => 'Posted date of the feed item, as a Unix timestamp.',
),
'guid' => array(
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
'type' => 'text',
'not null' => TRUE,
'description' => 'Unique identifier for the feed item.',
)
),
@@ -279,6 +272,11 @@ function aggregator_schema() {
return $schema;
}
/**
* @addtogroup updates-6.x-to-7.x
* @{
*/
/**
* Add hash column to aggregator_feed table.
*/
@@ -306,3 +304,27 @@ function aggregator_update_7002() {
db_add_index('aggregator_feed', 'queued', array('queued'));
}
/**
* @} End of "addtogroup updates-6.x-to-7.x"
*/
/**
* @addtogroup updates-7.x-extra
* @{
*/
/**
* Increase the length of {aggregator_feed}.url.
*/
function aggregator_update_7003() {
db_drop_unique_key('aggregator_feed', 'url');
db_change_field('aggregator_feed', 'url', 'url', array('type' => 'text', 'not null' => TRUE, 'description' => 'URL to the feed.'));
db_change_field('aggregator_feed', 'link', 'link', array('type' => 'text', 'not null' => TRUE, 'description' => 'The parent website of the feed; comes from the <link> element in the feed.'));
db_change_field('aggregator_item', 'link', 'link', array('type' => 'text', 'not null' => TRUE, 'description' => 'Link to the feed item.'));
db_change_field('aggregator_item', 'guid', 'guid', array('type' => 'text', 'not null' => TRUE, 'description' => 'Unique identifier for the feed item.'));
db_add_index('aggregator_feed', 'url', array(array('url', 255)));
}
/**
* @} End of "addtogroup updates-7.x-extra"
*/
+8 -9
View File
@@ -266,13 +266,13 @@ function aggregator_menu() {
}
/**
* Title callback: Returns a title for aggregatory category pages.
* Title callback: Returns a title for aggregator category pages.
*
* @param $category
* An aggregator category.
*
* @return
* An aggregator category title.
* A string with the aggregator category title.
*/
function _aggregator_category_title($category) {
return $category['title'];
@@ -534,6 +534,7 @@ function aggregator_save_feed($edit) {
'url' => $edit['url'],
'refresh' => $edit['refresh'],
'block' => $edit['block'],
'link' => '',
'description' => '',
'image' => '',
))
@@ -568,15 +569,13 @@ function aggregator_remove($feed) {
// Call hook_aggregator_remove() on all modules.
module_invoke_all('aggregator_remove', $feed);
// Reset feed.
db_merge('aggregator_feed')
->key(array('fid' => $feed->fid))
db_update('aggregator_feed')
->condition('fid', $feed->fid)
->fields(array(
'checked' => 0,
'hash' => '',
'etag' => '',
'modified' => 0,
'description' => $feed->description,
'image' => $feed->image,
))
->execute();
}
@@ -724,7 +723,7 @@ function theme_aggregator_block_item($variables) {
}
/**
* Safely renders HTML content, as allowed.
* Renders the HTML content safely, as allowed.
*
* @param $value
* The content to be filtered.
@@ -740,7 +739,7 @@ function aggregator_filter_xss($value) {
* Checks and sanitizes the aggregator configuration.
*
* Goes through all fetchers, parsers and processors and checks whether they
* are available. If one is missing resets to standard configuration.
* are available. If one is missing, resets to standard configuration.
*
* @return
* TRUE if this function resets the configuration; FALSE if not.
@@ -776,7 +775,7 @@ function aggregator_sanitize_configuration() {
* Items count.
*
* @return
* Plural-formatted "@count items"
* A string that is plural-formatted as "@count items".
*/
function _aggregator_items($count) {
return format_plural($count, '1 item', '@count items');
+44 -25
View File
@@ -2,14 +2,14 @@
/**
* @file
* User page callbacks for the aggregator module.
* User page callbacks for the Aggregator module.
*/
/**
* Menu callback; displays the most recent items gathered from any feed.
* Page callback: Displays the most recent items gathered from any feed.
*
* @return
* The items HTML.
* The rendered list of items for the feed.
*/
function aggregator_page_last() {
drupal_add_feed('aggregator/rss', variable_get('site_name', 'Drupal') . ' ' . t('aggregator'));
@@ -20,13 +20,15 @@ function aggregator_page_last() {
}
/**
* Menu callback; displays all the items captured from a particular feed.
* Page callback: Displays all the items captured from the particular feed.
*
* @param $feed
* The feed for which to display all items.
*
* @return
* The rendered list of items for a feed.
*
* @see aggregator_menu()
*/
function aggregator_page_source($feed) {
drupal_set_title($feed->title);
@@ -40,13 +42,13 @@ function aggregator_page_source($feed) {
}
/**
* Menu callback; displays a form with all items captured from a feed.
* Page callback: Displays a form with all items captured from a feed.
*
* @param $feed
* The feed for which to list all the aggregated items.
* The feed for which to list all of the aggregated items.
*
* @return
* The rendered list of items for a feed.
* The rendered list of items for the feed.
*
* @see aggregator_page_source()
*/
@@ -55,13 +57,13 @@ function aggregator_page_source_form($form, $form_state, $feed) {
}
/**
* Menu callback; displays all the items aggregated in a particular category.
* Page callback: Displays all the items aggregated in a particular category.
*
* @param $category
* The category for which to list all the aggregated items.
* The category for which to list all of the aggregated items.
*
* @return
* The rendered list of items for a category.
* The rendered list of items for the feed.
*/
function aggregator_page_category($category) {
drupal_add_feed('aggregator/rss/' . $category['cid'], variable_get('site_name', 'Drupal') . ' ' . t('aggregator - @title', array('@title' => $category['title'])));
@@ -74,13 +76,13 @@ function aggregator_page_category($category) {
}
/**
* Menu callback; displays a form containing items aggregated in a category.
* Page callback: Displays a form containing items aggregated in a category.
*
* @param $category
* The category for which to list all the aggregated items.
* The category for which to list all of the aggregated items.
*
* @return
* The rendered list of items for a category.
* The rendered list of items for the feed.
*
* @see aggregator_page_category()
*/
@@ -166,7 +168,7 @@ function aggregator_feed_items_load($type, $data = NULL) {
* The feed source URL.
*
* @return
* The rendered list of items for a feed.
* The rendered list of items for the feed.
*/
function _aggregator_page_list($items, $op, $feed_source = '') {
if (user_access('administer news feeds') && ($op == 'categorize')) {
@@ -191,10 +193,14 @@ function _aggregator_page_list($items, $op, $feed_source = '') {
* @param $items
* An array of the feed items.
* @param $feed_source
* The feed source URL.
* (optional) The feed source URL. Defaults to an empty string.
*
* @return array
* An array of FAPI elements.
*
* @ingroup forms
* @see aggregator_categorize_items_submit()
* @see theme_aggregator_categorize_items()
* @ingroup forms
*/
function aggregator_categorize_items($items, $feed_source = '') {
$form['#submit'][] = 'aggregator_categorize_items_submit';
@@ -334,7 +340,12 @@ function template_preprocess_aggregator_item(&$variables) {
}
/**
* Menu callback; displays all the feeds used by the aggregator.
* Page callback: Displays all the feeds used by the aggregator.
*
* @return
* An HTML-formatted string.
*
* @see aggregator_menu()
*/
function aggregator_page_sources() {
$result = db_query('SELECT f.fid, f.title, f.description, f.image, MAX(i.timestamp) AS last FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.description, f.image ORDER BY last DESC, f.title');
@@ -358,7 +369,12 @@ function aggregator_page_sources() {
}
/**
* Menu callback; displays all the categories used by the aggregator.
* Page callback: Displays all the categories used by the Aggregator module.
*
* @return string
* An HTML formatted string.
*
* @see aggregator_menu()
*/
function aggregator_page_categories() {
$result = db_query('SELECT c.cid, c.title, c.description FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid LEFT JOIN {aggregator_item} i ON ci.iid = i.iid GROUP BY c.cid, c.title, c.description');
@@ -380,7 +396,10 @@ function aggregator_page_categories() {
}
/**
* Menu callback; generate an RSS 0.92 feed of aggregator items or categories.
* Page callback: Generates an RSS 0.92 feed of aggregator items or categories.
*
* @return string
* An HTML formatted string.
*/
function aggregator_page_rss() {
$result = NULL;
@@ -448,12 +467,14 @@ function theme_aggregator_page_rss($variables) {
}
/**
* Menu callback; generates an OPML representation of all feeds.
* Page callback: Generates an OPML representation of all feeds.
*
* @param $cid
* If set, feeds are exported only from a category with this ID. Otherwise, all feeds are exported.
* (optional) If set, feeds are exported only from a category with this ID.
* Otherwise, all feeds are exported. Defaults to NULL.
*
* @return
* The output XML.
* An OPML formatted string.
*/
function aggregator_page_opml($cid = NULL) {
if ($cid) {
@@ -468,14 +489,12 @@ function aggregator_page_opml($cid = NULL) {
}
/**
* Prints the OPML page for a feed.
* Prints the OPML page for the feed.
*
* @param $variables
* An associative array containing:
* - feeds: An array of the feeds to theme.
*
* @return void
*
* @ingroup themeable
*/
function theme_aggregator_page_opml($variables) {
+8 -1
View File
@@ -38,8 +38,9 @@ function aggregator_aggregator_process($feed) {
$item['timestamp'] = isset($entry->timestamp) ? $entry->timestamp : REQUEST_TIME;
}
// Make sure the item title fits in 255 varchar column.
// Make sure the item title and author fit in the 255 varchar column.
$item['title'] = truncate_utf8($item['title'], 255, TRUE, TRUE);
$item['author'] = truncate_utf8($item['author'], 255, TRUE, TRUE);
aggregator_save_item(array('iid' => (isset($entry->iid) ? $entry->iid : ''), 'fid' => $feed->fid, 'timestamp' => $item['timestamp'], 'title' => $item['title'], 'link' => $item['link'], 'author' => $item['author'], 'description' => $item['description'], 'guid' => $item['guid']));
}
}
@@ -130,6 +131,12 @@ function aggregator_form_aggregator_admin_form_alter(&$form, $form_state) {
*
* Callback for drupal_map_assoc() within
* aggregator_form_aggregator_admin_form_alter().
*
* @param $length
* The desired length of teaser text, in bytes.
*
* @return
* A translated string explaining the teaser string length.
*/
function _aggregator_characters($length) {
return ($length == 0) ? t('Unlimited') : format_plural($length, '1 character', '@count characters');
+181 -94
View File
@@ -5,6 +5,9 @@
* Tests for aggregator.module.
*/
/**
* Defines a base class for testing the Aggregator module.
*/
class AggregatorTestCase extends DrupalWebTestCase {
function setUp() {
parent::setUp('aggregator', 'aggregator_test');
@@ -13,10 +16,15 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
* Create an aggregator feed (simulate form submission on admin/config/services/aggregator/add/feed).
* Creates an aggregator feed.
*
* This method simulates the form submission on path
* admin/config/services/aggregator/add/feed.
*
* @param $feed_url
* If given, feed will be created with this URL, otherwise /rss.xml will be used.
* (optional) If given, feed will be created with this URL, otherwise
* /rss.xml will be used. Defaults to NULL.
*
* @return $feed
* Full feed object if possible.
*
@@ -25,29 +33,30 @@ class AggregatorTestCase extends DrupalWebTestCase {
function createFeed($feed_url = NULL) {
$edit = $this->getFeedEditArray($feed_url);
$this->drupalPost('admin/config/services/aggregator/add/feed', $edit, t('Save'));
$this->assertRaw(t('The feed %name has been added.', array('%name' => $edit['title'])), t('The feed !name has been added.', array('!name' => $edit['title'])));
$this->assertRaw(t('The feed %name has been added.', array('%name' => $edit['title'])), format_string('The feed !name has been added.', array('!name' => $edit['title'])));
$feed = db_query("SELECT * FROM {aggregator_feed} WHERE title = :title AND url = :url", array(':title' => $edit['title'], ':url' => $edit['url']))->fetch();
$this->assertTrue(!empty($feed), t('The feed found in database.'));
$this->assertTrue(!empty($feed), 'The feed found in database.');
return $feed;
}
/**
* Delete an aggregator feed.
* Deletes an aggregator feed.
*
* @param $feed
* Feed object representing the feed.
*/
function deleteFeed($feed) {
$this->drupalPost('admin/config/services/aggregator/edit/feed/' . $feed->fid, array(), t('Delete'));
$this->assertRaw(t('The feed %title has been deleted.', array('%title' => $feed->title)), t('Feed deleted successfully.'));
$this->assertRaw(t('The feed %title has been deleted.', array('%title' => $feed->title)), 'Feed deleted successfully.');
}
/**
* Return a randomly generated feed edit array.
* Returns a randomly generated feed edit array.
*
* @param $feed_url
* If given, feed will be created with this URL, otherwise /rss.xml will be used.
* (optional) If given, feed will be created with this URL, otherwise
* /rss.xml will be used. Defaults to NULL.
* @return
* A feed array.
*/
@@ -68,7 +77,7 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
* Return the count of the randomly created feed array.
* Returns the count of the randomly created feed array.
*
* @return
* Number of feed items on default feed created by createFeed().
@@ -80,17 +89,20 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
* Update feed items (simulate click to admin/config/services/aggregator/update/$fid).
* Updates the feed items.
*
* This method simulates a click to
* admin/config/services/aggregator/update/$fid.
*
* @param $feed
* Feed object representing the feed.
* Feed object representing the feed, passed by reference.
* @param $expected_count
* Expected number of feed items.
*/
function updateFeedItems(&$feed, $expected_count) {
// First, let's ensure we can get to the rss xml.
$this->drupalGet($feed->url);
$this->assertResponse(200, t('!url is reachable.', array('!url' => $feed->url)));
$this->assertResponse(200, format_string('!url is reachable.', array('!url' => $feed->url)));
// Attempt to access the update link directly without an access token.
$this->drupalGet('admin/config/services/aggregator/update/' . $feed->fid);
@@ -108,22 +120,22 @@ class AggregatorTestCase extends DrupalWebTestCase {
$feed->items[] = $item->iid;
}
$feed->item_count = count($feed->items);
$this->assertEqual($expected_count, $feed->item_count, t('Total items in feed equal to the total items in database (!val1 != !val2)', array('!val1' => $expected_count, '!val2' => $feed->item_count)));
$this->assertEqual($expected_count, $feed->item_count, format_string('Total items in feed equal to the total items in database (!val1 != !val2)', array('!val1' => $expected_count, '!val2' => $feed->item_count)));
}
/**
* Confirm item removal from a feed.
* Confirms an item removal from a feed.
*
* @param $feed
* Feed object representing the feed.
*/
function removeFeedItems($feed) {
$this->drupalPost('admin/config/services/aggregator/remove/' . $feed->fid, array(), t('Remove items'));
$this->assertRaw(t('The news items from %title have been removed.', array('%title' => $feed->title)), t('Feed items removed.'));
$this->assertRaw(t('The news items from %title have been removed.', array('%title' => $feed->title)), 'Feed items removed.');
}
/**
* Add and remove feed items and ensure that the count is zero.
* Adds and removes feed items and ensure that the count is zero.
*
* @param $feed
* Feed object representing the feed.
@@ -140,7 +152,7 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
* Pull feed categories from aggregator_category_feed table.
* Pulls feed categories from {aggregator_category_feed} table.
*
* @param $feed
* Feed object representing the feed.
@@ -154,7 +166,11 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
* Pull categories from aggregator_category table.
* Pulls categories from {aggregator_category} table.
*
* @return
* An associative array keyed by category ID and values are set to the
* category names.
*/
function getCategories() {
$categories = array();
@@ -165,14 +181,14 @@ class AggregatorTestCase extends DrupalWebTestCase {
return $categories;
}
/**
* Check if the feed name and url is unique.
* Checks whether the feed name and URL are unique.
*
* @param $feed_name
* String containing the feed name to check.
* @param $feed_url
* String containing the feed url to check.
* String containing the feed URL to check.
*
* @return
* TRUE if feed is unique.
*/
@@ -182,10 +198,11 @@ class AggregatorTestCase extends DrupalWebTestCase {
}
/**
* Create a valid OPML file from an array of feeds.
* Creates a valid OPML file from an array of feeds.
*
* @param $feeds
* An array of feeds.
*
* @return
* Path to valid OPML file.
*/
@@ -223,7 +240,7 @@ EOF;
}
/**
* Create an invalid OPML file.
* Creates an invalid OPML file.
*
* @return
* Path to invalid OPML file.
@@ -240,7 +257,7 @@ EOF;
}
/**
* Create a valid but empty OPML file.
* Creates a valid but empty OPML file.
*
* @return
* Path to empty OPML file.
@@ -275,7 +292,7 @@ EOF;
* Creates sample article nodes.
*
* @param $count
* (optional) The number of nodes to generate.
* (optional) The number of nodes to generate. Defaults to five.
*/
function createSampleNodes($count = 5) {
$langcode = LANGUAGE_NONE;
@@ -290,7 +307,7 @@ EOF;
}
/**
* Tests aggregator configuration settings.
* Tests functionality of the configuration settings in the Aggregator module.
*/
class AggregatorConfigurationTestCase extends AggregatorTestCase {
public static function getInfo() {
@@ -316,11 +333,14 @@ class AggregatorConfigurationTestCase extends AggregatorTestCase {
$this->assertText(t('The configuration options have been saved.'));
foreach ($edit as $name => $value) {
$this->assertFieldByName($name, $value, t('"@name" has correct default value.', array('@name' => $name)));
$this->assertFieldByName($name, $value, format_string('"@name" has correct default value.', array('@name' => $name)));
}
}
}
/**
* Tests adding aggregator feeds.
*/
class AddFeedTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -331,27 +351,59 @@ class AddFeedTestCase extends AggregatorTestCase {
}
/**
* Create a feed, ensure that it is unique, check the source, and delete the feed.
* Creates and ensures that a feed is unique, checks source, and deletes feed.
*/
function testAddFeed() {
$feed = $this->createFeed();
// Check feed data.
$this->assertEqual($this->getUrl(), url('admin/config/services/aggregator/add/feed', array('absolute' => TRUE)), t('Directed to correct url.'));
$this->assertTrue($this->uniqueFeed($feed->title, $feed->url), t('The feed is unique.'));
$this->assertEqual($this->getUrl(), url('admin/config/services/aggregator/add/feed', array('absolute' => TRUE)), 'Directed to correct url.');
$this->assertTrue($this->uniqueFeed($feed->title, $feed->url), 'The feed is unique.');
// Check feed source.
$this->drupalGet('aggregator/sources/' . $feed->fid);
$this->assertResponse(200, t('Feed source exists.'));
$this->assertText($feed->title, t('Page title'));
$this->assertResponse(200, 'Feed source exists.');
$this->assertText($feed->title, 'Page title');
$this->drupalGet('aggregator/sources/' . $feed->fid . '/categorize');
$this->assertResponse(200, t('Feed categorization page exists.'));
$this->assertResponse(200, 'Feed categorization page exists.');
// Delete feed.
$this->deleteFeed($feed);
}
/**
* Tests feeds with very long URLs.
*/
function testAddLongFeed() {
// Create a feed with a URL of > 255 characters.
$long_url = "https://www.google.com/search?ix=heb&sourceid=chrome&ie=UTF-8&q=angie+byron#sclient=psy-ab&hl=en&safe=off&source=hp&q=angie+byron&pbx=1&oq=angie+byron&aq=f&aqi=&aql=&gs_sm=3&gs_upl=0l0l0l10534l0l0l0l0l0l0l0l0ll0l0&bav=on.2,or.r_gc.r_pw.r_cp.,cf.osb&fp=a70b6b1f0abe28d8&biw=1629&bih=889&ix=heb";
$feed = $this->createFeed($long_url);
// Create a second feed of > 255 characters, where the only difference is
// after the 255th character.
$long_url_2 = "https://www.google.com/search?ix=heb&sourceid=chrome&ie=UTF-8&q=angie+byron#sclient=psy-ab&hl=en&safe=off&source=hp&q=angie+byron&pbx=1&oq=angie+byron&aq=f&aqi=&aql=&gs_sm=3&gs_upl=0l0l0l10534l0l0l0l0l0l0l0l0ll0l0&bav=on.2,or.r_gc.r_pw.r_cp.,cf.osb&fp=a70b6b1f0abe28d8&biw=1629&bih=889";
$feed_2 = $this->createFeed($long_url_2);
// Check feed data.
$this->assertTrue($this->uniqueFeed($feed->title, $feed->url), 'The first long URL feed is unique.');
$this->assertTrue($this->uniqueFeed($feed_2->title, $feed_2->url), 'The second long URL feed is unique.');
// Check feed source.
$this->drupalGet('aggregator/sources/' . $feed->fid);
$this->assertResponse(200, 'Long URL feed source exists.');
$this->assertText($feed->title, 'Page title');
$this->drupalGet('aggregator/sources/' . $feed->fid . '/categorize');
$this->assertResponse(200, 'Long URL feed categorization page exists.');
// Delete feeds.
$this->deleteFeed($feed);
$this->deleteFeed($feed_2);
}
}
/**
* Tests the categorize feed functionality in the Aggregator module.
*/
class CategorizeFeedTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -362,18 +414,18 @@ class CategorizeFeedTestCase extends AggregatorTestCase {
}
/**
* Create a feed and make sure you can add more than one category to it.
* Creates a feed and makes sure you can add more than one category to it.
*/
function testCategorizeFeed() {
// Create 2 categories.
$category_1 = array('title' => $this->randomName(10), 'description' => '');
$this->drupalPost('admin/config/services/aggregator/add/category', $category_1, t('Save'));
$this->assertRaw(t('The category %title has been added.', array('%title' => $category_1['title'])), t('The category %title has been added.', array('%title' => $category_1['title'])));
$this->assertRaw(t('The category %title has been added.', array('%title' => $category_1['title'])), format_string('The category %title has been added.', array('%title' => $category_1['title'])));
$category_2 = array('title' => $this->randomName(10), 'description' => '');
$this->drupalPost('admin/config/services/aggregator/add/category', $category_2, t('Save'));
$this->assertRaw(t('The category %title has been added.', array('%title' => $category_2['title'])), t('The category %title has been added.', array('%title' => $category_2['title'])));
$this->assertRaw(t('The category %title has been added.', array('%title' => $category_2['title'])), format_string('The category %title has been added.', array('%title' => $category_2['title'])));
// Get categories from database.
$categories = $this->getCategories();
@@ -391,10 +443,13 @@ class CategorizeFeedTestCase extends AggregatorTestCase {
// Assert the feed has two categories.
$this->getFeedCategories($db_feed);
$this->assertEqual(count($db_feed->categories), 2, t('Feed has 2 categories'));
$this->assertEqual(count($db_feed->categories), 2, 'Feed has 2 categories');
}
}
/**
* Tests functionality of updating the feed in the Aggregator module.
*/
class UpdateFeedTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -405,7 +460,7 @@ class UpdateFeedTestCase extends AggregatorTestCase {
}
/**
* Create a feed and attempt to update it.
* Creates a feed and attempts to update it.
*/
function testUpdateFeed() {
$remamining_fields = array('title', 'url', '');
@@ -419,16 +474,16 @@ class UpdateFeedTestCase extends AggregatorTestCase {
$edit[$same_field] = $feed->{$same_field};
}
$this->drupalPost('admin/config/services/aggregator/edit/feed/' . $feed->fid, $edit, t('Save'));
$this->assertRaw(t('The feed %name has been updated.', array('%name' => $edit['title'])), t('The feed %name has been updated.', array('%name' => $edit['title'])));
$this->assertRaw(t('The feed %name has been updated.', array('%name' => $edit['title'])), format_string('The feed %name has been updated.', array('%name' => $edit['title'])));
// Check feed data.
$this->assertEqual($this->getUrl(), url('admin/config/services/aggregator/', array('absolute' => TRUE)));
$this->assertTrue($this->uniqueFeed($edit['title'], $edit['url']), t('The feed is unique.'));
$this->assertTrue($this->uniqueFeed($edit['title'], $edit['url']), 'The feed is unique.');
// Check feed source.
$this->drupalGet('aggregator/sources/' . $feed->fid);
$this->assertResponse(200, t('Feed source exists.'));
$this->assertText($edit['title'], t('Page title'));
$this->assertResponse(200, 'Feed source exists.');
$this->assertText($edit['title'], 'Page title');
// Delete feed.
$feed->title = $edit['title']; // Set correct title so deleteFeed() will work.
@@ -437,6 +492,9 @@ class UpdateFeedTestCase extends AggregatorTestCase {
}
}
/**
* Tests functionality for removing feeds in the Aggregator module.
*/
class RemoveFeedTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -447,7 +505,7 @@ class RemoveFeedTestCase extends AggregatorTestCase {
}
/**
* Remove a feed and ensure that all it services are removed.
* Removes a feed and ensures that all of its services are removed.
*/
function testRemoveFeed() {
$feed = $this->createFeed();
@@ -457,14 +515,17 @@ class RemoveFeedTestCase extends AggregatorTestCase {
// Check feed source.
$this->drupalGet('aggregator/sources/' . $feed->fid);
$this->assertResponse(404, t('Deleted feed source does not exists.'));
$this->assertResponse(404, 'Deleted feed source does not exists.');
// Check database for feed.
$result = db_query("SELECT COUNT(*) FROM {aggregator_feed} WHERE title = :title AND url = :url", array(':title' => $feed->title, ':url' => $feed->url))->fetchField();
$this->assertFalse($result, t('Feed not found in database'));
$this->assertFalse($result, 'Feed not found in database');
}
}
/**
* Tests functionality of updating a feed item in the Aggregator module.
*/
class UpdateFeedItemTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -475,7 +536,7 @@ class UpdateFeedItemTestCase extends AggregatorTestCase {
}
/**
* Test running "update items" from the 'admin/config/services/aggregator' page.
* Tests running "update items" from 'admin/config/services/aggregator' page.
*/
function testUpdateFeedItem() {
$this->createSampleNodes();
@@ -497,10 +558,10 @@ class UpdateFeedItemTestCase extends AggregatorTestCase {
);
$this->drupalGet($edit['url']);
$this->assertResponse(array(200), t('URL !url is accessible', array('!url' => $edit['url'])));
$this->assertResponse(array(200), format_string('URL !url is accessible', array('!url' => $edit['url'])));
$this->drupalPost('admin/config/services/aggregator/add/feed', $edit, t('Save'));
$this->assertRaw(t('The feed %name has been added.', array('%name' => $edit['title'])), t('The feed !name has been added.', array('!name' => $edit['title'])));
$this->assertRaw(t('The feed %name has been added.', array('%name' => $edit['title'])), format_string('The feed !name has been added.', array('!name' => $edit['title'])));
$feed = db_query("SELECT * FROM {aggregator_feed} WHERE url = :url", array(':url' => $edit['url']))->fetchObject();
@@ -521,7 +582,7 @@ class UpdateFeedItemTestCase extends AggregatorTestCase {
aggregator_refresh($feed);
$after = db_query('SELECT timestamp FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $feed->fid))->fetchField();
$this->assertTrue($before === $after, t('Publish timestamp of feed item was not updated (!before === !after)', array('!before' => $before, '!after' => $after)));
$this->assertTrue($before === $after, format_string('Publish timestamp of feed item was not updated (!before === !after)', array('!before' => $before, '!after' => $after)));
}
}
@@ -535,7 +596,7 @@ class RemoveFeedItemTestCase extends AggregatorTestCase {
}
/**
* Test running "remove items" from the 'admin/config/services/aggregator' page.
* Tests running "remove items" from 'admin/config/services/aggregator' page.
*/
function testRemoveFeedItem() {
// Create a bunch of test feeds.
@@ -554,15 +615,18 @@ class RemoveFeedItemTestCase extends AggregatorTestCase {
// Update and remove items two times in a row to make sure that removal
// resets all 'modified' information (modified, etag, hash) and allows for
// immediate update.
$this->updateAndRemove($feed, 2);
$this->updateAndRemove($feed, 2);
$this->updateAndRemove($feed, 2);
$this->updateAndRemove($feed, 4);
$this->updateAndRemove($feed, 4);
$this->updateAndRemove($feed, 4);
// Delete feed.
$this->deleteFeed($feed);
}
}
}
/**
* Tests categorization functionality in the Aggregator module.
*/
class CategorizeFeedItemTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -573,6 +637,8 @@ class CategorizeFeedItemTestCase extends AggregatorTestCase {
}
/**
* Checks that children of a feed inherit a defined category.
*
* If a feed has a category, make sure that the children inherit that
* categorization.
*/
@@ -582,14 +648,14 @@ class CategorizeFeedItemTestCase extends AggregatorTestCase {
// Simulate form submission on "admin/config/services/aggregator/add/category".
$edit = array('title' => $this->randomName(10), 'description' => '');
$this->drupalPost('admin/config/services/aggregator/add/category', $edit, t('Save'));
$this->assertRaw(t('The category %title has been added.', array('%title' => $edit['title'])), t('The category %title has been added.', array('%title' => $edit['title'])));
$this->assertRaw(t('The category %title has been added.', array('%title' => $edit['title'])), format_string('The category %title has been added.', array('%title' => $edit['title'])));
$category = db_query("SELECT * FROM {aggregator_category} WHERE title = :title", array(':title' => $edit['title']))->fetch();
$this->assertTrue(!empty($category), t('The category found in database.'));
$this->assertTrue(!empty($category), 'The category found in database.');
$link_path = 'aggregator/categories/' . $category->cid;
$menu_link = db_query("SELECT * FROM {menu_links} WHERE link_path = :link_path", array(':link_path' => $link_path))->fetch();
$this->assertTrue(!empty($menu_link), t('The menu link associated with the category found in database.'));
$this->assertTrue(!empty($menu_link), 'The menu link associated with the category found in database.');
$feed = $this->createFeed();
db_insert('aggregator_category_feed')
@@ -600,7 +666,7 @@ class CategorizeFeedItemTestCase extends AggregatorTestCase {
->execute();
$this->updateFeedItems($feed, $this->getDefaultFeedItemCount());
$this->getFeedCategories($feed);
$this->assertTrue(!empty($feed->categories), t('The category found in the feed.'));
$this->assertTrue(!empty($feed->categories), 'The category found in the feed.');
// For each category of a feed, ensure feed items have that category, too.
if (!empty($feed->categories) && !empty($feed->items)) {
@@ -611,7 +677,7 @@ class CategorizeFeedItemTestCase extends AggregatorTestCase {
->execute()
->fetchField();
$this->assertEqual($feed->item_count, $categorized_count, t('Total items in feed equal to the total categorized feed items in database'));
$this->assertEqual($feed->item_count, $categorized_count, 'Total items in feed equal to the total categorized feed items in database');
}
}
@@ -620,6 +686,9 @@ class CategorizeFeedItemTestCase extends AggregatorTestCase {
}
}
/**
* Tests importing feeds from OPML functionality for the Aggregator module.
*/
class ImportOPMLTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -630,7 +699,7 @@ class ImportOPMLTestCase extends AggregatorTestCase {
}
/**
* Open OPML import form.
* Opens OPML import form.
*/
function openImportForm() {
db_delete('aggregator_category')->execute();
@@ -644,22 +713,22 @@ class ImportOPMLTestCase extends AggregatorTestCase {
->execute();
$this->drupalGet('admin/config/services/aggregator/add/opml');
$this->assertText('A single OPML document may contain a collection of many feeds.', t('Found OPML help text.'));
$this->assertField('files[upload]', t('Found file upload field.'));
$this->assertField('remote', t('Found Remote URL field.'));
$this->assertField('refresh', '', t('Found Refresh field.'));
$this->assertFieldByName("category[$cid]", $cid, t('Found category field.'));
$this->assertText('A single OPML document may contain a collection of many feeds.', 'Found OPML help text.');
$this->assertField('files[upload]', 'Found file upload field.');
$this->assertField('remote', 'Found Remote URL field.');
$this->assertField('refresh', 'Found Refresh field.');
$this->assertFieldByName("category[$cid]", $cid, 'Found category field.');
}
/**
* Submit form filled with invalid fields.
* Submits form filled with invalid fields.
*/
function validateImportFormFields() {
$before = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
$edit = array();
$this->drupalPost('admin/config/services/aggregator/add/opml', $edit, t('Import'));
$this->assertRaw(t('You must <em>either</em> upload a file or enter a URL.'), t('Error if no fields are filled.'));
$this->assertRaw(t('You must <em>either</em> upload a file or enter a URL.'), 'Error if no fields are filled.');
$path = $this->getEmptyOpml();
$edit = array(
@@ -667,32 +736,32 @@ class ImportOPMLTestCase extends AggregatorTestCase {
'remote' => file_create_url($path),
);
$this->drupalPost('admin/config/services/aggregator/add/opml', $edit, t('Import'));
$this->assertRaw(t('You must <em>either</em> upload a file or enter a URL.'), t('Error if both fields are filled.'));
$this->assertRaw(t('You must <em>either</em> upload a file or enter a URL.'), 'Error if both fields are filled.');
$edit = array('remote' => 'invalidUrl://empty');
$this->drupalPost('admin/config/services/aggregator/add/opml', $edit, t('Import'));
$this->assertText(t('This URL is not valid.'), t('Error if the URL is invalid.'));
$this->assertText(t('This URL is not valid.'), 'Error if the URL is invalid.');
$after = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
$this->assertEqual($before, $after, t('No feeds were added during the three last form submissions.'));
$this->assertEqual($before, $after, 'No feeds were added during the three last form submissions.');
}
/**
* Submit form with invalid, empty and valid OPML files.
* Submits form with invalid, empty, and valid OPML files.
*/
function submitImportForm() {
$before = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
$form['files[upload]'] = $this->getInvalidOpml();
$this->drupalPost('admin/config/services/aggregator/add/opml', $form, t('Import'));
$this->assertText(t('No new feed has been added.'), t('Attempting to upload invalid XML.'));
$this->assertText(t('No new feed has been added.'), 'Attempting to upload invalid XML.');
$edit = array('remote' => file_create_url($this->getEmptyOpml()));
$this->drupalPost('admin/config/services/aggregator/add/opml', $edit, t('Import'));
$this->assertText(t('No new feed has been added.'), t('Attempting to load empty OPML from remote URL.'));
$this->assertText(t('No new feed has been added.'), 'Attempting to load empty OPML from remote URL.');
$after = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
$this->assertEqual($before, $after, t('No feeds were added during the two last form submissions.'));
$this->assertEqual($before, $after, 'No feeds were added during the two last form submissions.');
db_delete('aggregator_feed')->execute();
db_delete('aggregator_category')->execute();
@@ -716,11 +785,11 @@ class ImportOPMLTestCase extends AggregatorTestCase {
'category[1]' => $category,
);
$this->drupalPost('admin/config/services/aggregator/add/opml', $edit, t('Import'));
$this->assertRaw(t('A feed with the URL %url already exists.', array('%url' => $feeds[0]['url'])), t('Verifying that a duplicate URL was identified'));
$this->assertRaw(t('A feed named %title already exists.', array('%title' => $feeds[1]['title'])), t('Verifying that a duplicate title was identified'));
$this->assertRaw(t('A feed with the URL %url already exists.', array('%url' => $feeds[0]['url'])), 'Verifying that a duplicate URL was identified');
$this->assertRaw(t('A feed named %title already exists.', array('%title' => $feeds[1]['title'])), 'Verifying that a duplicate title was identified');
$after = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
$this->assertEqual($after, 2, t('Verifying that two distinct feeds were added.'));
$this->assertEqual($after, 2, 'Verifying that two distinct feeds were added.');
$feeds_from_db = db_query("SELECT f.title, f.url, f.refresh, cf.cid FROM {aggregator_feed} f LEFT JOIN {aggregator_category_feed} cf ON f.fid = cf.fid");
$refresh = $category = TRUE;
@@ -731,12 +800,15 @@ class ImportOPMLTestCase extends AggregatorTestCase {
$refresh = $refresh && $feed->refresh == 900;
}
$this->assertEqual($title[$feeds[0]['url']], $feeds[0]['title'], t('First feed was added correctly.'));
$this->assertEqual($url[$feeds[1]['title']], $feeds[1]['url'], t('Second feed was added correctly.'));
$this->assertTrue($refresh, t('Refresh times are correct.'));
$this->assertTrue($category, t('Categories are correct.'));
$this->assertEqual($title[$feeds[0]['url']], $feeds[0]['title'], 'First feed was added correctly.');
$this->assertEqual($url[$feeds[1]['title']], $feeds[1]['url'], 'Second feed was added correctly.');
$this->assertTrue($refresh, 'Refresh times are correct.');
$this->assertTrue($category, 'Categories are correct.');
}
/**
* Tests the import of an OPML file.
*/
function testOPMLImport() {
$this->openImportForm();
$this->validateImportFormFields();
@@ -744,6 +816,9 @@ class ImportOPMLTestCase extends AggregatorTestCase {
}
}
/**
* Tests functionality of the cron process in the Aggregator module.
*/
class AggregatorCronTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -754,7 +829,7 @@ class AggregatorCronTestCase extends AggregatorTestCase {
}
/**
* Add feeds update them on cron.
* Adds feeds and updates them via cron process.
*/
public function testCron() {
// Create feed and test basic updating on cron.
@@ -790,6 +865,9 @@ class AggregatorCronTestCase extends AggregatorTestCase {
}
}
/**
* Tests rendering functionality in the Aggregator module.
*/
class AggregatorRenderingTestCase extends AggregatorTestCase {
public static function getInfo() {
return array(
@@ -800,9 +878,9 @@ class AggregatorRenderingTestCase extends AggregatorTestCase {
}
/**
* Add a feed block to the page and checks its links.
* Adds a feed block to the page and checks its links.
*
* TODO: Test the category block as well.
* @todo Test the category block as well.
*/
public function testBlockLinks() {
// Create feed.
@@ -834,20 +912,20 @@ class AggregatorRenderingTestCase extends AggregatorTestCase {
$this->assertFieldByName('blocks[' . $block['module'] . '_' . $block['delta'] . '][region]', '', 'Aggregator feed block is available for positioning.');
// Position it.
$this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
$this->assertText(t('The block settings have been updated.'), t('Block successfully moved to %region_name region.', array( '%region_name' => $region)));
$this->assertText(t('The block settings have been updated.'), format_string('Block successfully moved to %region_name region.', array( '%region_name' => $region)));
// Confirm that the block is now being displayed on pages.
$this->drupalGet('node');
$this->assertText(t($block['title']), t('Feed block is displayed on the page.'));
$this->assertText(t($block['title']), 'Feed block is displayed on the page.');
// Find the expected read_more link.
$href = 'aggregator/sources/' . $feed->fid;
$links = $this->xpath('//a[@href = :href]', array(':href' => url($href)));
$this->assert(isset($links[0]), t('Link to href %href found.', array('%href' => $href)));
$this->assert(isset($links[0]), format_string('Link to href %href found.', array('%href' => $href)));
// Visit that page.
$this->drupalGet($href);
$correct_titles = $this->xpath('//h1[normalize-space(text())=:title]', array(':title' => $feed->title));
$this->assertFalse(empty($correct_titles), t('Aggregator feed page is available and has the correct title.'));
$this->assertFalse(empty($correct_titles), 'Aggregator feed page is available and has the correct title.');
// Set the number of news items to 0 to test that the block does not show
// up.
@@ -861,7 +939,7 @@ class AggregatorRenderingTestCase extends AggregatorTestCase {
}
/**
* Create a feed and check that feed's page.
* Creates a feed and checks that feed's page.
*/
public function testFeedPage() {
// Increase the number of items published in the rss.xml feed so we have
@@ -876,7 +954,7 @@ class AggregatorRenderingTestCase extends AggregatorTestCase {
// Check for the presence of a pager.
$this->drupalGet('aggregator/sources/' . $feed->fid);
$elements = $this->xpath("//ul[@class=:class]", array(':class' => 'pager'));
$this->assertTrue(!empty($elements), t('Individual source page contains a pager.'));
$this->assertTrue(!empty($elements), 'Individual source page contains a pager.');
// Reset the number of items in rss.xml to the default value.
variable_set('feed_default_items', 10);
@@ -884,7 +962,7 @@ class AggregatorRenderingTestCase extends AggregatorTestCase {
}
/**
* Tests for feed parsing.
* Tests feed parsing in the Aggregator module.
*/
class FeedParserTestCase extends AggregatorTestCase {
public static function getInfo() {
@@ -904,26 +982,35 @@ class FeedParserTestCase extends AggregatorTestCase {
}
/**
* Test a feed that uses the RSS 0.91 format.
* Tests a feed that uses the RSS 0.91 format.
*/
function testRSS091Sample() {
$feed = $this->createFeed($this->getRSS091Sample());
aggregator_refresh($feed);
$this->drupalGet('aggregator/sources/' . $feed->fid);
$this->assertResponse(200, t('Feed %name exists.', array('%name' => $feed->title)));
$this->assertResponse(200, format_string('Feed %name exists.', array('%name' => $feed->title)));
$this->assertText('First example feed item title');
$this->assertLinkByHref('http://example.com/example-turns-one');
$this->assertText('First example feed item description.');
// Several additional items that include elements over 255 characters.
$this->assertRaw("Second example feed item title.");
$this->assertText('Long link feed item title');
$this->assertText('Long link feed item description');
$this->assertLinkByHref('http://example.com/tomorrow/and/tomorrow/and/tomorrow/creeps/in/this/petty/pace/from/day/to/day/to/the/last/syllable/of/recorded/time/and/all/our/yesterdays/have/lighted/fools/the/way/to/dusty/death/out/out/brief/candle/life/is/but/a/walking/shadow/a/poor/player/that/struts/and/frets/his/hour/upon/the/stage/and/is/heard/no/more/it/is/a/tale/told/by/an/idiot/full/of/sound/and/fury/signifying/nothing');
$this->assertText('Long author feed item title');
$this->assertText('Long author feed item description');
$this->assertLinkByHref('http://example.com/long/author');
}
/**
* Test a feed that uses the Atom format.
* Tests a feed that uses the Atom format.
*/
function testAtomSample() {
$feed = $this->createFeed($this->getAtomSample());
aggregator_refresh($feed);
$this->drupalGet('aggregator/sources/' . $feed->fid);
$this->assertResponse(200, t('Feed %name exists.', array('%name' => $feed->title)));
$this->assertResponse(200, format_string('Feed %name exists.', array('%name' => $feed->title)));
$this->assertText('Atom-Powered Robots Run Amok');
$this->assertLinkByHref('http://example.org/2003/12/13/atom03');
$this->assertText('Some text.');
@@ -5,8 +5,8 @@ version = VERSION
core = 7.x
hidden = TRUE
; Information added by drupal.org packaging script on 2012-08-01
version = "7.15"
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
project = "drupal"
datestamp = "1343839327"
datestamp = "1365027012"
@@ -26,5 +26,16 @@
<link>http://example.com/example-turns-two</link>
<description>Second example feed item description.</description>
</item>
<item>
<title>Long link feed item title.</title>
<link>http://example.com/tomorrow/and/tomorrow/and/tomorrow/creeps/in/this/petty/pace/from/day/to/day/to/the/last/syllable/of/recorded/time/and/all/our/yesterdays/have/lighted/fools/the/way/to/dusty/death/out/out/brief/candle/life/is/but/a/walking/shadow/a/poor/player/that/struts/and/frets/his/hour/upon/the/stage/and/is/heard/no/more/it/is/a/tale/told/by/an/idiot/full/of/sound/and/fury/signifying/nothing</link>
<description>Long link feed item description.</description>
</item>
<item>
<title>Long author feed item title.</title>
<link>http://example.com/long/author</link>
<author>I wanted to get out and walk eastward toward the park through the soft twilight, but each time I tried to go I became entangled in some wild, strident argument which pulled me back, as if with ropes, into my chair. Yet high over the city our line of yellow windows must have contributed their share of human secrecy to the casual watcher in the darkening streets, and I was him too, looking up and wondering. I was within and without, simultaneously enchanted and repelled by the inexhaustible variety of life.</author>
<description>Long author feed item description.</description>
</item>
</channel>
</rss>
+1
View File
@@ -55,6 +55,7 @@
* viewed.
* - DRUPAL_CACHE_GLOBAL: The block is the same for every user on every page
* where it is visible.
* - DRUPAL_CACHE_CUSTOM: The module implements its own caching system.
* - DRUPAL_NO_CACHE: The block should not get cached.
* - properties: (optional) Array of additional metadata to add to the block.
* Common properties include:
+3 -3
View File
@@ -6,8 +6,8 @@ core = 7.x
files[] = block.test
configure = admin/structure/block
; Information added by drupal.org packaging script on 2012-08-01
version = "7.15"
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
project = "drupal"
datestamp = "1343839327"
datestamp = "1365027012"
+1 -1
View File
@@ -740,7 +740,7 @@ function _block_load_blocks() {
/**
* Implements hook_block_list_alter().
*
* Checks the page, user role, and user-specific visibilty settings.
* Checks the page, user role, and user-specific visibility settings.
* Removes the block if the visibility conditions are not met.
*/
function block_block_list_alter(&$blocks) {
+65 -65
View File
@@ -45,9 +45,9 @@ class BlockTestCase extends DrupalWebTestCase {
function testCustomBlock() {
// Confirm that the add block link appears on block overview pages.
$this->drupalGet('admin/structure/block');
$this->assertRaw(l('Add block', 'admin/structure/block/add'), t('Add block link is present on block overview page for default theme.'));
$this->assertRaw(l('Add block', 'admin/structure/block/add'), 'Add block link is present on block overview page for default theme.');
$this->drupalGet('admin/structure/block/list/seven');
$this->assertRaw(l('Add block', 'admin/structure/block/list/seven/add'), t('Add block link is present on block overview page for non-default theme.'));
$this->assertRaw(l('Add block', 'admin/structure/block/list/seven/add'), 'Add block link is present on block overview page for non-default theme.');
// Confirm that hidden regions are not shown as options for block placement
// when adding a new block.
@@ -58,7 +58,7 @@ class BlockTestCase extends DrupalWebTestCase {
if ($theme->status) {
foreach ($theme->info['regions_hidden'] as $hidden_region) {
$elements = $this->xpath('//select[@id=:id]//option[@value=:value]', array(':id' => 'edit-regions-' . $key, ':value' => $hidden_region));
$this->assertFalse(isset($elements[0]), t('The hidden region @region is not available for @theme.', array('@region' => $hidden_region, '@theme' => $key)));
$this->assertFalse(isset($elements[0]), format_string('The hidden region @region is not available for @theme.', array('@region' => $hidden_region, '@theme' => $key)));
}
}
}
@@ -71,17 +71,17 @@ class BlockTestCase extends DrupalWebTestCase {
$this->drupalPost('admin/structure/block/add', $custom_block, t('Save block'));
// Confirm that the custom block has been created, and then query the created bid.
$this->assertText(t('The block has been created.'), t('Custom block successfully created.'));
$this->assertText(t('The block has been created.'), 'Custom block successfully created.');
$bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField();
// Check to see if the custom block was created by checking that it's in the database.
$this->assertNotNull($bid, t('Custom block found in database'));
$this->assertNotNull($bid, 'Custom block found in database');
// Check that block_block_view() returns the correct title and content.
$data = block_block_view($bid);
$format = db_query("SELECT format FROM {block_custom} WHERE bid = :bid", array(':bid' => $bid))->fetchField();
$this->assertTrue(array_key_exists('subject', $data) && empty($data['subject']), t('block_block_view() provides an empty block subject, since custom blocks do not have default titles.'));
$this->assertEqual(check_markup($custom_block['body[value]'], $format), $data['content'], t('block_block_view() provides correct block content.'));
$this->assertTrue(array_key_exists('subject', $data) && empty($data['subject']), 'block_block_view() provides an empty block subject, since custom blocks do not have default titles.');
$this->assertEqual(check_markup($custom_block['body[value]'], $format), $data['content'], 'block_block_view() provides correct block content.');
// Check whether the block can be moved to all available regions.
$custom_block['module'] = 'block';
@@ -92,8 +92,8 @@ class BlockTestCase extends DrupalWebTestCase {
// Verify presence of configure and delete links for custom block.
$this->drupalGet('admin/structure/block');
$this->assertLinkByHref('admin/structure/block/manage/block/' . $bid . '/configure', 0, t('Custom block configure link found.'));
$this->assertLinkByHref('admin/structure/block/manage/block/' . $bid . '/delete', 0, t('Custom block delete link found.'));
$this->assertLinkByHref('admin/structure/block/manage/block/' . $bid . '/configure', 0, 'Custom block configure link found.');
$this->assertLinkByHref('admin/structure/block/manage/block/' . $bid . '/delete', 0, 'Custom block delete link found.');
// Set visibility only for authenticated users, to verify delete functionality.
$edit = array();
@@ -103,10 +103,10 @@ class BlockTestCase extends DrupalWebTestCase {
// Delete the created custom block & verify that it's been deleted and no longer appearing on the page.
$this->clickLink(t('delete'));
$this->drupalPost('admin/structure/block/manage/block/' . $bid . '/delete', array(), t('Delete'));
$this->assertRaw(t('The block %title has been removed.', array('%title' => $custom_block['info'])), t('Custom block successfully deleted.'));
$this->assertNoText(t($custom_block['title']), t('Custom block no longer appears on page.'));
$this->assertRaw(t('The block %title has been removed.', array('%title' => $custom_block['info'])), 'Custom block successfully deleted.');
$this->assertNoText(t($custom_block['title']), 'Custom block no longer appears on page.');
$count = db_query("SELECT 1 FROM {block_role} WHERE module = :module AND delta = :delta", array(':module' => $custom_block['module'], ':delta' => $custom_block['delta']))->fetchField();
$this->assertFalse($count, t('Table block_role being cleaned.'));
$this->assertFalse($count, 'Table block_role being cleaned.');
}
/**
@@ -130,20 +130,20 @@ class BlockTestCase extends DrupalWebTestCase {
// Confirm that the custom block is being displayed using configured text format.
$this->drupalGet('node');
$this->assertRaw('<h1>Full HTML</h1>', t('Custom block successfully being displayed using Full HTML.'));
$this->assertRaw('<h1>Full HTML</h1>', 'Custom block successfully being displayed using Full HTML.');
// Confirm that a user without access to Full HTML can not see the body field,
// but can still submit the form without errors.
$block_admin = $this->drupalCreateUser(array('administer blocks'));
$this->drupalLogin($block_admin);
$this->drupalGet('admin/structure/block/manage/block/' . $bid . '/configure');
$this->assertFieldByXPath("//textarea[@name='body[value]' and @disabled='disabled']", t('This field has been disabled because you do not have sufficient permissions to edit it.'), t('Body field contains denied message'));
$this->assertFieldByXPath("//textarea[@name='body[value]' and @disabled='disabled']", t('This field has been disabled because you do not have sufficient permissions to edit it.'), 'Body field contains denied message');
$this->drupalPost('admin/structure/block/manage/block/' . $bid . '/configure', array(), t('Save block'));
$this->assertNoText(t('Ensure that each block description is unique.'));
// Confirm that the custom block is still being displayed using configured text format.
$this->drupalGet('node');
$this->assertRaw('<h1>Full HTML</h1>', t('Custom block successfully being displayed using Full HTML.'));
$this->assertRaw('<h1>Full HTML</h1>', 'Custom block successfully being displayed using Full HTML.');
}
/**
@@ -178,18 +178,18 @@ class BlockTestCase extends DrupalWebTestCase {
$this->moveBlockToRegion($block, $this->regions[1]);
$this->drupalGet('');
$this->assertText($title, t('Block was displayed on the front page.'));
$this->assertText($title, 'Block was displayed on the front page.');
$this->drupalGet('user');
$this->assertNoText($title, t('Block was not displayed according to block visibility rules.'));
$this->assertNoText($title, 'Block was not displayed according to block visibility rules.');
$this->drupalGet('USER/' . $this->admin_user->uid);
$this->assertNoText($title, t('Block was not displayed according to block visibility rules regardless of path case.'));
$this->assertNoText($title, 'Block was not displayed according to block visibility rules regardless of path case.');
// Confirm that the block is not displayed to anonymous users.
$this->drupalLogout();
$this->drupalGet('');
$this->assertNoText($title, t('Block was not displayed to anonymous users.'));
$this->assertNoText($title, 'Block was not displayed to anonymous users.');
}
/**
@@ -224,15 +224,15 @@ class BlockTestCase extends DrupalWebTestCase {
$this->drupalPost('admin/structure/block/manage/' . $block['module'] . '/' . $block['delta'] . '/configure', $edit, t('Save block'));
$this->drupalGet('');
$this->assertNoText($title, t('Block was not displayed according to block visibility rules.'));
$this->assertNoText($title, 'Block was not displayed according to block visibility rules.');
$this->drupalGet('user');
$this->assertNoText($title, t('Block was not displayed according to block visibility rules regardless of path case.'));
$this->assertNoText($title, 'Block was not displayed according to block visibility rules regardless of path case.');
// Confirm that the block is not displayed to anonymous users.
$this->drupalLogout();
$this->drupalGet('');
$this->assertNoText($title, t('Block was not displayed to anonymous users.'));
$this->assertNoText($title, 'Block was not displayed to anonymous users.');
}
/**
@@ -270,7 +270,7 @@ class BlockTestCase extends DrupalWebTestCase {
$this->drupalPost('user/' . $this->admin_user->uid . '/edit', $edit, t('Save'));
$this->drupalGet('');
$this->assertNoText($block['title'], t('Block was not displayed according to per user block visibility setting.'));
$this->assertNoText($block['title'], 'Block was not displayed according to per user block visibility setting.');
// Set the block to be customizable per user, hidden by default.
$edit = array();
@@ -283,7 +283,7 @@ class BlockTestCase extends DrupalWebTestCase {
$this->drupalPost('user/' . $this->admin_user->uid . '/edit', $edit, t('Save'));
$this->drupalGet('');
$this->assertText($block['title'], t('Block was displayed according to per user block visibility setting.'));
$this->assertText($block['title'], 'Block was displayed according to per user block visibility setting.');
}
/**
@@ -298,14 +298,14 @@ class BlockTestCase extends DrupalWebTestCase {
// Set block title to confirm that interface works and override any custom titles.
$this->drupalPost('admin/structure/block/manage/' . $block['module'] . '/' . $block['delta'] . '/configure', array('title' => $block['title']), t('Save block'));
$this->assertText(t('The block configuration has been saved.'), t('Block title set.'));
$this->assertText(t('The block configuration has been saved.'), 'Block title set.');
$bid = db_query("SELECT bid FROM {block} WHERE module = :module AND delta = :delta", array(
':module' => $block['module'],
':delta' => $block['delta'],
))->fetchField();
// Check to see if the block was created by checking that it's in the database.
$this->assertNotNull($bid, t('Block found in database'));
$this->assertNotNull($bid, 'Block found in database');
// Check whether the block can be moved to all available regions.
foreach ($this->regions as $region) {
@@ -318,21 +318,21 @@ class BlockTestCase extends DrupalWebTestCase {
$this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
// Confirm that the block was moved to the proper region.
$this->assertText(t('The block settings have been updated.'), t('Block successfully move to disabled region.'));
$this->assertNoText(t($block['title']), t('Block no longer appears on page.'));
$this->assertText(t('The block settings have been updated.'), 'Block successfully move to disabled region.');
$this->assertNoText(t($block['title']), 'Block no longer appears on page.');
// Confirm that the region's xpath is not available.
$xpath = $this->buildXPathQuery('//div[@id=:id]/*', array(':id' => 'block-block-' . $bid));
$this->assertNoFieldByXPath($xpath, FALSE, t('Custom block found in no regions.'));
$this->assertNoFieldByXPath($xpath, FALSE, 'Custom block found in no regions.');
// For convenience of developers, put the navigation block back.
$edit = array();
$edit['blocks[' . $block['module'] . '_' . $block['delta'] . '][region]'] = $this->regions[1];
$this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
$this->assertText(t('The block settings have been updated.'), t('Block successfully move to first sidebar region.'));
$this->assertText(t('The block settings have been updated.'), 'Block successfully move to first sidebar region.');
$this->drupalPost('admin/structure/block/manage/' . $block['module'] . '/' . $block['delta'] . '/configure', array('title' => 'Navigation'), t('Save block'));
$this->assertText(t('The block configuration has been saved.'), t('Block title set.'));
$this->assertText(t('The block configuration has been saved.'), 'Block title set.');
}
function moveBlockToRegion($block, $region) {
@@ -342,18 +342,18 @@ class BlockTestCase extends DrupalWebTestCase {
$this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
// Confirm that the block was moved to the proper region.
$this->assertText(t('The block settings have been updated.'), t('Block successfully moved to %region_name region.', array( '%region_name' => $region)));
$this->assertText(t('The block settings have been updated.'), format_string('Block successfully moved to %region_name region.', array( '%region_name' => $region)));
// Confirm that the block is being displayed.
$this->drupalGet('node');
$this->assertText(t($block['title']), t('Block successfully being displayed on the page.'));
$this->assertText(t($block['title']), 'Block successfully being displayed on the page.');
// Confirm that the custom block was found at the proper region.
$xpath = $this->buildXPathQuery('//div[@class=:region-class]//div[@id=:block-id]/*', array(
':region-class' => 'region region-' . str_replace('_', '-', $region),
':block-id' => 'block-' . $block['module'] . '-' . $block['delta'],
));
$this->assertFieldByXPath($xpath, NULL, t('Custom block found in %region_name region.', array('%region_name' => $region)));
$this->assertFieldByXPath($xpath, NULL, format_string('Custom block found in %region_name region.', array('%region_name' => $region)));
}
/**
@@ -361,14 +361,14 @@ class BlockTestCase extends DrupalWebTestCase {
*/
function testBlockRehash() {
module_enable(array('block_test'));
$this->assertTrue(module_exists('block_test'), t('Test block module enabled.'));
$this->assertTrue(module_exists('block_test'), 'Test block module enabled.');
// Our new block should be inserted in the database when we visit the
// block management page.
$this->drupalGet('admin/structure/block');
// Our test block's caching should default to DRUPAL_CACHE_PER_ROLE.
$current_caching = db_query("SELECT cache FROM {block} WHERE module = 'block_test' AND delta = 'test_cache'")->fetchField();
$this->assertEqual($current_caching, DRUPAL_CACHE_PER_ROLE, t('Test block cache mode defaults to DRUPAL_CACHE_PER_ROLE.'));
$this->assertEqual($current_caching, DRUPAL_CACHE_PER_ROLE, 'Test block cache mode defaults to DRUPAL_CACHE_PER_ROLE.');
// Disable caching for this block.
variable_set('block_test_caching', DRUPAL_NO_CACHE);
@@ -376,7 +376,7 @@ class BlockTestCase extends DrupalWebTestCase {
drupal_flush_all_caches();
// Verify that the database is updated with the new caching mode.
$current_caching = db_query("SELECT cache FROM {block} WHERE module = 'block_test' AND delta = 'test_cache'")->fetchField();
$this->assertEqual($current_caching, DRUPAL_NO_CACHE, t("Test block's database entry updated to DRUPAL_NO_CACHE."));
$this->assertEqual($current_caching, DRUPAL_NO_CACHE, "Test block's database entry updated to DRUPAL_NO_CACHE.");
}
}
@@ -427,7 +427,7 @@ class NewDefaultThemeBlocks extends DrupalWebTestCase {
$themes['admin'] = $admin_theme;
}
$count = db_query_range('SELECT 1 FROM {block} WHERE theme NOT IN (:themes)', 0, 1, array(':themes' => $themes))->fetchField();
$this->assertFalse($count, t('Only the default theme and the admin theme have blocks.'));
$this->assertFalse($count, 'Only the default theme and the admin theme have blocks.');
// Populate list of all blocks for matching against new theme.
$blocks = array();
@@ -445,7 +445,7 @@ class NewDefaultThemeBlocks extends DrupalWebTestCase {
$result = db_query('SELECT * FROM {block} WHERE theme = :theme', array(':theme' => 'stark'));
foreach ($result as $block) {
unset($block->theme, $block->bid);
$this->assertEqual($blocks[$block->module][$block->delta], $block, t('Block %name matched', array('%name' => $block->module . '-' . $block->delta)));
$this->assertEqual($blocks[$block->module][$block->delta], $block, format_string('Block %name matched', array('%name' => $block->module . '-' . $block->delta)));
}
}
}
@@ -472,13 +472,13 @@ class BlockAdminThemeTestCase extends DrupalWebTestCase {
// Ensure that access to block admin page is denied when theme is disabled.
$this->drupalGet('admin/structure/block/list/stark');
$this->assertResponse(403, t('The block admin page for a disabled theme can not be accessed'));
$this->assertResponse(403, 'The block admin page for a disabled theme can not be accessed');
// Enable admin theme and confirm that tab is accessible.
$edit['admin_theme'] = 'stark';
$this->drupalPost('admin/appearance', $edit, t('Save configuration'));
$this->drupalGet('admin/structure/block/list/stark');
$this->assertResponse(200, t('The block admin page for the admin theme can be accessed'));
$this->assertResponse(200, 'The block admin page for the admin theme can be accessed');
}
}
@@ -532,20 +532,20 @@ class BlockCacheTestCase extends DrupalWebTestCase {
variable_set('block_test_content', $current_content);
$this->drupalLogin($this->normal_user);
$this->drupalGet('');
$this->assertText($current_content, t('Block content displays.'));
$this->assertText($current_content, 'Block content displays.');
// Change the content, but the cached copy should still be served.
$old_content = $current_content;
$current_content = $this->randomName();
variable_set('block_test_content', $current_content);
$this->drupalGet('');
$this->assertText($old_content, t('Block is served from the cache.'));
$this->assertText($old_content, 'Block is served from the cache.');
// Clear the cache and verify that the stale data is no longer there.
cache_clear_all();
$this->drupalGet('');
$this->assertNoText($old_content, t('Block cache clear removes stale cache data.'));
$this->assertText($current_content, t('Fresh block content is displayed after clearing the cache.'));
$this->assertNoText($old_content, 'Block cache clear removes stale cache data.');
$this->assertText($current_content, 'Fresh block content is displayed after clearing the cache.');
// Test whether the cached data is served for the correct users.
$old_content = $current_content;
@@ -553,19 +553,19 @@ class BlockCacheTestCase extends DrupalWebTestCase {
variable_set('block_test_content', $current_content);
$this->drupalLogout();
$this->drupalGet('');
$this->assertNoText($old_content, t('Anonymous user does not see content cached per-role for normal user.'));
$this->assertNoText($old_content, 'Anonymous user does not see content cached per-role for normal user.');
$this->drupalLogin($this->normal_user_alt);
$this->drupalGet('');
$this->assertText($old_content, t('User with the same roles sees per-role cached content.'));
$this->assertText($old_content, 'User with the same roles sees per-role cached content.');
$this->drupalLogin($this->admin_user);
$this->drupalGet('');
$this->assertNoText($old_content, t('Admin user does not see content cached per-role for normal user.'));
$this->assertNoText($old_content, 'Admin user does not see content cached per-role for normal user.');
$this->drupalLogin($this->normal_user);
$this->drupalGet('');
$this->assertText($old_content, t('Block is served from the per-role cache.'));
$this->assertText($old_content, 'Block is served from the per-role cache.');
}
/**
@@ -577,7 +577,7 @@ class BlockCacheTestCase extends DrupalWebTestCase {
variable_set('block_test_content', $current_content);
$this->drupalGet('');
$this->assertText($current_content, t('Block content displays.'));
$this->assertText($current_content, 'Block content displays.');
$old_content = $current_content;
$current_content = $this->randomName();
@@ -585,7 +585,7 @@ class BlockCacheTestCase extends DrupalWebTestCase {
$this->drupalLogout();
$this->drupalGet('user');
$this->assertText($old_content, t('Block content served from global cache.'));
$this->assertText($old_content, 'Block content served from global cache.');
}
/**
@@ -598,13 +598,13 @@ class BlockCacheTestCase extends DrupalWebTestCase {
// If DRUPAL_NO_CACHE has no effect, the next request would be cached.
$this->drupalGet('');
$this->assertText($current_content, t('Block content displays.'));
$this->assertText($current_content, 'Block content displays.');
// A cached copy should not be served.
$current_content = $this->randomName();
variable_set('block_test_content', $current_content);
$this->drupalGet('');
$this->assertText($current_content, t('DRUPAL_NO_CACHE prevents blocks from being cached.'));
$this->assertText($current_content, 'DRUPAL_NO_CACHE prevents blocks from being cached.');
}
/**
@@ -617,22 +617,22 @@ class BlockCacheTestCase extends DrupalWebTestCase {
$this->drupalLogin($this->normal_user);
$this->drupalGet('');
$this->assertText($current_content, t('Block content displays.'));
$this->assertText($current_content, 'Block content displays.');
$old_content = $current_content;
$current_content = $this->randomName();
variable_set('block_test_content', $current_content);
$this->drupalGet('');
$this->assertText($old_content, t('Block is served from per-user cache.'));
$this->assertText($old_content, 'Block is served from per-user cache.');
$this->drupalLogin($this->normal_user_alt);
$this->drupalGet('');
$this->assertText($current_content, t('Per-user block cache is not served for other users.'));
$this->assertText($current_content, 'Per-user block cache is not served for other users.');
$this->drupalLogin($this->normal_user);
$this->drupalGet('');
$this->assertText($old_content, t('Per-user block cache is persistent.'));
$this->assertText($old_content, 'Per-user block cache is persistent.');
}
/**
@@ -644,16 +644,16 @@ class BlockCacheTestCase extends DrupalWebTestCase {
variable_set('block_test_content', $current_content);
$this->drupalGet('node');
$this->assertText($current_content, t('Block content displays on the node page.'));
$this->assertText($current_content, 'Block content displays on the node page.');
$old_content = $current_content;
$current_content = $this->randomName();
variable_set('block_test_content', $current_content);
$this->drupalGet('user');
$this->assertNoText($old_content, t('Block content cached for the node page does not show up for the user page.'));
$this->assertNoText($old_content, 'Block content cached for the node page does not show up for the user page.');
$this->drupalGet('node');
$this->assertText($old_content, t('Block content cached for the node page.'));
$this->assertText($old_content, 'Block content cached for the node page.');
}
/**
@@ -706,7 +706,7 @@ class BlockHTMLIdTestCase extends DrupalWebTestCase {
*/
function testHTMLId() {
$this->drupalGet('');
$this->assertRaw('block-block-test-test-html-id', t('HTML id for test block is valid.'));
$this->assertRaw('block-block-test-test-html-id', 'HTML id for test block is valid.');
}
}
@@ -736,7 +736,7 @@ class BlockTemplateSuggestionsUnitTest extends DrupalUnitTestCase {
$variables1['elements']['#block'] = $block1;
$variables1['elements']['#children'] = '';
template_preprocess_block($variables1);
$this->assertEqual($variables1['theme_hook_suggestions'], array('block__footer', 'block__block', 'block__block__underscore_test'), t('Found expected block suggestions for delta with underscore'));
$this->assertEqual($variables1['theme_hook_suggestions'], array('block__footer', 'block__block', 'block__block__underscore_test'), 'Found expected block suggestions for delta with underscore');
// Define block delta with hyphens to be preprocessed. Hyphens should be
// replaced with underscores.
@@ -748,7 +748,7 @@ class BlockTemplateSuggestionsUnitTest extends DrupalUnitTestCase {
$variables2['elements']['#block'] = $block2;
$variables2['elements']['#children'] = '';
template_preprocess_block($variables2);
$this->assertEqual($variables2['theme_hook_suggestions'], array('block__footer', 'block__block', 'block__block__hyphen_test'), t('Hyphens (-) in block delta were replaced by underscore (_)'));
$this->assertEqual($variables2['theme_hook_suggestions'], array('block__footer', 'block__block', 'block__block__hyphen_test'), 'Hyphens (-) in block delta were replaced by underscore (_)');
}
}
@@ -784,11 +784,11 @@ class BlockHiddenRegionTestCase extends DrupalWebTestCase {
// Ensure that "block_test_theme" is set as the default theme.
$this->drupalGet('admin/structure/block');
$this->assertText('Block test theme(' . t('active tab') . ')', t('Default local task on blocks admin page is the block test theme.'));
$this->assertText('Block test theme(' . t('active tab') . ')', 'Default local task on blocks admin page is the block test theme.');
// Ensure that the search form block is displayed.
$this->drupalGet('');
$this->assertText('Search form', t('Block was displayed on the front page.'));
$this->assertText('Search form', 'Block was displayed on the front page.');
}
}
+3 -3
View File
@@ -5,8 +5,8 @@ version = VERSION
core = 7.x
hidden = TRUE
; Information added by drupal.org packaging script on 2012-08-01
version = "7.15"
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
project = "drupal"
datestamp = "1343839327"
datestamp = "1365027012"
@@ -13,8 +13,8 @@ regions[footer] = Footer
regions[highlighted] = Highlighted
regions[help] = Help
; Information added by drupal.org packaging script on 2012-08-01
version = "7.15"
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
project = "drupal"
datestamp = "1343839327"
datestamp = "1365027012"
+3 -3
View File
@@ -5,8 +5,8 @@ version = VERSION
core = 7.x
files[] = blog.test
; Information added by drupal.org packaging script on 2012-08-01
version = "7.15"
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
project = "drupal"
datestamp = "1343839327"
datestamp = "1365027012"
+4
View File
@@ -1,3 +1,7 @@
/**
* @file
* Right-to-Left styling for the Book module.
*/
.book-navigation .menu {
padding: 1em 3em 0 0;
+12 -5
View File
@@ -2,11 +2,16 @@
/**
* @file
* Admin page callbacks for the book module.
* Administration page callbacks for the Book module.
*/
/**
* Returns an administrative overview of all books.
*
* @return string
* A HTML-formatted string with the administrative page content.
*
* @see book_menu()
*/
function book_admin_overview() {
$rows = array();
@@ -53,6 +58,8 @@ function book_admin_settings() {
/**
* Form validation handler for book_admin_settings().
*
* @see book_admin_settings_submit()
*/
function book_admin_settings_validate($form, &$form_state) {
$child_type = $form_state['values']['book_child_type'];
@@ -149,7 +156,7 @@ function book_admin_edit_submit($form, &$form_state) {
* @param $node
* The node of the top-level page in the book.
* @param $form
* The form that is being modified.
* The form that is being modified, passed by reference.
*
* @see book_admin_edit()
*/
@@ -184,10 +191,10 @@ function _book_admin_table($node, &$form) {
* @param $tree
* A subtree of the book menu hierarchy.
* @param $form
* The form that is being modified.
* The form that is being modified, passed by reference.
*
* @return
* The form that is being modified.
* The modified form array.
*
* @see book_admin_edit()
*/
@@ -278,5 +285,5 @@ function theme_book_admin_table($variables) {
$rows[] = $row;
}
return theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'book-outline')));
return theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'book-outline'), 'empty' => t('No book content available.')));
}
+4
View File
@@ -1,3 +1,7 @@
/**
* @file
* Styling for the Book module.
*/
.book-navigation .menu {
border-top: 1px solid #888;
+3 -3
View File
@@ -7,8 +7,8 @@ files[] = book.test
configure = admin/content/book/settings
stylesheets[all][] = book.css
; Information added by drupal.org packaging script on 2012-08-01
version = "7.15"
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
project = "drupal"
datestamp = "1343839327"
datestamp = "1365027012"
+5
View File
@@ -1,3 +1,8 @@
/**
* @file
* Javascript behaviors for the Book module.
*/
(function ($) {
Drupal.behaviors.bookFieldsetSummaries = {
+31 -16
View File
@@ -221,6 +221,9 @@ function _book_outline_remove_access($node) {
*
* A node can be removed from a book if it is actually in a book and it either
* is not a top-level page or is a top-level page with no children.
*
* @param $node
* The node to remove from the outline.
*/
function _book_node_is_removable($node) {
return (!empty($node->book['bid']) && (($node->book['bid'] != $node->nid) || !$node->book['has_children']));
@@ -734,7 +737,7 @@ function book_get_flat_menu($book_link) {
* @param $tree
* A tree of menu links in an array.
* @param $flat
* A flat array of the menu links from $tree.
* A flat array of the menu links from $tree, passed by reference.
*
* @see book_get_flat_menu().
*/
@@ -1062,8 +1065,9 @@ function _book_link_defaults($nid) {
* to the structured data but can also simply iterate over all elements and
* render them (as in the default template).
*
* The $variables array contains the following elements:
* - book_menus
* @param $variables
* An associative array containing the following key:
* - book_menus
*
* @see book-all-books-block.tpl.php
*/
@@ -1079,8 +1083,9 @@ function template_preprocess_book_all_books_block(&$variables) {
/**
* Processes variables for book-navigation.tpl.php.
*
* The $variables array contains the following elements:
* - book_link
* @param $variables
* An associative array containing the following key:
* - book_link
*
* @see book-navigation.tpl.php
*/
@@ -1151,8 +1156,9 @@ function template_preprocess_book_navigation(&$variables) {
* Reference to the table of contents array. This is modified in place, so the
* function does not have a return value.
* @param $exclude
* Optional array of menu link ID values. Any link whose menu link ID is in
* this array will be excluded (along with its children).
* (optional) An array of menu link ID values. Any link whose menu link ID is
* in this array will be excluded (along with its children). Defaults to an
* empty array.
* @param $depth_limit
* Any link deeper than this value will be excluded (along with its children).
*/
@@ -1198,10 +1204,11 @@ function book_toc($bid, $depth_limit, $exclude = array()) {
/**
* Processes variables for book-export-html.tpl.php.
*
* The $variables array contains the following elements:
* - title
* - contents
* - depth
* @param $variables
* An associative array containing the following keys:
* - title
* - contents
* - depth
*
* @see book-export-html.tpl.php
*/
@@ -1261,7 +1268,8 @@ function book_export_traverse($tree, $visit_func) {
* @param $node
* The node that will be output.
* @param $children
* All the rendered child nodes within the current node.
* (optional) All the rendered child nodes within the current node. Defaults
* to an empty string.
*
* @return
* The HTML generated for the given node.
@@ -1280,9 +1288,10 @@ function book_node_export($node, $children = '') {
/**
* Processes variables for book-node-export-html.tpl.php.
*
* The $variables array contains the following elements:
* - node
* - children
* @param $variables
* An associative array containing the following keys:
* - node
* - children
*
* @see book-node-export-html.tpl.php
*/
@@ -1294,6 +1303,12 @@ function template_preprocess_book_node_export_html(&$variables) {
/**
* Determine if a given node type is in the list of types allowed for books.
*
* @param $type
* A node type.
*
* @return
* A Boolean TRUE if the node type can be included in books; otherwise, FALSE.
*/
function book_type_is_allowed($type) {
return in_array($type, variable_get('book_allowed_types', array('book')));
@@ -1336,7 +1351,7 @@ function book_node_type_update($type) {
*
* @return
* A menu link, with the link translated for rendering and data added from the
* {book} table.
* {book} table. FALSE if there is an error.
*/
function book_link_load($mlid) {
if ($item = db_query("SELECT * FROM {menu_links} ml INNER JOIN {book} b ON b.mlid = ml.mlid LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.mlid = :mlid", array(
+21 -1
View File
@@ -7,6 +7,11 @@
/**
* Menu callback: Prints a listing of all books.
*
* @return string
* A HTML-formatted string with the listing of all books content.
*
* @see book_menu()
*/
function book_render() {
$book_list = array();
@@ -36,8 +41,19 @@ function book_render() {
* @return
* A string representing the node and its children in the book hierarchy in a
* format determined by the $type parameter.
*
* @see book_menu()
*/
function book_export($type, $nid) {
// Check that the node exists and that the current user has access to it.
$node = node_load($nid);
if (!$node) {
return MENU_NOT_FOUND;
}
if (!node_access('view', $node)) {
return MENU_ACCESS_DENIED;
}
$type = drupal_strtolower($type);
$export_function = 'book_export_' . $type;
@@ -70,7 +86,6 @@ function book_export($type, $nid) {
*/
function book_export_html($nid) {
if (user_access('access printer-friendly version')) {
$export_data = array();
$node = node_load($nid);
if (isset($node->book)) {
$tree = book_menu_subtree_data($node->book);
@@ -91,6 +106,11 @@ function book_export_html($nid) {
*
* @param $node
* The book node for which to show the outline.
*
* @return string
* A HTML-formatted string with the outline form for a single node.
*
* @see book_menu()
*/
function book_outline($node) {
drupal_set_title($node->title);
+83 -45
View File
@@ -5,14 +5,37 @@
* Tests for book.module.
*/
/**
* Tests the functionality of the Book module.
*/
class BookTestCase extends DrupalWebTestCase {
/**
* A book node.
*
* @var object
*/
protected $book;
// $book_author is a user with permission to create and edit books.
/**
* A user with permission to create and edit books.
*
* @var object
*/
protected $book_author;
// $web_user is a user with permission to view a book
// and access the printer-friendly version.
/**
* A user with permission to view a book and access printer-friendly version.
*
* @var object
*/
protected $web_user;
// $admin_user is a user with permission to create and edit books and to administer blocks.
/**
* A user with permission to create and edit books and to administer blocks.
*
* @var object
*/
protected $admin_user;
public static function getInfo() {
@@ -36,7 +59,7 @@ class BookTestCase extends DrupalWebTestCase {
}
/**
* Create a new book with a page hierarchy.
* Creates a new book with a page hierarchy.
*/
function createBook() {
// Create new book.
@@ -67,7 +90,7 @@ class BookTestCase extends DrupalWebTestCase {
}
/**
* Test book functionality through node interfaces.
* Tests book functionality through node interfaces.
*/
function testBook() {
// Create new book.
@@ -106,18 +129,20 @@ class BookTestCase extends DrupalWebTestCase {
}
/**
* Check the outline of sub-pages; previous, up, and next; and printer friendly version.
* Checks the outline of sub-pages; previous, up, and next.
*
* Also checks the printer friendly version of the outline.
*
* @param $node
* Node to check.
* @param $nodes
* Nodes that should be in outline.
* @param $previous
* Previous link node.
* (optional) Previous link node. Defaults to FALSE.
* @param $up
* Up link node.
* (optional) Up link node. Defaults to FALSE.
* @param $next
* Next link node.
* (optional) Next link node. Defaults to FALSE.
* @param $breadcrumb
* The nodes that should be displayed in the breadcrumb.
*/
@@ -129,23 +154,23 @@ class BookTestCase extends DrupalWebTestCase {
// Check outline structure.
if ($nodes !== NULL) {
$this->assertPattern($this->generateOutlinePattern($nodes), t('Node ' . $number . ' outline confirmed.'));
$this->assertPattern($this->generateOutlinePattern($nodes), format_string('Node %number outline confirmed.', array('%number' => $number)));
}
else {
$this->pass(t('Node ' . $number . ' doesn\'t have outline.'));
$this->pass(format_string('Node %number does not have outline.', array('%number' => $number)));
}
// Check previous, up, and next links.
if ($previous) {
$this->assertRaw(l(' ' . $previous->title, 'node/' . $previous->nid, array('attributes' => array('class' => array('page-previous'), 'title' => t('Go to previous page')))), t('Previous page link found.'));
$this->assertRaw(l(' ' . $previous->title, 'node/' . $previous->nid, array('attributes' => array('class' => array('page-previous'), 'title' => t('Go to previous page')))), 'Previous page link found.');
}
if ($up) {
$this->assertRaw(l('up', 'node/' . $up->nid, array('attributes' => array('class' => array('page-up'), 'title' => t('Go to parent page')))), t('Up page link found.'));
$this->assertRaw(l('up', 'node/' . $up->nid, array('attributes' => array('class' => array('page-up'), 'title' => t('Go to parent page')))), 'Up page link found.');
}
if ($next) {
$this->assertRaw(l($next->title . ' ', 'node/' . $next->nid, array('attributes' => array('class' => array('page-next'), 'title' => t('Go to next page')))), t('Next page link found.'));
$this->assertRaw(l($next->title . ' ', 'node/' . $next->nid, array('attributes' => array('class' => array('page-next'), 'title' => t('Go to next page')))), 'Next page link found.');
}
// Compute the expected breadcrumb.
@@ -163,20 +188,24 @@ class BookTestCase extends DrupalWebTestCase {
}
// Compare expected and got breadcrumbs.
$this->assertIdentical($expected_breadcrumb, $got_breadcrumb, t('The breadcrumb is correctly displayed on the page.'));
$this->assertIdentical($expected_breadcrumb, $got_breadcrumb, 'The breadcrumb is correctly displayed on the page.');
// Check printer friendly version.
$this->drupalGet('book/export/html/' . $node->nid);
$this->assertText($node->title, t('Printer friendly title found.'));
$this->assertRaw(check_markup($node->body[LANGUAGE_NONE][0]['value'], $node->body[LANGUAGE_NONE][0]['format']), t('Printer friendly body found.'));
$this->assertText($node->title, 'Printer friendly title found.');
$this->assertRaw(check_markup($node->body[LANGUAGE_NONE][0]['value'], $node->body[LANGUAGE_NONE][0]['format']), 'Printer friendly body found.');
$number++;
}
/**
* Create a regular expression to check for the sub-nodes in the outline.
* Creates a regular expression to check for the sub-nodes in the outline.
*
* @param array $nodes Nodes to check in outline.
* @param array $nodes
* An array of nodes to check in outline.
*
* @return
* A regular expression that locates sub-nodes of the outline.
*/
function generateOutlinePattern($nodes) {
$outline = '';
@@ -188,10 +217,12 @@ class BookTestCase extends DrupalWebTestCase {
}
/**
* Create book node.
* Creates a book node.
*
* @param integer $book_nid Book node id or set to 'new' to create new book.
* @param integer $parent Parent book reference id.
* @param $book_nid
* A book node ID or set to 'new' to create a new book.
* @param $parent
* (optional) Parent book reference ID. Defaults to NULL.
*/
function createBookNode($book_nid, $parent = NULL) {
// $number does not use drupal_static as it should not be reset
@@ -216,7 +247,7 @@ class BookTestCase extends DrupalWebTestCase {
// Check to make sure the book node was created.
$node = $this->drupalGetNodeByTitle($edit['title']);
$this->assertNotNull(($node === FALSE ? NULL : $node), t('Book node found in database.'));
$this->assertNotNull(($node === FALSE ? NULL : $node), 'Book node found in database.');
$number++;
return $node;
@@ -236,28 +267,35 @@ class BookTestCase extends DrupalWebTestCase {
// Make sure each part of the book is there.
foreach ($nodes as $node) {
$this->assertText($node->title, t('Node title found in printer friendly version.'));
$this->assertRaw(check_markup($node->body[LANGUAGE_NONE][0]['value'], $node->body[LANGUAGE_NONE][0]['format']), t('Node body found in printer friendly version.'));
$this->assertText($node->title, 'Node title found in printer friendly version.');
$this->assertRaw(check_markup($node->body[LANGUAGE_NONE][0]['value'], $node->body[LANGUAGE_NONE][0]['format']), 'Node body found in printer friendly version.');
}
// Make sure we can't export an unsupported format.
$this->drupalGet('book/export/foobar/' . $this->book->nid);
$this->assertResponse('404', t('Unsupported export format returned "not found".'));
$this->assertResponse('404', 'Unsupported export format returned "not found".');
// Make sure we get a 404 on a not existing book node.
$this->drupalGet('book/export/html/123');
$this->assertResponse('404', t('Not existing book node returned "not found".'));
$this->assertResponse('404', 'Not existing book node returned "not found".');
// Make sure an anonymous user cannot view printer-friendly version.
$this->drupalLogout();
// Load the book and verify there is no printer-friendly version link.
$this->drupalGet('node/' . $this->book->nid);
$this->assertNoLink(t('Printer-friendly version'), t('Anonymous user is not shown link to printer-friendly version.'));
$this->assertNoLink(t('Printer-friendly version'), 'Anonymous user is not shown link to printer-friendly version.');
// Try getting the URL directly, and verify it fails.
$this->drupalGet('book/export/html/' . $this->book->nid);
$this->assertResponse('403', t('Anonymous user properly forbidden.'));
$this->assertResponse('403', 'Anonymous user properly forbidden.');
// Now grant anonymous users permission to view the printer-friendly
// version and verify that node access restrictions still prevent them from
// seeing it.
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access printer-friendly version'));
$this->drupalGet('book/export/html/' . $this->book->nid);
$this->assertResponse('403', 'Anonymous user properly forbidden from seeing the printer-friendly version when denied by node access.');
}
/**
@@ -269,30 +307,30 @@ class BookTestCase extends DrupalWebTestCase {
// Set block title to confirm that the interface is available.
$block_title = $this->randomName(16);
$this->drupalPost('admin/structure/block/manage/book/navigation/configure', array('title' => $block_title), t('Save block'));
$this->assertText(t('The block configuration has been saved.'), t('Block configuration set.'));
$this->assertText(t('The block configuration has been saved.'), 'Block configuration set.');
// Set the block to a region to confirm block is available.
$edit = array();
$edit['blocks[book_navigation][region]'] = 'footer';
$this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
$this->assertText(t('The block settings have been updated.'), t('Block successfully move to footer region.'));
$this->assertText(t('The block settings have been updated.'), 'Block successfully move to footer region.');
// Give anonymous users the permission 'node test view'.
$edit = array();
$edit[DRUPAL_ANONYMOUS_RID . '[node test view]'] = TRUE;
$this->drupalPost('admin/people/permissions/' . DRUPAL_ANONYMOUS_RID, $edit, t('Save permissions'));
$this->assertText(t('The changes have been saved.'), t("Permission 'node test view' successfully assigned to anonymous users."));
$this->assertText(t('The changes have been saved.'), "Permission 'node test view' successfully assigned to anonymous users.");
// Test correct display of the block.
$nodes = $this->createBook();
$this->drupalGet('<front>');
$this->assertText($block_title, t('Book navigation block is displayed.'));
$this->assertText($this->book->title, t('Link to book root (@title) is displayed.', array('@title' => $nodes[0]->title)));
$this->assertNoText($nodes[0]->title, t('No links to individual book pages are displayed.'));
$this->assertText($block_title, 'Book navigation block is displayed.');
$this->assertText($this->book->title, format_string('Link to book root (@title) is displayed.', array('@title' => $nodes[0]->title)));
$this->assertNoText($nodes[0]->title, 'No links to individual book pages are displayed.');
}
/**
* Test the book navigation block when an access module is enabled.
* Tests the book navigation block when an access module is enabled.
*/
function testNavigationBlockOnAccessModuleEnabled() {
$this->drupalLogin($this->admin_user);
@@ -305,19 +343,19 @@ class BookTestCase extends DrupalWebTestCase {
// Set block display to 'Show block only on book pages'.
$edit['book_block_mode'] = 'book pages';
$this->drupalPost('admin/structure/block/manage/book/navigation/configure', $edit, t('Save block'));
$this->assertText(t('The block configuration has been saved.'), t('Block configuration set.'));
$this->assertText(t('The block configuration has been saved.'), 'Block configuration set.');
// Set the block to a region to confirm block is available.
$edit = array();
$edit['blocks[book_navigation][region]'] = 'footer';
$this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
$this->assertText(t('The block settings have been updated.'), t('Block successfully move to footer region.'));
$this->assertText(t('The block settings have been updated.'), 'Block successfully move to footer region.');
// Give anonymous users the permission 'node test view'.
$edit = array();
$edit[DRUPAL_ANONYMOUS_RID . '[node test view]'] = TRUE;
$this->drupalPost('admin/people/permissions/' . DRUPAL_ANONYMOUS_RID, $edit, t('Save permissions'));
$this->assertText(t('The changes have been saved.'), t('Permission \'node test view\' successfully assigned to anonymous users.'));
$this->assertText(t('The changes have been saved.'), "Permission 'node test view' successfully assigned to anonymous users.");
// Create a book.
$this->createBook();
@@ -325,12 +363,12 @@ class BookTestCase extends DrupalWebTestCase {
// Test correct display of the block to registered users.
$this->drupalLogin($this->web_user);
$this->drupalGet('node/' . $this->book->nid);
$this->assertText($block_title, t('Book navigation block is displayed to registered users.'));
$this->assertText($block_title, 'Book navigation block is displayed to registered users.');
$this->drupalLogout();
// Test correct display of the block to anonymous users.
$this->drupalGet('node/' . $this->book->nid);
$this->assertText($block_title, t('Book navigation block is displayed to anonymous users.'));
$this->assertText($block_title, 'Book navigation block is displayed to anonymous users.');
}
/**
@@ -343,10 +381,10 @@ class BookTestCase extends DrupalWebTestCase {
// Test access to delete top-level and child book nodes.
$this->drupalGet('node/' . $this->book->nid . '/outline/remove');
$this->assertResponse('403', t('Deleting top-level book node properly forbidden.'));
$this->assertResponse('403', 'Deleting top-level book node properly forbidden.');
$this->drupalPost('node/' . $nodes[4]->nid . '/outline/remove', $edit, t('Remove'));
$node4 = node_load($nodes[4]->nid, NULL, TRUE);
$this->assertTrue(empty($node4->book), t('Deleting child book node properly allowed.'));
$this->assertTrue(empty($node4->book), 'Deleting child book node properly allowed.');
// Delete all child book nodes and retest top-level node deletion.
foreach ($nodes as $node) {
@@ -355,6 +393,6 @@ class BookTestCase extends DrupalWebTestCase {
node_delete_multiple($nids);
$this->drupalPost('node/' . $this->book->nid . '/outline/remove', $edit, t('Remove'));
$node = node_load($this->book->nid, NULL, TRUE);
$this->assertTrue(empty($node->book), t('Deleting childless top-level book node properly allowed.'));
$this->assertTrue(empty($node->book), 'Deleting childless top-level book node properly allowed.');
}
}
+3 -3
View File
@@ -5,8 +5,8 @@ version = VERSION
core = 7.x
files[] = color.test
; Information added by drupal.org packaging script on 2012-08-01
version = "7.15"
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
project = "drupal"
datestamp = "1343839327"
datestamp = "1365027012"
+2 -1
View File
@@ -32,7 +32,8 @@
* into a string within the variable $classes.
*
* @see template_preprocess_comment_wrapper()
* @see theme_comment_wrapper()
*
* @ingroup themeable
*/
?>
<div id="comments" class="<?php print $classes; ?>"<?php print $attributes; ?>>
+2 -1
View File
@@ -98,13 +98,14 @@ function comment_admin_overview($form, &$form_state, $arg) {
// Remove the first node title from the node_titles array and attach to
// the comment.
$comment->node_title = array_shift($node_titles);
$comment_body = field_get_items('comment', $comment, 'comment_body');
$options[$comment->cid] = array(
'subject' => array(
'data' => array(
'#type' => 'link',
'#title' => $comment->subject,
'#href' => 'comment/' . $comment->cid,
'#options' => array('attributes' => array('title' => truncate_utf8($comment->comment_body[LANGUAGE_NONE][0]['value'], 128)), 'fragment' => 'comment-' . $comment->cid),
'#options' => array('attributes' => array('title' => truncate_utf8($comment_body[0]['value'], 128)), 'fragment' => 'comment-' . $comment->cid),
),
),
'author' => theme('username', array('account' => $comment)),
+3 -3
View File
@@ -9,8 +9,8 @@ files[] = comment.test
configure = admin/content/comment
stylesheets[all][] = comment.css
; Information added by drupal.org packaging script on 2012-08-01
version = "7.15"
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
project = "drupal"
datestamp = "1343839327"
datestamp = "1365027012"
+29 -6
View File
@@ -152,7 +152,7 @@ function comment_node_type_load($name) {
}
/**
* Entity uri callback.
* Entity URI callback.
*/
function comment_uri($comment) {
return array(
@@ -992,6 +992,14 @@ function comment_build_content($comment, $node, $view_mode = 'full', $langcode =
// Remove previously built content, if exists.
$comment->content = array();
// Allow modules to change the view mode.
$context = array(
'entity_type' => 'comment',
'entity' => $comment,
'langcode' => $langcode,
);
drupal_alter('entity_view_mode', $view_mode, $context);
// Build fields content.
field_attach_prepare_view('comment', array($comment->cid => $comment), $view_mode, $langcode);
entity_prepare_view('comment', array($comment->cid => $comment), $langcode);
@@ -1013,6 +1021,10 @@ function comment_build_content($comment, $node, $view_mode = 'full', $langcode =
// Allow modules to make their own additions to the comment.
module_invoke_all('comment_view', $comment, $view_mode, $langcode);
module_invoke_all('entity_view', $comment, 'comment', $view_mode, $langcode);
// Make sure the current view mode is stored if no module has already
// populated the related key.
$comment->content += array('#view_mode' => $view_mode);
}
/**
@@ -2029,7 +2041,8 @@ function comment_form($form, &$form_state, $comment) {
// Attach fields.
$comment->node_type = 'comment_node_' . $node->type;
field_attach_form('comment', $comment, $form, $form_state);
$langcode = entity_language('comment', $comment);
field_attach_form('comment', $comment, $form, $form_state, $langcode);
return $form;
}
@@ -2054,7 +2067,8 @@ function comment_preview($comment) {
$node = node_load($comment->nid);
if (!form_get_errors()) {
$comment->format = $comment->comment_body[LANGUAGE_NONE][0]['format'];
$comment_body = field_get_items('comment', $comment, 'comment_body');
$comment->format = $comment_body[0]['format'];
// Attach the user and time information.
if (!empty($comment->name)) {
$account = user_load_by_name($comment->name);
@@ -2178,7 +2192,9 @@ function comment_submit($comment) {
// 1) Filter it into HTML
// 2) Strip out all HTML tags
// 3) Convert entities back to plain-text.
$comment_body = $comment->comment_body[LANGUAGE_NONE][0];
$field = field_info_field('comment_body');
$langcode = field_is_translatable('comment', $field) ? entity_language('comment', $comment) : LANGUAGE_NONE;
$comment_body = $comment->comment_body[$langcode][0];
if (isset($comment_body['format'])) {
$comment_text = check_markup($comment_body['value'], $comment_body['format']);
}
@@ -2272,8 +2288,16 @@ function template_preprocess_comment(&$variables) {
$variables['comment'] = $comment;
$variables['node'] = $node;
$variables['author'] = theme('username', array('account' => $comment));
$variables['created'] = format_date($comment->created);
$variables['changed'] = format_date($comment->changed);
// Avoid calling format_date() twice on the same timestamp.
if ($comment->changed == $comment->created) {
$variables['changed'] = $variables['created'];
}
else {
$variables['changed'] = format_date($comment->changed);
}
$variables['new'] = !empty($comment->new) ? t('new') : '';
$variables['picture'] = theme_get_setting('toggle_comment_user_picture') ? theme('user_picture', array('account' => $comment)) : '';
@@ -2375,7 +2399,6 @@ function theme_comment_post_forbidden($variables) {
* Process variables for comment-wrapper.tpl.php.
*
* @see comment-wrapper.tpl.php
* @see theme_comment_wrapper()
*/
function template_preprocess_comment_wrapper(&$variables) {
// Provide contextual information.
+187 -185
View File
@@ -1,7 +1,7 @@
<?php
/**
* @file
* @file
* Tests for comment.module.
*/
@@ -48,7 +48,7 @@ class CommentHelperCase extends DrupalWebTestCase {
$edit['subject'] = $subject;
}
else {
$this->assertNoFieldByName('subject', '', t('Subject field not found.'));
$this->assertNoFieldByName('subject', '', 'Subject field not found.');
}
if ($contact !== NULL && is_array($contact)) {
@@ -57,19 +57,19 @@ class CommentHelperCase extends DrupalWebTestCase {
switch ($preview_mode) {
case DRUPAL_REQUIRED:
// Preview required so no save button should be found.
$this->assertNoFieldByName('op', t('Save'), t('Save button not found.'));
$this->assertNoFieldByName('op', t('Save'), 'Save button not found.');
$this->drupalPost(NULL, $edit, t('Preview'));
// Don't break here so that we can test post-preview field presence and
// function below.
case DRUPAL_OPTIONAL:
$this->assertFieldByName('op', t('Preview'), t('Preview button found.'));
$this->assertFieldByName('op', t('Save'), t('Save button found.'));
$this->assertFieldByName('op', t('Preview'), 'Preview button found.');
$this->assertFieldByName('op', t('Save'), 'Save button found.');
$this->drupalPost(NULL, $edit, t('Save'));
break;
case DRUPAL_DISABLED:
$this->assertNoFieldByName('op', t('Preview'), t('Preview button not found.'));
$this->assertFieldByName('op', t('Save'), t('Save button found.'));
$this->assertNoFieldByName('op', t('Preview'), 'Preview button not found.');
$this->assertFieldByName('op', t('Save'), 'Save button found.');
$this->drupalPost(NULL, $edit, t('Save'));
break;
}
@@ -83,7 +83,7 @@ class CommentHelperCase extends DrupalWebTestCase {
$this->assertText($subject, 'Comment subject posted.');
}
$this->assertText($comment, 'Comment body posted.');
$this->assertTrue((!empty($match) && !empty($match[1])), t('Comment id found.'));
$this->assertTrue((!empty($match) && !empty($match[1])), 'Comment id found.');
}
if (isset($match[1])) {
@@ -122,7 +122,7 @@ class CommentHelperCase extends DrupalWebTestCase {
*/
function deleteComment($comment) {
$this->drupalPost('comment/' . $comment->id . '/delete', array(), t('Delete'));
$this->assertText(t('The comment and all its replies have been deleted.'), t('Comment deleted.'));
$this->assertText(t('The comment and all its replies have been deleted.'), 'Comment deleted.');
}
/**
@@ -200,7 +200,8 @@ class CommentHelperCase extends DrupalWebTestCase {
*/
function setCommentSettings($name, $value, $message) {
variable_set($name . '_article', $value);
$this->assertTrue(TRUE, t($message)); // Display status message.
// Display status message.
$this->assertTrue(TRUE, $message);
}
/**
@@ -230,10 +231,10 @@ class CommentHelperCase extends DrupalWebTestCase {
if ($operation == 'delete') {
$this->drupalPost(NULL, array(), t('Delete comments'));
$this->assertRaw(format_plural(1, 'Deleted 1 comment.', 'Deleted @count comments.'), t('Operation "' . $operation . '" was performed on comment.'));
$this->assertRaw(format_plural(1, 'Deleted 1 comment.', 'Deleted @count comments.'), format_string('Operation @operation was performed on comment.', array('@operation' => $operation)));
}
else {
$this->assertText(t('The update has been performed.'), t('Operation "' . $operation . '" was performed on comment.'));
$this->assertText(t('The update has been performed.'), format_string('Operation @operation was performed on comment.', array('@operation' => $operation)));
}
}
@@ -280,7 +281,7 @@ class CommentInterfaceTest extends CommentHelperCase {
$comment_text = $this->randomName();
$comment = $this->postComment($this->node, $comment_text);
$comment_loaded = comment_load($comment->id);
$this->assertTrue($this->commentExists($comment), t('Comment found.'));
$this->assertTrue($this->commentExists($comment), 'Comment found.');
// Set comments to have subject and preview to required.
$this->drupalLogout();
@@ -295,12 +296,12 @@ class CommentInterfaceTest extends CommentHelperCase {
$comment_text = $this->randomName();
$comment = $this->postComment($this->node, $comment_text, $subject_text, TRUE);
$comment_loaded = comment_load($comment->id);
$this->assertTrue($this->commentExists($comment), t('Comment found.'));
$this->assertTrue($this->commentExists($comment), 'Comment found.');
// Check comment display.
$this->drupalGet('node/' . $this->node->nid . '/' . $comment->id);
$this->assertText($subject_text, t('Individual comment subject found.'));
$this->assertText($comment_text, t('Individual comment body found.'));
$this->assertText($subject_text, 'Individual comment subject found.');
$this->assertText($comment_text, 'Individual comment body found.');
// Set comments to have subject and preview to optional.
$this->drupalLogout();
@@ -312,20 +313,20 @@ class CommentInterfaceTest extends CommentHelperCase {
$this->drupalGet('comment/' . $comment->id . '/edit');
$comment = $this->postComment(NULL, $comment->comment, $comment->subject, array('name' => ''));
$comment_loaded = comment_load($comment->id);
$this->assertTrue(empty($comment_loaded->name) && $comment_loaded->uid == 0, t('Comment author successfully changed to anonymous.'));
$this->assertTrue(empty($comment_loaded->name) && $comment_loaded->uid == 0, 'Comment author successfully changed to anonymous.');
// Test changing the comment author to an unverified user.
$random_name = $this->randomName();
$this->drupalGet('comment/' . $comment->id . '/edit');
$comment = $this->postComment(NULL, $comment->comment, $comment->subject, array('name' => $random_name));
$this->drupalGet('node/' . $this->node->nid);
$this->assertText($random_name . ' (' . t('not verified') . ')', t('Comment author successfully changed to an unverified user.'));
$this->assertText($random_name . ' (' . t('not verified') . ')', 'Comment author successfully changed to an unverified user.');
// Test changing the comment author to a verified user.
$this->drupalGet('comment/' . $comment->id . '/edit');
$comment = $this->postComment(NULL, $comment->comment, $comment->subject, array('name' => $this->web_user->name));
$comment_loaded = comment_load($comment->id);
$this->assertTrue($comment_loaded->name == $this->web_user->name && $comment_loaded->uid == $this->web_user->uid, t('Comment author successfully changed to a registered user.'));
$this->assertTrue($comment_loaded->name == $this->web_user->name && $comment_loaded->uid == $this->web_user->uid, 'Comment author successfully changed to a registered user.');
$this->drupalLogout();
@@ -333,60 +334,60 @@ class CommentInterfaceTest extends CommentHelperCase {
// subject though field enabled.
$this->drupalLogin($this->web_user);
$this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id);
$this->assertText($subject_text, t('Individual comment-reply subject found.'));
$this->assertText($comment_text, t('Individual comment-reply body found.'));
$this->assertText($subject_text, 'Individual comment-reply subject found.');
$this->assertText($comment_text, 'Individual comment-reply body found.');
$reply = $this->postComment(NULL, $this->randomName(), '', TRUE);
$reply_loaded = comment_load($reply->id);
$this->assertTrue($this->commentExists($reply, TRUE), t('Reply found.'));
$this->assertEqual($comment->id, $reply_loaded->pid, t('Pid of a reply to a comment is set correctly.'));
$this->assertEqual(rtrim($comment_loaded->thread, '/') . '.00/', $reply_loaded->thread, t('Thread of reply grows correctly.'));
$this->assertTrue($this->commentExists($reply, TRUE), 'Reply found.');
$this->assertEqual($comment->id, $reply_loaded->pid, 'Pid of a reply to a comment is set correctly.');
$this->assertEqual(rtrim($comment_loaded->thread, '/') . '.00/', $reply_loaded->thread, 'Thread of reply grows correctly.');
// Second reply to comment #3 creating comment #4.
$this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id);
$this->assertText($subject_text, t('Individual comment-reply subject found.'));
$this->assertText($comment_text, t('Individual comment-reply body found.'));
$this->assertText($subject_text, 'Individual comment-reply subject found.');
$this->assertText($comment_text, 'Individual comment-reply body found.');
$reply = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
$reply_loaded = comment_load($reply->id);
$this->assertTrue($this->commentExists($reply, TRUE), t('Second reply found.'));
$this->assertEqual(rtrim($comment_loaded->thread, '/') . '.01/', $reply_loaded->thread, t('Thread of second reply grows correctly.'));
$this->assertTrue($this->commentExists($reply, TRUE), 'Second reply found.');
$this->assertEqual(rtrim($comment_loaded->thread, '/') . '.01/', $reply_loaded->thread, 'Thread of second reply grows correctly.');
// Edit reply.
$this->drupalGet('comment/' . $reply->id . '/edit');
$reply = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
$this->assertTrue($this->commentExists($reply, TRUE), t('Modified reply found.'));
$this->assertTrue($this->commentExists($reply, TRUE), 'Modified reply found.');
// Correct link count
$this->drupalGet('node');
$this->assertRaw('4 comments', t('Link to the 4 comments exist.'));
$this->assertRaw('4 comments', 'Link to the 4 comments exist.');
// Confirm a new comment is posted to the correct page.
$this->setCommentsPerPage(2);
$comment_new_page = $this->postComment($this->node, $this->randomName(), $this->randomName(), TRUE);
$this->assertTrue($this->commentExists($comment_new_page), t('Page one exists. %s'));
$this->assertTrue($this->commentExists($comment_new_page), 'Page one exists. %s');
$this->drupalGet('node/' . $this->node->nid, array('query' => array('page' => 1)));
$this->assertTrue($this->commentExists($reply, TRUE), t('Page two exists. %s'));
$this->assertTrue($this->commentExists($reply, TRUE), 'Page two exists. %s');
$this->setCommentsPerPage(50);
// Attempt to post to node with comments disabled.
$this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => COMMENT_NODE_HIDDEN));
$this->assertTrue($this->node, t('Article node created.'));
$this->assertTrue($this->node, 'Article node created.');
$this->drupalGet('comment/reply/' . $this->node->nid);
$this->assertText('This discussion is closed', t('Posting to node with comments disabled'));
$this->assertNoField('edit-comment', t('Comment body field found.'));
$this->assertText('This discussion is closed', 'Posting to node with comments disabled');
$this->assertNoField('edit-comment', 'Comment body field found.');
// Attempt to post to node with read-only comments.
$this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => COMMENT_NODE_CLOSED));
$this->assertTrue($this->node, t('Article node created.'));
$this->assertTrue($this->node, 'Article node created.');
$this->drupalGet('comment/reply/' . $this->node->nid);
$this->assertText('This discussion is closed', t('Posting to node with comments read-only'));
$this->assertNoField('edit-comment', t('Comment body field found.'));
$this->assertText('This discussion is closed', 'Posting to node with comments read-only');
$this->assertNoField('edit-comment', 'Comment body field found.');
// Attempt to post to node with comments enabled (check field names etc).
$this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => COMMENT_NODE_OPEN));
$this->assertTrue($this->node, t('Article node created.'));
$this->assertTrue($this->node, 'Article node created.');
$this->drupalGet('comment/reply/' . $this->node->nid);
$this->assertNoText('This discussion is closed', t('Posting to node with comments enabled'));
$this->assertField('edit-comment-body-' . $langcode . '-0-value', t('Comment body field found.'));
$this->assertNoText('This discussion is closed', 'Posting to node with comments enabled');
$this->assertField('edit-comment-body-' . $langcode . '-0-value', 'Comment body field found.');
// Delete comment and make sure that reply is also removed.
$this->drupalLogout();
@@ -395,8 +396,8 @@ class CommentInterfaceTest extends CommentHelperCase {
$this->deleteComment($comment_new_page);
$this->drupalGet('node/' . $this->node->nid);
$this->assertFalse($this->commentExists($comment), t('Comment not found.'));
$this->assertFalse($this->commentExists($reply, TRUE), t('Reply not found.'));
$this->assertFalse($this->commentExists($comment), 'Comment not found.');
$this->assertFalse($this->commentExists($reply, TRUE), 'Reply not found.');
// Enabled comment form on node page.
$this->drupalLogin($this->admin_user);
@@ -407,7 +408,7 @@ class CommentInterfaceTest extends CommentHelperCase {
$this->drupalLogin($this->web_user);
$this->drupalGet('node/' . $this->node->nid);
$form_comment = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
$this->assertTrue($this->commentExists($form_comment), t('Form comment found.'));
$this->assertTrue($this->commentExists($form_comment), 'Form comment found.');
// Disable comment form on node page.
$this->drupalLogout();
@@ -428,7 +429,7 @@ class CommentInterfaceTest extends CommentHelperCase {
$this->assertNoLink(t('@count new comments', array('@count' => 0)));
$this->assertLink(t('Read more'));
$count = $this->xpath('//div[@id=:id]/div[@class=:class]/ul/li', array(':id' => 'node-' . $this->node->nid, ':class' => 'link-wrapper'));
$this->assertTrue(count($count) == 1, t('One child found'));
$this->assertTrue(count($count) == 1, 'One child found');
// Create a new comment. This helper function may be run with different
// comment settings so use comment_save() to avoid complex setup.
@@ -452,8 +453,8 @@ class CommentInterfaceTest extends CommentHelperCase {
$this->drupalGet('node');
$this->assertLink(t('1 new comment'));
$this->clickLink(t('1 new comment'));
$this->assertRaw('<a id="new"></a>', t('Found "new" marker.'));
$this->assertTrue($this->xpath('//a[@id=:new]/following-sibling::a[1][@id=:comment_id]', array(':new' => 'new', ':comment_id' => 'comment-1')), t('The "new" anchor is positioned at the right comment.'));
$this->assertRaw('<a id="new"></a>', 'Found "new" marker.');
$this->assertTrue($this->xpath('//a[@id=:new]/following-sibling::a[1][@id=:comment_id]', array(':new' => 'new', ':comment_id' => 'comment-1')), 'The "new" anchor is positioned at the right comment.');
// Test if "new comment" link is correctly removed.
$this->drupalGet('node');
@@ -590,10 +591,10 @@ class CommentInterfaceTest extends CommentHelperCase {
// Checks the initial values of node comment statistics with no comment.
$node = node_load($this->node->nid);
$this->assertEqual($node->last_comment_timestamp, $this->node->created, t('The initial value of node last_comment_timestamp is the node created date.'));
$this->assertEqual($node->last_comment_name, NULL, t('The initial value of node last_comment_name is NULL.'));
$this->assertEqual($node->last_comment_uid, $this->web_user->uid, t('The initial value of node last_comment_uid is the node uid.'));
$this->assertEqual($node->comment_count, 0, t('The initial value of node comment_count is zero.'));
$this->assertEqual($node->last_comment_timestamp, $this->node->created, 'The initial value of node last_comment_timestamp is the node created date.');
$this->assertEqual($node->last_comment_name, NULL, 'The initial value of node last_comment_name is NULL.');
$this->assertEqual($node->last_comment_uid, $this->web_user->uid, 'The initial value of node last_comment_uid is the node uid.');
$this->assertEqual($node->comment_count, 0, 'The initial value of node comment_count is zero.');
// Post comment #1 as web_user2.
$this->drupalLogin($this->web_user2);
@@ -604,9 +605,9 @@ class CommentInterfaceTest extends CommentHelperCase {
// Checks the new values of node comment statistics with comment #1.
// The node needs to be reloaded with a node_load_multiple cache reset.
$node = node_load($this->node->nid, NULL, TRUE);
$this->assertEqual($node->last_comment_name, NULL, t('The value of node last_comment_name is NULL.'));
$this->assertEqual($node->last_comment_uid, $this->web_user2->uid, t('The value of node last_comment_uid is the comment #1 uid.'));
$this->assertEqual($node->comment_count, 1, t('The value of node comment_count is 1.'));
$this->assertEqual($node->last_comment_name, NULL, 'The value of node last_comment_name is NULL.');
$this->assertEqual($node->last_comment_uid, $this->web_user2->uid, 'The value of node last_comment_uid is the comment #1 uid.');
$this->assertEqual($node->comment_count, 1, 'The value of node comment_count is 1.');
// Prepare for anonymous comment submission (comment approval enabled).
variable_set('user_register', USER_REGISTER_VISITORS);
@@ -629,9 +630,9 @@ class CommentInterfaceTest extends CommentHelperCase {
// ensure they haven't changed since the comment has not been moderated.
// The node needs to be reloaded with a node_load_multiple cache reset.
$node = node_load($this->node->nid, NULL, TRUE);
$this->assertEqual($node->last_comment_name, NULL, t('The value of node last_comment_name is still NULL.'));
$this->assertEqual($node->last_comment_uid, $this->web_user2->uid, t('The value of node last_comment_uid is still the comment #1 uid.'));
$this->assertEqual($node->comment_count, 1, t('The value of node comment_count is still 1.'));
$this->assertEqual($node->last_comment_name, NULL, 'The value of node last_comment_name is still NULL.');
$this->assertEqual($node->last_comment_uid, $this->web_user2->uid, 'The value of node last_comment_uid is still the comment #1 uid.');
$this->assertEqual($node->comment_count, 1, 'The value of node comment_count is still 1.');
// Prepare for anonymous comment submission (no approval required).
$this->drupalLogin($this->admin_user);
@@ -650,9 +651,9 @@ class CommentInterfaceTest extends CommentHelperCase {
// Checks the new values of node comment statistics with comment #3.
// The node needs to be reloaded with a node_load_multiple cache reset.
$node = node_load($this->node->nid, NULL, TRUE);
$this->assertEqual($node->last_comment_name, $comment_loaded->name, t('The value of node last_comment_name is the name of the anonymous user.'));
$this->assertEqual($node->last_comment_uid, 0, t('The value of node last_comment_uid is zero.'));
$this->assertEqual($node->comment_count, 2, t('The value of node comment_count is 2.'));
$this->assertEqual($node->last_comment_name, $comment_loaded->name, 'The value of node last_comment_name is the name of the anonymous user.');
$this->assertEqual($node->last_comment_uid, 0, 'The value of node last_comment_uid is zero.');
$this->assertEqual($node->comment_count, 2, 'The value of node comment_count is 2.');
}
/**
@@ -919,10 +920,10 @@ class CommentInterfaceTest extends CommentHelperCase {
if ($path == "node/$nid") {
$elements = $this->xpath('//form[@id=:id]', array(':id' => 'comment-form'));
if ($info['form'] == COMMENT_FORM_BELOW) {
$this->assertTrue(count($elements), t('Comment form found below.'));
$this->assertTrue(count($elements), 'Comment form found below.');
}
else {
$this->assertFalse(count($elements), t('Comment form not found below.'));
$this->assertFalse(count($elements), 'Comment form not found below.');
}
}
}
@@ -974,13 +975,13 @@ class CommentPreviewTest extends CommentHelperCase {
$this->drupalPost('node/' . $this->node->nid, $edit, t('Preview'));
// Check that the preview is displaying the title and body.
$this->assertTitle(t('Preview comment | Drupal'), t('Page title is "Preview comment".'));
$this->assertText($edit['subject'], t('Subject displayed.'));
$this->assertText($edit['comment_body[' . $langcode . '][0][value]'], t('Comment displayed.'));
$this->assertTitle(t('Preview comment | Drupal'), 'Page title is "Preview comment".');
$this->assertText($edit['subject'], 'Subject displayed.');
$this->assertText($edit['comment_body[' . $langcode . '][0][value]'], 'Comment displayed.');
// Check that the title and body fields are displayed with the correct values.
$this->assertFieldByName('subject', $edit['subject'], t('Subject field displayed.'));
$this->assertFieldByName('comment_body[' . $langcode . '][0][value]', $edit['comment_body[' . $langcode . '][0][value]'], t('Comment field displayed.'));
$this->assertFieldByName('subject', $edit['subject'], 'Subject field displayed.');
$this->assertFieldByName('comment_body[' . $langcode . '][0][value]', $edit['comment_body[' . $langcode . '][0][value]'], 'Comment field displayed.');
// Check that the signature is displaying with the correct text format.
$this->assertLink($test_signature);
@@ -1013,28 +1014,28 @@ class CommentPreviewTest extends CommentHelperCase {
$this->drupalPost('comment/' . $comment->id . '/edit', $edit, t('Preview'));
// Check that the preview is displaying the subject, comment, author and date correctly.
$this->assertTitle(t('Preview comment | Drupal'), t('Page title is "Preview comment".'));
$this->assertText($edit['subject'], t('Subject displayed.'));
$this->assertText($edit['comment_body[' . $langcode . '][0][value]'], t('Comment displayed.'));
$this->assertText($edit['name'], t('Author displayed.'));
$this->assertText($expected_text_date, t('Date displayed.'));
$this->assertTitle(t('Preview comment | Drupal'), 'Page title is "Preview comment".');
$this->assertText($edit['subject'], 'Subject displayed.');
$this->assertText($edit['comment_body[' . $langcode . '][0][value]'], 'Comment displayed.');
$this->assertText($edit['name'], 'Author displayed.');
$this->assertText($expected_text_date, 'Date displayed.');
// Check that the subject, comment, author and date fields are displayed with the correct values.
$this->assertFieldByName('subject', $edit['subject'], t('Subject field displayed.'));
$this->assertFieldByName('comment_body[' . $langcode . '][0][value]', $edit['comment_body[' . $langcode . '][0][value]'], t('Comment field displayed.'));
$this->assertFieldByName('name', $edit['name'], t('Author field displayed.'));
$this->assertFieldByName('date', $edit['date'], t('Date field displayed.'));
$this->assertFieldByName('subject', $edit['subject'], 'Subject field displayed.');
$this->assertFieldByName('comment_body[' . $langcode . '][0][value]', $edit['comment_body[' . $langcode . '][0][value]'], 'Comment field displayed.');
$this->assertFieldByName('name', $edit['name'], 'Author field displayed.');
$this->assertFieldByName('date', $edit['date'], 'Date field displayed.');
// Check that saving a comment produces a success message.
$this->drupalPost('comment/' . $comment->id . '/edit', $edit, t('Save'));
$this->assertText(t('Your comment has been posted.'), t('Comment posted.'));
$this->assertText(t('Your comment has been posted.'), 'Comment posted.');
// Check that the comment fields are correct after loading the saved comment.
$this->drupalGet('comment/' . $comment->id . '/edit');
$this->assertFieldByName('subject', $edit['subject'], t('Subject field displayed.'));
$this->assertFieldByName('comment_body[' . $langcode . '][0][value]', $edit['comment_body[' . $langcode . '][0][value]'], t('Comment field displayed.'));
$this->assertFieldByName('name', $edit['name'], t('Author field displayed.'));
$this->assertFieldByName('date', $expected_form_date, t('Date field displayed.'));
$this->assertFieldByName('subject', $edit['subject'], 'Subject field displayed.');
$this->assertFieldByName('comment_body[' . $langcode . '][0][value]', $edit['comment_body[' . $langcode . '][0][value]'], 'Comment field displayed.');
$this->assertFieldByName('name', $edit['name'], 'Author field displayed.');
$this->assertFieldByName('date', $expected_form_date, 'Date field displayed.');
// Submit the form using the displayed values.
$displayed = array();
@@ -1046,10 +1047,10 @@ class CommentPreviewTest extends CommentHelperCase {
// Check that the saved comment is still correct.
$comment_loaded = comment_load($comment->id);
$this->assertEqual($comment_loaded->subject, $edit['subject'], t('Subject loaded.'));
$this->assertEqual($comment_loaded->comment_body[$langcode][0]['value'], $edit['comment_body[' . $langcode . '][0][value]'], t('Comment body loaded.'));
$this->assertEqual($comment_loaded->name, $edit['name'], t('Name loaded.'));
$this->assertEqual($comment_loaded->created, $raw_date, t('Date loaded.'));
$this->assertEqual($comment_loaded->subject, $edit['subject'], 'Subject loaded.');
$this->assertEqual($comment_loaded->comment_body[$langcode][0]['value'], $edit['comment_body[' . $langcode . '][0][value]'], 'Comment body loaded.');
$this->assertEqual($comment_loaded->name, $edit['name'], 'Name loaded.');
$this->assertEqual($comment_loaded->created, $raw_date, 'Date loaded.');
}
@@ -1085,7 +1086,7 @@ class CommentAnonymous extends CommentHelperCase {
// Post anonymous comment without contact info.
$anonymous_comment1 = $this->postComment($this->node, $this->randomName(), $this->randomName());
$this->assertTrue($this->commentExists($anonymous_comment1), t('Anonymous comment without contact info found.'));
$this->assertTrue($this->commentExists($anonymous_comment1), 'Anonymous comment without contact info found.');
// Allow contact info.
$this->drupalLogin($this->admin_user);
@@ -1094,15 +1095,15 @@ class CommentAnonymous extends CommentHelperCase {
// Attempt to edit anonymous comment.
$this->drupalGet('comment/' . $anonymous_comment1->id . '/edit');
$edited_comment = $this->postComment(NULL, $this->randomName(), $this->randomName());
$this->assertTrue($this->commentExists($edited_comment, FALSE), t('Modified reply found.'));
$this->assertTrue($this->commentExists($edited_comment, FALSE), 'Modified reply found.');
$this->drupalLogout();
// Post anonymous comment with contact info (optional).
$this->drupalGet('comment/reply/' . $this->node->nid);
$this->assertTrue($this->commentContactInfoAvailable(), t('Contact information available.'));
$this->assertTrue($this->commentContactInfoAvailable(), 'Contact information available.');
$anonymous_comment2 = $this->postComment($this->node, $this->randomName(), $this->randomName());
$this->assertTrue($this->commentExists($anonymous_comment2), t('Anonymous comment with contact info (optional) found.'));
$this->assertTrue($this->commentExists($anonymous_comment2), 'Anonymous comment with contact info (optional) found.');
// Ensure anonymous users cannot post in the name of registered users.
$langcode = LANGUAGE_NONE;
@@ -1122,41 +1123,42 @@ class CommentAnonymous extends CommentHelperCase {
// Try to post comment with contact info (required).
$this->drupalGet('comment/reply/' . $this->node->nid);
$this->assertTrue($this->commentContactInfoAvailable(), t('Contact information available.'));
$this->assertTrue($this->commentContactInfoAvailable(), 'Contact information available.');
$anonymous_comment3 = $this->postComment($this->node, $this->randomName(), $this->randomName(), TRUE);
$this->assertText(t('E-mail field is required.'), t('E-mail required.')); // Name should have 'Anonymous' for value by default.
$this->assertFalse($this->commentExists($anonymous_comment3), t('Anonymous comment with contact info (required) not found.'));
// Name should have 'Anonymous' for value by default.
$this->assertText(t('E-mail field is required.'), 'E-mail required.');
$this->assertFalse($this->commentExists($anonymous_comment3), 'Anonymous comment with contact info (required) not found.');
// Post comment with contact info (required).
$author_name = $this->randomName();
$author_mail = $this->randomName() . '@example.com';
$anonymous_comment3 = $this->postComment($this->node, $this->randomName(), $this->randomName(), array('name' => $author_name, 'mail' => $author_mail));
$this->assertTrue($this->commentExists($anonymous_comment3), t('Anonymous comment with contact info (required) found.'));
$this->assertTrue($this->commentExists($anonymous_comment3), 'Anonymous comment with contact info (required) found.');
// Make sure the user data appears correctly when editing the comment.
$this->drupalLogin($this->admin_user);
$this->drupalGet('comment/' . $anonymous_comment3->id . '/edit');
$this->assertRaw($author_name, t("The anonymous user's name is correct when editing the comment."));
$this->assertRaw($author_mail, t("The anonymous user's e-mail address is correct when editing the comment."));
$this->assertRaw($author_name, "The anonymous user's name is correct when editing the comment.");
$this->assertRaw($author_mail, "The anonymous user's e-mail address is correct when editing the comment.");
// Unpublish comment.
$this->performCommentOperation($anonymous_comment3, 'unpublish');
$this->drupalGet('admin/content/comment/approval');
$this->assertRaw('comments[' . $anonymous_comment3->id . ']', t('Comment was unpublished.'));
$this->assertRaw('comments[' . $anonymous_comment3->id . ']', 'Comment was unpublished.');
// Publish comment.
$this->performCommentOperation($anonymous_comment3, 'publish', TRUE);
$this->drupalGet('admin/content/comment');
$this->assertRaw('comments[' . $anonymous_comment3->id . ']', t('Comment was published.'));
$this->assertRaw('comments[' . $anonymous_comment3->id . ']', 'Comment was published.');
// Delete comment.
$this->performCommentOperation($anonymous_comment3, 'delete');
$this->drupalGet('admin/content/comment');
$this->assertNoRaw('comments[' . $anonymous_comment3->id . ']', t('Comment was deleted.'));
$this->assertNoRaw('comments[' . $anonymous_comment3->id . ']', 'Comment was deleted.');
$this->drupalLogout();
// Reset.
@@ -1170,14 +1172,14 @@ class CommentAnonymous extends CommentHelperCase {
// NOTE: if authenticated user has permission to post comments, then a
// "Login or register to post comments" type link may be shown.
$this->drupalGet('node/' . $this->node->nid);
$this->assertNoPattern('@<h2[^>]*>Comments</h2>@', t('Comments were not displayed.'));
$this->assertNoLink('Add new comment', t('Link to add comment was found.'));
$this->assertNoPattern('@<h2[^>]*>Comments</h2>@', 'Comments were not displayed.');
$this->assertNoLink('Add new comment', 'Link to add comment was found.');
// Attempt to view node-comment form while disallowed.
$this->drupalGet('comment/reply/' . $this->node->nid);
$this->assertText('You are not authorized to post comments', t('Error attempting to post comment.'));
$this->assertNoFieldByName('subject', '', t('Subject field not found.'));
$this->assertNoFieldByName("comment_body[$langcode][0][value]", '', t('Comment field not found.'));
$this->assertText('You are not authorized to post comments', 'Error attempting to post comment.');
$this->assertNoFieldByName('subject', '', 'Subject field not found.');
$this->assertNoFieldByName("comment_body[$langcode][0][value]", '', 'Comment field not found.');
user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(
'access comments' => TRUE,
@@ -1185,9 +1187,9 @@ class CommentAnonymous extends CommentHelperCase {
'skip comment approval' => FALSE,
));
$this->drupalGet('node/' . $this->node->nid);
$this->assertPattern('@<h2[^>]*>Comments</h2>@', t('Comments were displayed.'));
$this->assertLink('Log in', 1, t('Link to log in was found.'));
$this->assertLink('register', 1, t('Link to register was found.'));
$this->assertPattern('@<h2[^>]*>Comments</h2>@', 'Comments were displayed.');
$this->assertLink('Log in', 1, 'Link to log in was found.');
$this->assertLink('register', 1, 'Link to register was found.');
user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(
'access comments' => FALSE,
@@ -1195,13 +1197,13 @@ class CommentAnonymous extends CommentHelperCase {
'skip comment approval' => TRUE,
));
$this->drupalGet('node/' . $this->node->nid);
$this->assertNoPattern('@<h2[^>]*>Comments</h2>@', t('Comments were not displayed.'));
$this->assertFieldByName('subject', '', t('Subject field found.'));
$this->assertFieldByName("comment_body[$langcode][0][value]", '', t('Comment field found.'));
$this->assertNoPattern('@<h2[^>]*>Comments</h2>@', 'Comments were not displayed.');
$this->assertFieldByName('subject', '', 'Subject field found.');
$this->assertFieldByName("comment_body[$langcode][0][value]", '', 'Comment field found.');
$this->drupalGet('comment/reply/' . $this->node->nid . '/' . $anonymous_comment3->id);
$this->assertText('You are not authorized to view comments', t('Error attempting to post reply.'));
$this->assertNoText($author_name, t('Comment not displayed.'));
$this->assertText('You are not authorized to view comments', 'Error attempting to post reply.');
$this->assertNoText($author_name, 'Comment not displayed.');
}
}
@@ -1245,22 +1247,22 @@ class CommentPagerTest extends CommentHelperCase {
// Check the first page of the node, and confirm the correct comments are
// shown.
$this->drupalGet('node/' . $node->nid);
$this->assertRaw(t('next'), t('Paging links found.'));
$this->assertTrue($this->commentExists($comments[0]), t('Comment 1 appears on page 1.'));
$this->assertFalse($this->commentExists($comments[1]), t('Comment 2 does not appear on page 1.'));
$this->assertFalse($this->commentExists($comments[2]), t('Comment 3 does not appear on page 1.'));
$this->assertRaw(t('next'), 'Paging links found.');
$this->assertTrue($this->commentExists($comments[0]), 'Comment 1 appears on page 1.');
$this->assertFalse($this->commentExists($comments[1]), 'Comment 2 does not appear on page 1.');
$this->assertFalse($this->commentExists($comments[2]), 'Comment 3 does not appear on page 1.');
// Check the second page.
$this->drupalGet('node/' . $node->nid, array('query' => array('page' => 1)));
$this->assertTrue($this->commentExists($comments[1]), t('Comment 2 appears on page 2.'));
$this->assertFalse($this->commentExists($comments[0]), t('Comment 1 does not appear on page 2.'));
$this->assertFalse($this->commentExists($comments[2]), t('Comment 3 does not appear on page 2.'));
$this->assertTrue($this->commentExists($comments[1]), 'Comment 2 appears on page 2.');
$this->assertFalse($this->commentExists($comments[0]), 'Comment 1 does not appear on page 2.');
$this->assertFalse($this->commentExists($comments[2]), 'Comment 3 does not appear on page 2.');
// Check the third page.
$this->drupalGet('node/' . $node->nid, array('query' => array('page' => 2)));
$this->assertTrue($this->commentExists($comments[2]), t('Comment 3 appears on page 3.'));
$this->assertFalse($this->commentExists($comments[0]), t('Comment 1 does not appear on page 3.'));
$this->assertFalse($this->commentExists($comments[1]), t('Comment 2 does not appear on page 3.'));
$this->assertTrue($this->commentExists($comments[2]), 'Comment 3 appears on page 3.');
$this->assertFalse($this->commentExists($comments[0]), 'Comment 1 does not appear on page 3.');
$this->assertFalse($this->commentExists($comments[1]), 'Comment 2 does not appear on page 3.');
// Post a reply to the oldest comment and test again.
$replies = array();
@@ -1272,21 +1274,21 @@ class CommentPagerTest extends CommentHelperCase {
// We are still in flat view - the replies should not be on the first page,
// even though they are replies to the oldest comment.
$this->drupalGet('node/' . $node->nid, array('query' => array('page' => 0)));
$this->assertFalse($this->commentExists($reply, TRUE), t('In flat mode, reply does not appear on page 1.'));
$this->assertFalse($this->commentExists($reply, TRUE), 'In flat mode, reply does not appear on page 1.');
// If we switch to threaded mode, the replies on the oldest comment
// should be bumped to the first page and comment 6 should be bumped
// to the second page.
$this->setCommentSettings('comment_default_mode', COMMENT_MODE_THREADED, t('Switched to threaded mode.'));
$this->drupalGet('node/' . $node->nid, array('query' => array('page' => 0)));
$this->assertTrue($this->commentExists($reply, TRUE), t('In threaded mode, reply appears on page 1.'));
$this->assertFalse($this->commentExists($comments[1]), t('In threaded mode, comment 2 has been bumped off of page 1.'));
$this->assertTrue($this->commentExists($reply, TRUE), 'In threaded mode, reply appears on page 1.');
$this->assertFalse($this->commentExists($comments[1]), 'In threaded mode, comment 2 has been bumped off of page 1.');
// If (# replies > # comments per page) in threaded expanded view,
// the overage should be bumped.
$reply2 = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
$this->drupalGet('node/' . $node->nid, array('query' => array('page' => 0)));
$this->assertFalse($this->commentExists($reply2, TRUE), t('In threaded mode where # replies > # comments per page, the newest reply does not appear on page 1.'));
$this->assertFalse($this->commentExists($reply2, TRUE), 'In threaded mode where # replies > # comments per page, the newest reply does not appear on page 1.');
$this->drupalLogout();
}
@@ -1388,7 +1390,7 @@ class CommentPagerTest extends CommentHelperCase {
$result_order[] = substr($anchor['id'], 8);
}
return $this->assertIdentical($expected_cids, $result_order, t('Comment order: expected @expected, returned @returned.', array('@expected' => implode(',', $expected_cids), '@returned' => implode(',', $result_order))));
return $this->assertIdentical($expected_cids, $result_order, format_string('Comment order: expected @expected, returned @returned.', array('@expected' => implode(',', $expected_cids), '@returned' => implode(',', $result_order))));
}
/**
@@ -1448,7 +1450,7 @@ class CommentPagerTest extends CommentHelperCase {
foreach ($expected_pages as $new_replies => $expected_page) {
$returned = comment_new_page_count($node->comment_count, $new_replies, $node);
$returned_page = is_array($returned) ? $returned['page'] : 0;
$this->assertIdentical($expected_page, $returned_page, t('Flat mode, @new replies: expected page @expected, returned page @returned.', array('@new' => $new_replies, '@expected' => $expected_page, '@returned' => $returned_page)));
$this->assertIdentical($expected_page, $returned_page, format_string('Flat mode, @new replies: expected page @expected, returned page @returned.', array('@new' => $new_replies, '@expected' => $expected_page, '@returned' => $returned_page)));
}
$this->setCommentSettings('comment_default_mode', COMMENT_MODE_THREADED, t('Switched to threaded mode.'));
@@ -1466,7 +1468,7 @@ class CommentPagerTest extends CommentHelperCase {
foreach ($expected_pages as $new_replies => $expected_page) {
$returned = comment_new_page_count($node->comment_count, $new_replies, $node);
$returned_page = is_array($returned) ? $returned['page'] : 0;
$this->assertEqual($expected_page, $returned_page, t('Threaded mode, @new replies: expected page @expected, returned page @returned.', array('@new' => $new_replies, '@expected' => $expected_page, '@returned' => $returned_page)));
$this->assertEqual($expected_page, $returned_page, format_string('Threaded mode, @new replies: expected page @expected, returned page @returned.', array('@new' => $new_replies, '@expected' => $expected_page, '@returned' => $returned_page)));
}
}
}
@@ -1516,12 +1518,12 @@ class CommentNodeAccessTest extends CommentHelperCase {
$comment_subject = $this->randomName();
$comment = $this->postComment($this->node, $comment_text, $comment_subject);
$comment_loaded = comment_load($comment->id);
$this->assertTrue($this->commentExists($comment), t('Comment found.'));
$this->assertTrue($this->commentExists($comment), 'Comment found.');
// Check comment display.
$this->drupalGet('node/' . $this->node->nid . '/' . $comment->id);
$this->assertText($comment_subject, t('Individual comment subject found.'));
$this->assertText($comment_text, t('Individual comment body found.'));
$this->assertText($comment_subject, 'Individual comment subject found.');
$this->assertText($comment_text, 'Individual comment body found.');
// Reply to comment, creating second comment.
$this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id);
@@ -1529,7 +1531,7 @@ class CommentNodeAccessTest extends CommentHelperCase {
$reply_subject = $this->randomName();
$reply = $this->postComment(NULL, $reply_text, $reply_subject, TRUE);
$reply_loaded = comment_load($reply->id);
$this->assertTrue($this->commentExists($reply, TRUE), t('Reply found.'));
$this->assertTrue($this->commentExists($reply, TRUE), 'Reply found.');
// Go to the node page and verify comment and reply are visible.
$this->drupalGet('node/' . $this->node->nid);
@@ -1572,7 +1574,7 @@ class CommentApprovalTest extends CommentHelperCase {
$subject = $this->randomName();
$body = $this->randomName();
$this->postComment($this->node, $body, $subject, TRUE); // Set $contact to true so that it won't check for id and message.
$this->assertText(t('Your comment has been queued for review by site administrators and will be published after approval.'), t('Comment requires approval.'));
$this->assertText(t('Your comment has been queued for review by site administrators and will be published after approval.'), 'Comment requires approval.');
// Get unapproved comment id.
$this->drupalLogin($this->admin_user);
@@ -1580,7 +1582,7 @@ class CommentApprovalTest extends CommentHelperCase {
$anonymous_comment4 = (object) array('id' => $anonymous_comment4, 'subject' => $subject, 'comment' => $body);
$this->drupalLogout();
$this->assertFalse($this->commentExists($anonymous_comment4), t('Anonymous comment was not published.'));
$this->assertFalse($this->commentExists($anonymous_comment4), 'Anonymous comment was not published.');
// Approve comment.
$this->drupalLogin($this->admin_user);
@@ -1588,7 +1590,7 @@ class CommentApprovalTest extends CommentHelperCase {
$this->drupalLogout();
$this->drupalGet('node/' . $this->node->nid);
$this->assertTrue($this->commentExists($anonymous_comment4), t('Anonymous comment visible.'));
$this->assertTrue($this->commentExists($anonymous_comment4), 'Anonymous comment visible.');
// Post 2 anonymous comments without contact info.
$comments[] = $this->postComment($this->node, $this->randomName(), $this->randomName(), TRUE);
@@ -1597,13 +1599,13 @@ class CommentApprovalTest extends CommentHelperCase {
// Publish multiple comments in one operation.
$this->drupalLogin($this->admin_user);
$this->drupalGet('admin/content/comment/approval');
$this->assertText(t('Unapproved comments (@count)', array('@count' => 2)), t('Two unapproved comments waiting for approval.'));
$this->assertText(t('Unapproved comments (@count)', array('@count' => 2)), 'Two unapproved comments waiting for approval.');
$edit = array(
"comments[{$comments[0]->id}]" => 1,
"comments[{$comments[1]->id}]" => 1,
);
$this->drupalPost(NULL, $edit, t('Update'));
$this->assertText(t('Unapproved comments (@count)', array('@count' => 0)), t('All comments were approved.'));
$this->assertText(t('Unapproved comments (@count)', array('@count' => 0)), 'All comments were approved.');
// Delete multiple comments in one operation.
$edit = array(
@@ -1613,9 +1615,9 @@ class CommentApprovalTest extends CommentHelperCase {
"comments[{$anonymous_comment4->id}]" => 1,
);
$this->drupalPost(NULL, $edit, t('Update'));
$this->assertText(t('Are you sure you want to delete these comments and all their children?'), t('Confirmation required.'));
$this->assertText(t('Are you sure you want to delete these comments and all their children?'), 'Confirmation required.');
$this->drupalPost(NULL, $edit, t('Delete comments'));
$this->assertText(t('No comments available.'), t('All comments were deleted.'));
$this->assertText(t('No comments available.'), 'All comments were deleted.');
}
/**
@@ -1636,7 +1638,7 @@ class CommentApprovalTest extends CommentHelperCase {
$subject = $this->randomName();
$body = $this->randomName();
$this->postComment($this->node, $body, $subject, TRUE); // Set $contact to true so that it won't check for id and message.
$this->assertText(t('Your comment has been queued for review by site administrators and will be published after approval.'), t('Comment requires approval.'));
$this->assertText(t('Your comment has been queued for review by site administrators and will be published after approval.'), 'Comment requires approval.');
// Get unapproved comment id.
$this->drupalLogin($this->admin_user);
@@ -1644,20 +1646,20 @@ class CommentApprovalTest extends CommentHelperCase {
$anonymous_comment4 = (object) array('id' => $anonymous_comment4, 'subject' => $subject, 'comment' => $body);
$this->drupalLogout();
$this->assertFalse($this->commentExists($anonymous_comment4), t('Anonymous comment was not published.'));
$this->assertFalse($this->commentExists($anonymous_comment4), 'Anonymous comment was not published.');
// Approve comment.
$this->drupalLogin($this->admin_user);
$this->drupalGet('comment/1/approve');
$this->assertResponse(403, t('Forged comment approval was denied.'));
$this->assertResponse(403, 'Forged comment approval was denied.');
$this->drupalGet('comment/1/approve', array('query' => array('token' => 'forged')));
$this->assertResponse(403, t('Forged comment approval was denied.'));
$this->assertResponse(403, 'Forged comment approval was denied.');
$this->drupalGet('node/' . $this->node->nid);
$this->clickLink(t('approve'));
$this->drupalLogout();
$this->drupalGet('node/' . $this->node->nid);
$this->assertTrue($this->commentExists($anonymous_comment4), t('Anonymous comment visible.'));
$this->assertTrue($this->commentExists($anonymous_comment4), 'Anonymous comment visible.');
}
}
@@ -1684,7 +1686,7 @@ class CommentBlockFunctionalTest extends CommentHelperCase {
'blocks[comment_recent][region]' => 'sidebar_first',
);
$this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
$this->assertText(t('The block settings have been updated.'), t('Block saved to first sidebar region.'));
$this->assertText(t('The block settings have been updated.'), 'Block saved to first sidebar region.');
// Set block title and variables.
$block = array(
@@ -1692,7 +1694,7 @@ class CommentBlockFunctionalTest extends CommentHelperCase {
'comment_block_count' => 2,
);
$this->drupalPost('admin/structure/block/manage/comment/recent/configure', $block, t('Save block'));
$this->assertText(t('The block configuration has been saved.'), t('Block saved.'));
$this->assertText(t('The block configuration has been saved.'), 'Block saved.');
// Add some test comments, one without a subject.
$comment1 = $this->postComment($this->node, $this->randomName(), $this->randomName());
@@ -1704,20 +1706,20 @@ class CommentBlockFunctionalTest extends CommentHelperCase {
$this->drupalLogout();
user_role_revoke_permissions(DRUPAL_ANONYMOUS_RID, array('access comments'));
$this->drupalGet('');
$this->assertNoText($block['title'], t('Block was not found.'));
$this->assertNoText($block['title'], 'Block was not found.');
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access comments'));
// Test that a user with the 'access comments' permission can see the
// block.
$this->drupalLogin($this->web_user);
$this->drupalGet('');
$this->assertText($block['title'], t('Block was found.'));
$this->assertText($block['title'], 'Block was found.');
// Test the only the 2 latest comments are shown and in the proper order.
$this->assertNoText($comment1->subject, t('Comment not found in block.'));
$this->assertText($comment2->subject, t('Comment found in block.'));
$this->assertText($comment3->comment, t('Comment found in block.'));
$this->assertTrue(strpos($this->drupalGetContent(), $comment3->comment) < strpos($this->drupalGetContent(), $comment2->subject), t('Comments were ordered correctly in block.'));
$this->assertNoText($comment1->subject, 'Comment not found in block.');
$this->assertText($comment2->subject, 'Comment found in block.');
$this->assertText($comment3->comment, 'Comment found in block.');
$this->assertTrue(strpos($this->drupalGetContent(), $comment3->comment) < strpos($this->drupalGetContent(), $comment2->subject), 'Comments were ordered correctly in block.');
// Set the number of recent comments to show to 10.
$this->drupalLogout();
@@ -1726,30 +1728,30 @@ class CommentBlockFunctionalTest extends CommentHelperCase {
'comment_block_count' => 10,
);
$this->drupalPost('admin/structure/block/manage/comment/recent/configure', $block, t('Save block'));
$this->assertText(t('The block configuration has been saved.'), t('Block saved.'));
$this->assertText(t('The block configuration has been saved.'), 'Block saved.');
// Post an additional comment.
$comment4 = $this->postComment($this->node, $this->randomName(), $this->randomName());
// Test that all four comments are shown.
$this->assertText($comment1->subject, t('Comment found in block.'));
$this->assertText($comment2->subject, t('Comment found in block.'));
$this->assertText($comment3->comment, t('Comment found in block.'));
$this->assertText($comment4->subject, t('Comment found in block.'));
$this->assertText($comment1->subject, 'Comment found in block.');
$this->assertText($comment2->subject, 'Comment found in block.');
$this->assertText($comment3->comment, 'Comment found in block.');
$this->assertText($comment4->subject, 'Comment found in block.');
// Test that links to comments work when comments are across pages.
$this->setCommentsPerPage(1);
$this->drupalGet('');
$this->clickLink($comment1->subject);
$this->assertText($comment1->subject, t('Comment link goes to correct page.'));
$this->assertText($comment1->subject, 'Comment link goes to correct page.');
$this->drupalGet('');
$this->clickLink($comment2->subject);
$this->assertText($comment2->subject, t('Comment link goes to correct page.'));
$this->assertText($comment2->subject, 'Comment link goes to correct page.');
$this->clickLink($comment4->subject);
$this->assertText($comment4->subject, t('Comment link goes to correct page.'));
$this->assertText($comment4->subject, 'Comment link goes to correct page.');
// Check that when viewing a comment page from a link to the comment, that
// rel="canonical" is added to the head of the document.
$this->assertRaw('<link rel="canonical"', t('Canonical URL was found in the HTML head'));
$this->assertRaw('<link rel="canonical"', 'Canonical URL was found in the HTML head');
}
}
@@ -1774,13 +1776,13 @@ class CommentRSSUnitTest extends CommentHelperCase {
$comment = $this->postComment($this->node, $this->randomName(), $this->randomName());
$this->drupalGet('rss.xml');
$raw = '<comments>' . url('node/' . $this->node->nid, array('fragment' => 'comments', 'absolute' => TRUE)) . '</comments>';
$this->assertRaw($raw, t('Comments as part of RSS feed.'));
$this->assertRaw($raw, 'Comments as part of RSS feed.');
// Hide comments from RSS feed and check presence.
$this->node->comment = COMMENT_NODE_HIDDEN;
node_save($this->node);
$this->drupalGet('rss.xml');
$this->assertNoRaw($raw, t('Hidden comments is not a part of RSS feed.'));
$this->assertNoRaw($raw, 'Hidden comments is not a part of RSS feed.');
}
}
@@ -1814,14 +1816,14 @@ class CommentContentRebuild extends CommentHelperCase {
$comment_text = $this->randomName();
$comment = $this->postComment($this->node, $comment_text, $subject_text, TRUE);
$comment_loaded = comment_load($comment->id);
$this->assertTrue($this->commentExists($comment), t('Comment found.'));
$this->assertTrue($this->commentExists($comment), 'Comment found.');
// Add the property to the content array and then see if it still exists on build.
$comment_loaded->content['test_property'] = array('#value' => $this->randomString());
$built_content = comment_view($comment_loaded, $this->node);
// This means that the content was rebuilt as the added test property no longer exists.
$this->assertFalse(isset($built_content['test_property']), t('Comment content was emptied before being built.'));
$this->assertFalse(isset($built_content['test_property']), 'Comment content was emptied before being built.');
}
}
@@ -1887,11 +1889,11 @@ class CommentTokenReplaceTestCase extends CommentHelperCase {
$tests['[comment:author:name]'] = check_plain($this->admin_user->name);
// Test to make sure that we generated something for each token.
$this->assertFalse(in_array(0, array_map('strlen', $tests)), t('No empty tokens generated.'));
$this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.');
foreach ($tests as $input => $expected) {
$output = token_replace($input, array('comment' => $comment), array('language' => $language));
$this->assertEqual($output, $expected, t('Sanitized comment token %token replaced.', array('%token' => $input)));
$this->assertEqual($output, $expected, format_string('Sanitized comment token %token replaced.', array('%token' => $input)));
}
// Generate and test unsanitized tokens.
@@ -1907,7 +1909,7 @@ class CommentTokenReplaceTestCase extends CommentHelperCase {
foreach ($tests as $input => $expected) {
$output = token_replace($input, array('comment' => $comment), array('language' => $language, 'sanitize' => FALSE));
$this->assertEqual($output, $expected, t('Unsanitized comment token %token replaced.', array('%token' => $input)));
$this->assertEqual($output, $expected, format_string('Unsanitized comment token %token replaced.', array('%token' => $input)));
}
// Load node so comment_count gets computed.
@@ -1920,7 +1922,7 @@ class CommentTokenReplaceTestCase extends CommentHelperCase {
foreach ($tests as $input => $expected) {
$output = token_replace($input, array('node' => $node), array('language' => $language));
$this->assertEqual($output, $expected, t('Node comment token %token replaced.', array('%token' => $input)));
$this->assertEqual($output, $expected, format_string('Node comment token %token replaced.', array('%token' => $input)));
}
}
}
@@ -1949,25 +1951,25 @@ class CommentActionsTestCase extends CommentHelperCase {
// Unpublish a comment (direct form: doesn't actually save the comment).
comment_unpublish_action($comment);
$this->assertEqual($comment->status, COMMENT_NOT_PUBLISHED, t('Comment was unpublished'));
$this->assertWatchdogMessage('Unpublished comment %subject.', array('%subject' => $subject), t('Found watchdog message'));
$this->assertEqual($comment->status, COMMENT_NOT_PUBLISHED, 'Comment was unpublished');
$this->assertWatchdogMessage('Unpublished comment %subject.', array('%subject' => $subject), 'Found watchdog message');
$this->clearWatchdog();
// Unpublish a comment (indirect form: modify the comment in the database).
comment_unpublish_action(NULL, array('cid' => $comment->cid));
$this->assertEqual(comment_load($comment->cid)->status, COMMENT_NOT_PUBLISHED, t('Comment was unpublished'));
$this->assertWatchdogMessage('Unpublished comment %subject.', array('%subject' => $subject), t('Found watchdog message'));
$this->assertEqual(comment_load($comment->cid)->status, COMMENT_NOT_PUBLISHED, 'Comment was unpublished');
$this->assertWatchdogMessage('Unpublished comment %subject.', array('%subject' => $subject), 'Found watchdog message');
// Publish a comment (direct form: doesn't actually save the comment).
comment_publish_action($comment);
$this->assertEqual($comment->status, COMMENT_PUBLISHED, t('Comment was published'));
$this->assertWatchdogMessage('Published comment %subject.', array('%subject' => $subject), t('Found watchdog message'));
$this->assertEqual($comment->status, COMMENT_PUBLISHED, 'Comment was published');
$this->assertWatchdogMessage('Published comment %subject.', array('%subject' => $subject), 'Found watchdog message');
$this->clearWatchdog();
// Publish a comment (indirect form: modify the comment in the database).
comment_publish_action(NULL, array('cid' => $comment->cid));
$this->assertEqual(comment_load($comment->cid)->status, COMMENT_PUBLISHED, t('Comment was published'));
$this->assertWatchdogMessage('Published comment %subject.', array('%subject' => $subject), t('Found watchdog message'));
$this->assertEqual(comment_load($comment->cid)->status, COMMENT_PUBLISHED, 'Comment was published');
$this->assertWatchdogMessage('Published comment %subject.', array('%subject' => $subject), 'Found watchdog message');
$this->clearWatchdog();
}
@@ -1983,7 +1985,7 @@ class CommentActionsTestCase extends CommentHelperCase {
*/
function assertWatchdogMessage($watchdog_message, $variables, $message) {
$status = (bool) db_query_range("SELECT 1 FROM {watchdog} WHERE message = :message AND variables = :variables", 0, 1, array(':message' => $watchdog_message, ':variables' => serialize($variables)))->fetchField();
return $this->assert($status, $message);
return $this->assert($status, format_string('@message', array('@message' => $message)));
}
/**
@@ -2011,13 +2013,13 @@ class CommentFieldsTest extends CommentHelperCase {
*/
function testCommentDefaultFields() {
// Do not make assumptions on default node types created by the test
// install profile, and create our own.
// installation profile, and create our own.
$this->drupalCreateContentType(array('type' => 'test_node_type'));
// Check that the 'comment_body' field is present on all comment bundles.
$instances = field_info_instances('comment');
foreach (node_type_get_types() as $type_name => $info) {
$this->assertTrue(isset($instances['comment_node_' . $type_name]['comment_body']), t('The comment_body field is present for comments on type @type', array('@type' => $type_name)));
$this->assertTrue(isset($instances['comment_node_' . $type_name]['comment_body']), format_string('The comment_body field is present for comments on type @type', array('@type' => $type_name)));
// Delete the instance along the way.
field_delete_instance($instances['comment_node_' . $type_name]['comment_body']);
@@ -2025,7 +2027,7 @@ class CommentFieldsTest extends CommentHelperCase {
// Check that the 'comment_body' field is deleted.
$field = field_info_field('comment_body');
$this->assertTrue(empty($field), t('The comment_body field was deleted'));
$this->assertTrue(empty($field), 'The comment_body field was deleted');
// Create a new content type.
$type_name = 'test_node_type_2';
@@ -2034,9 +2036,9 @@ class CommentFieldsTest extends CommentHelperCase {
// Check that the 'comment_body' field exists and has an instance on the
// new comment bundle.
$field = field_info_field('comment_body');
$this->assertTrue($field, t('The comment_body field exists'));
$this->assertTrue($field, 'The comment_body field exists');
$instances = field_info_instances('comment');
$this->assertTrue(isset($instances['comment_node_' . $type_name]['comment_body']), t('The comment_body field is present for comments on type @type', array('@type' => $type_name)));
$this->assertTrue(isset($instances['comment_node_' . $type_name]['comment_body']), format_string('The comment_body field is present for comments on type @type', array('@type' => $type_name)));
}
/**
@@ -2052,7 +2054,7 @@ class CommentFieldsTest extends CommentHelperCase {
$edit['modules[Core][comment][enable]'] = FALSE;
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->resetAll();
$this->assertFalse(module_exists('comment'), t('Comment module disabled.'));
$this->assertFalse(module_exists('comment'), 'Comment module disabled.');
// Enable core content type modules (blog, book, and poll).
$edit = array();
@@ -2067,7 +2069,7 @@ class CommentFieldsTest extends CommentHelperCase {
$edit['modules[Core][comment][enable]'] = 'comment';
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->resetAll();
$this->assertTrue(module_exists('comment'), t('Comment module enabled.'));
$this->assertTrue(module_exists('comment'), 'Comment module enabled.');
// Create nodes of each type.
$blog_node = $this->drupalCreateNode(array('type' => 'blog'));
+2
View File
@@ -55,6 +55,8 @@
* @see template_preprocess_comment()
* @see template_process()
* @see theme_comment()
*
* @ingroup themeable
*/
?>
<div class="<?php print $classes; ?> clearfix"<?php print $attributes; ?>>
+3 -3
View File
@@ -6,8 +6,8 @@ core = 7.x
files[] = contact.test
configure = admin/structure/contact
; Information added by drupal.org packaging script on 2012-08-01
version = "7.15"
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
project = "drupal"
datestamp = "1343839327"
datestamp = "1365027012"
+3 -3
View File
@@ -5,8 +5,8 @@ version = VERSION
core = 7.x
files[] = contextual.test
; Information added by drupal.org packaging script on 2012-08-01
version = "7.15"
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
project = "drupal"
datestamp = "1343839327"
datestamp = "1365027012"
+3 -3
View File
@@ -7,8 +7,8 @@ files[] = dashboard.test
dependencies[] = block
configure = admin/dashboard/customize
; Information added by drupal.org packaging script on 2012-08-01
version = "7.15"
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
project = "drupal"
datestamp = "1343839327"
datestamp = "1365027012"
+4
View File
@@ -1,3 +1,7 @@
/**
* @file
* Right-to-Left styling for the Database Logging module.
*/
.form-item-type,
.form-item-severity {
+57 -22
View File
@@ -2,14 +2,19 @@
/**
* @file
* Administrative page callbacks for the dblog module.
* Administrative page callbacks for the Database Logging module.
*/
/**
* Menu callback; displays a listing of log messages.
* Page callback: Displays a listing of database log messages.
*
* Messages are truncated at 56 chars. Full-length message could be viewed at
* the message details page.
* Messages are truncated at 56 chars. Full-length messages can be viewed on the
* message details page.
*
* @see dblog_clear_log_form()
* @see dblog_event()
* @see dblog_filter_form()
* @see dblog_menu()
*
* @ingroup logging_severity_levels
*/
@@ -81,12 +86,18 @@ function dblog_overview() {
}
/**
* Menu callback; generic function to display a page of the most frequent events.
* Page callback: Shows the most frequent log messages of a given event type.
*
* Messages are not truncated because events from this page have no detail view.
* Messages are not truncated on this page because events detailed herein do not
* have links to a detailed view.
*
* @param $type
* type of dblog events to display.
* @param string $type
* Type of database log events to display (e.g., 'search').
*
* @return array
* A build array in the format expected by drupal_render().
*
* @see dblog_menu()
*/
function dblog_top($type) {
@@ -127,7 +138,16 @@ function dblog_top($type) {
}
/**
* Menu callback; displays details about a log message.
* Page callback: Displays details about a specific database log message.
*
* @param int $id
* Unique ID of the database log message.
*
* @return array|string
* If the ID is located in the Database Logging table, a build array in the
* format expected by drupal_render(); otherwise, an empty string.
*
* @see dblog_menu()
*/
function dblog_event($id) {
$severity = watchdog_severity_levels();
@@ -184,7 +204,10 @@ function dblog_event($id) {
}
/**
* Build query for dblog administration filters based on session.
* Builds a query for database log administration filters based on session.
*
* @return array
* An associative array with keys 'where' and 'args'.
*/
function dblog_build_filter_query() {
if (empty($_SESSION['dblog_overview_filter'])) {
@@ -213,9 +236,16 @@ function dblog_build_filter_query() {
);
}
/**
* List dblog administration filters that can be applied.
* Creates a list of database log administration filters that can be applied.
*
* @return array
* Associative array of filters. The top-level keys are used as the form
* element names for the filters, and the values are arrays with the following
* elements:
* - title: Title of the filter.
* - where: The filter condition.
* - options: Array of options for the select list for the filter.
*/
function dblog_filters() {
$filters = array();
@@ -244,7 +274,7 @@ function dblog_filters() {
/**
* Returns HTML for a log message.
*
* @param $variables
* @param array $variables
* An associative array containing:
* - event: An object with at least the message and variables properties.
* - link: (optional) Format message as link, event->wid is required.
@@ -274,11 +304,13 @@ function theme_dblog_message($variables) {
}
/**
* Return form for dblog administration filters.
* Form constructor for the database logging filter form.
*
* @see dblog_filter_form_validate()
* @see dblog_filter_form_submit()
* @see dblog_overview()
*
* @ingroup forms
* @see dblog_filter_form_submit()
* @see dblog_filter_form_validate()
*/
function dblog_filter_form($form) {
$filters = dblog_filters();
@@ -316,12 +348,13 @@ function dblog_filter_form($form) {
'#value' => t('Reset')
);
}
return $form;
}
/**
* Validate result from dblog administration filter form.
* Form validation handler for dblog_filter_form().
*
* @see dblog_filter_form_submit()
*/
function dblog_filter_form_validate($form, &$form_state) {
if ($form_state['values']['op'] == t('Filter') && empty($form_state['values']['type']) && empty($form_state['values']['severity'])) {
@@ -330,7 +363,9 @@ function dblog_filter_form_validate($form, &$form_state) {
}
/**
* Process result from dblog administration filter form.
* Form submission handler for dblog_filter_form().
*
* @see dblog_filter_form_validate()
*/
function dblog_filter_form_submit($form, &$form_state) {
$op = $form_state['values']['op'];
@@ -351,10 +386,10 @@ function dblog_filter_form_submit($form, &$form_state) {
}
/**
* Return form for dblog clear button.
* Form constructor for the form that clears out the log.
*
* @ingroup forms
* @see dblog_clear_log_submit()
* @ingroup forms
*/
function dblog_clear_log_form($form) {
$form['dblog_clear'] = array(
@@ -374,7 +409,7 @@ function dblog_clear_log_form($form) {
}
/**
* Submit callback: clear database with log messages.
* Form submission handler for dblog_clear_log_form().
*/
function dblog_clear_log_submit() {
$_SESSION['dblog_overview_filter'] = array();
+5
View File
@@ -1,3 +1,8 @@
/**
* @file
* Admin styles for the Database Logging module.
*/
.form-item-type,
.form-item-severity {
float: left; /* LTR */
+3 -3
View File
@@ -5,8 +5,8 @@ version = VERSION
core = 7.x
files[] = dblog.test
; Information added by drupal.org packaging script on 2012-08-01
version = "7.15"
; Information added by drupal.org packaging script on 2013-04-03
version = "7.22"
project = "drupal"
datestamp = "1343839327"
datestamp = "1365027012"
+17
View File
@@ -85,6 +85,7 @@ function dblog_schema() {
'indexes' => array(
'type' => array('type'),
'uid' => array('uid'),
'severity' => array('severity'),
),
);
@@ -140,3 +141,19 @@ function dblog_update_7001() {
/**
* @} End of "addtogroup updates-6.x-to-7.x".
*/
/**
* @addtogroup updates-7.x-extra
* @{
*/
/**
* Add an index to the severity column in the watchdog database table.
*/
function dblog_update_7002() {
db_add_index('watchdog', 'severity', array('severity'));
}
/**
* @} End of "addtogroup updates-7.x-extra".
*/
+12 -6
View File
@@ -4,9 +4,9 @@
* @file
* System monitoring and logging for administrators.
*
* The dblog module monitors your site and keeps a list of
* recorded events containing usage and performance data, errors,
* warnings, and similar operational information.
* The Database Logging module monitors your site and keeps a list of recorded
* events containing usage and performance data, errors, warnings, and similar
* operational information.
*
* @see watchdog()
*/
@@ -96,7 +96,7 @@ function dblog_init() {
/**
* Implements hook_cron().
*
* Remove expired log messages and flood control events.
* Controls the size of the log table, paring it to 'dblog_row_limit' messages.
*/
function dblog_cron() {
// Cleanup the watchdog table.
@@ -121,6 +121,12 @@ function dblog_cron() {
}
}
/**
* Gathers a list of uniquely defined database log message types.
*
* @return array
* List of uniquely defined database log message types.
*/
function _dblog_get_message_types() {
$types = array();
@@ -135,7 +141,7 @@ function _dblog_get_message_types() {
/**
* Implements hook_watchdog().
*
* Note some values may be truncated for database column size restrictions.
* Note: Some values may be truncated to meet database column size restrictions.
*/
function dblog_watchdog(array $log_entry) {
Database::getConnection('default', 'default')->insert('watchdog')
@@ -155,7 +161,7 @@ function dblog_watchdog(array $log_entry) {
}
/**
* Implements hook_form_FORM_ID_alter().
* Implements hook_form_FORM_ID_alter() for system_logging_settings().
*/
function dblog_form_system_logging_settings_alter(&$form, $form_state) {
$form['dblog_row_limit'] = array(
+137 -93
View File
@@ -5,8 +5,23 @@
* Tests for dblog.module.
*/
/**
* Tests logging messages to the database.
*/
class DBLogTestCase extends DrupalWebTestCase {
/**
* A user with some relevent administrative permissions.
*
* @var object
*/
protected $big_user;
/**
* A user without any permissions.
*
* @var object
*/
protected $any_user;
public static function getInfo() {
@@ -28,7 +43,11 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
* Login users, create dblog events, and test dblog functionality through the admin and user interfaces.
* Tests Database Logging module functionality through interfaces.
*
* First logs in users, then creates database log events, and finally tests
* Database Logging module functionality through both the admin and user
* interfaces.
*/
function testDBLog() {
// Login the admin user.
@@ -46,12 +65,13 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
* Verify setting of the dblog row limit.
* Verifies setting of the database log row limit.
*
* @param integer $count Log row limit.
* @param int $row_limit
* The row limit.
*/
private function verifyRowLimit($row_limit) {
// Change the dblog row limit.
// Change the database log row limit.
$edit = array();
$edit['dblog_row_limit'] = $row_limit;
$this->drupalPost('admin/config/development/logging', $edit, t('Save configuration'));
@@ -66,33 +86,35 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
* Verify cron applies the dblog row limit.
* Verifies that cron correctly applies the database log row limit.
*
* @param integer $count Log row limit.
* @param int $row_limit
* The row limit.
*/
private function verifyCron($row_limit) {
// Generate additional log entries.
$this->generateLogEntries($row_limit + 10);
// Verify dblog row count exceeds row limit.
// Verify that the database log row count exceeds the row limit.
$count = db_query('SELECT COUNT(wid) FROM {watchdog}')->fetchField();
$this->assertTrue($count > $row_limit, t('Dblog row count of @count exceeds row limit of @limit', array('@count' => $count, '@limit' => $row_limit)));
// Run cron job.
// Run a cron job.
$this->cronRun();
// Verify dblog row count equals row limit plus one because cron adds a record after it runs.
// Verify that the database log row count equals the row limit plus one
// because cron adds a record after it runs.
$count = db_query('SELECT COUNT(wid) FROM {watchdog}')->fetchField();
$this->assertTrue($count == $row_limit + 1, t('Dblog row count of @count equals row limit of @limit plus one', array('@count' => $count, '@limit' => $row_limit)));
}
/**
* Generate dblog entries.
* Generates a number of random database log events.
*
* @param integer $count
* Number of log entries to generate.
* @param $type
* The type of watchdog entry.
* @param $severity
* The severity of the watchdog entry.
* @param int $count
* Number of watchdog entries to generate.
* @param string $type
* (optional) The type of watchdog entry. Defaults to 'custom'.
* @param int $severity
* (optional) The severity of the watchdog entry. Defaults to WATCHDOG_NOTICE.
*/
private function generateLogEntries($count, $type = 'custom', $severity = WATCHDOG_NOTICE) {
global $base_root;
@@ -119,42 +141,43 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
* Verify the logged in user has the desired access to the various dblog nodes.
* Confirms that database log reports are displayed at the correct paths.
*
* @param integer $response HTTP response code.
* @param int $response
* (optional) HTTP response code. Defaults to 200.
*/
private function verifyReports($response = 200) {
$quote = '&#039;';
// View dblog help node.
// View the database log help page.
$this->drupalGet('admin/help/dblog');
$this->assertResponse($response);
if ($response == 200) {
$this->assertText(t('Database logging'), t('DBLog help was displayed'));
}
// View dblog report node.
// View the database log report page.
$this->drupalGet('admin/reports/dblog');
$this->assertResponse($response);
if ($response == 200) {
$this->assertText(t('Recent log messages'), t('DBLog report was displayed'));
}
// View dblog page-not-found report node.
// View the database log page-not-found report page.
$this->drupalGet('admin/reports/page-not-found');
$this->assertResponse($response);
if ($response == 200) {
$this->assertText(t('Top ' . $quote . 'page not found' . $quote . ' errors'), t('DBLog page-not-found report was displayed'));
}
// View dblog access-denied report node.
// View the database log access-denied report page.
$this->drupalGet('admin/reports/access-denied');
$this->assertResponse($response);
if ($response == 200) {
$this->assertText(t('Top ' . $quote . 'access denied' . $quote . ' errors'), t('DBLog access-denied report was displayed'));
}
// View dblog event node.
// View the database log event page.
$this->drupalGet('admin/reports/event/1');
$this->assertResponse($response);
if ($response == 200) {
@@ -163,7 +186,7 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
* Verify events.
* Generates and then verifies various types of events.
*/
private function verifyEvents() {
// Invoke events.
@@ -179,14 +202,14 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
* Generate and verify user events.
*
* Generates and then verifies some user events.
*/
private function doUser() {
// Set user variables.
$name = $this->randomName();
$pass = user_password();
// Add user using form to generate add user event (which is not triggered by drupalCreateUser).
// Add a user using the form to generate an add user event (which is not
// triggered by drupalCreateUser).
$edit = array();
$edit['name'] = $name;
$edit['mail'] = $name . '@example.com';
@@ -195,15 +218,16 @@ class DBLogTestCase extends DrupalWebTestCase {
$edit['status'] = 1;
$this->drupalPost('admin/people/create', $edit, t('Create new account'));
$this->assertResponse(200);
// Retrieve user object.
// Retrieve the user object.
$user = user_load_by_name($name);
$this->assertTrue($user != NULL, t('User @name was loaded', array('@name' => $name)));
$user->pass_raw = $pass; // Needed by drupalLogin.
// pass_raw property is needed by drupalLogin.
$user->pass_raw = $pass;
// Login user.
$this->drupalLogin($user);
// Logout user.
$this->drupalLogout();
// Fetch row ids in watchdog that relate to the user.
// Fetch the row IDs in watchdog that relate to the user.
$result = db_query('SELECT wid FROM {watchdog} WHERE uid = :uid', array(':uid' => $user->uid));
foreach ($result as $row) {
$ids[] = $row->wid;
@@ -213,17 +237,18 @@ class DBLogTestCase extends DrupalWebTestCase {
// Login the admin user.
$this->drupalLogin($this->big_user);
// Delete user.
// Delete the user created at the start of this test.
// We need to POST here to invoke batch_process() in the internal browser.
$this->drupalPost('user/' . $user->uid . '/cancel', array('user_cancel_method' => 'user_cancel_reassign'), t('Cancel account'));
// View the dblog report.
// View the database log report.
$this->drupalGet('admin/reports/dblog');
$this->assertResponse(200);
// Verify events were recorded.
// Verify that the expected events were recorded.
// Add user.
// Default display includes name and email address; if too long then email is replaced by three periods.
// Default display includes name and email address; if too long, the email
// address is replaced by three periods.
$this->assertLogMessage(t('New user: %name (%email).', array('%name' => $name, '%email' => $user->mail)), t('DBLog event was recorded: [add user]'));
// Login user.
$this->assertLogMessage(t('Session opened for %name.', array('%name' => $name)), t('DBLog event was recorded: [login user]'));
@@ -232,7 +257,7 @@ class DBLogTestCase extends DrupalWebTestCase {
// Delete user.
$message = t('Deleted user: %name %email.', array('%name' => $name, '%email' => '<' . $user->mail . '>'));
$message_text = truncate_utf8(filter_xss($message, array()), 56, TRUE, TRUE);
// Verify full message on details page.
// Verify that the full message displays on the details page.
$link = FALSE;
if ($links = $this->xpath('//a[text()="' . html_entity_decode($message_text) . '"]')) {
// Found link with the message text.
@@ -253,17 +278,18 @@ class DBLogTestCase extends DrupalWebTestCase {
$not_found_url = $this->randomName(60);
$this->drupalGet($not_found_url);
$this->assertResponse(404);
// View dblog page-not-found report page.
// View the database log page-not-found report page.
$this->drupalGet('admin/reports/page-not-found');
$this->assertResponse(200);
// Check that full-length url displayed.
// Check that full-length URL displayed.
$this->assertText($not_found_url, t('DBLog event was recorded: [page not found]'));
}
/**
* Generate and verify node events.
* Generates and then verifies some node events.
*
* @param string $type Content type.
* @param string $type
* A node type (e.g., 'article', 'page' or 'poll').
*/
private function doNode($type) {
// Create user.
@@ -272,61 +298,65 @@ class DBLogTestCase extends DrupalWebTestCase {
// Login user.
$this->drupalLogin($user);
// Create node using form to generate add content event (which is not triggered by drupalCreateNode).
// Create a node using the form in order to generate an add content event
// (which is not triggered by drupalCreateNode).
$edit = $this->getContent($type);
$langcode = LANGUAGE_NONE;
$title = $edit["title"];
$this->drupalPost('node/add/' . $type, $edit, t('Save'));
$this->assertResponse(200);
// Retrieve node object.
// Retrieve the node object.
$node = $this->drupalGetNodeByTitle($title);
$this->assertTrue($node != NULL, t('Node @title was loaded', array('@title' => $title)));
// Edit node.
// Edit the node.
$edit = $this->getContentUpdate($type);
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
$this->assertResponse(200);
// Delete node.
// Delete the node.
$this->drupalPost('node/' . $node->nid . '/delete', array(), t('Delete'));
$this->assertResponse(200);
// View node (to generate page not found event).
// View the node (to generate page not found event).
$this->drupalGet('node/' . $node->nid);
$this->assertResponse(404);
// View the dblog report (to generate access denied event).
// View the database log report (to generate access denied event).
$this->drupalGet('admin/reports/dblog');
$this->assertResponse(403);
// Login the admin user.
$this->drupalLogin($this->big_user);
// View the dblog report.
// View the database log report.
$this->drupalGet('admin/reports/dblog');
$this->assertResponse(200);
// Verify events were recorded.
// Content added.
// Verify that node events were recorded.
// Was node content added?
$this->assertLogMessage(t('@type: added %title.', array('@type' => $type, '%title' => $title)), t('DBLog event was recorded: [content added]'));
// Content updated.
// Was node content updated?
$this->assertLogMessage(t('@type: updated %title.', array('@type' => $type, '%title' => $title)), t('DBLog event was recorded: [content updated]'));
// Content deleted.
// Was node content deleted?
$this->assertLogMessage(t('@type: deleted %title.', array('@type' => $type, '%title' => $title)), t('DBLog event was recorded: [content deleted]'));
// View dblog access-denied report node.
// View the database log access-denied report page.
$this->drupalGet('admin/reports/access-denied');
$this->assertResponse(200);
// Access denied.
// Verify that the 'access denied' event was recorded.
$this->assertText(t('admin/reports/dblog'), t('DBLog event was recorded: [access denied]'));
// View dblog page-not-found report node.
// View the database log page-not-found report page.
$this->drupalGet('admin/reports/page-not-found');
$this->assertResponse(200);
// Page not found.
// Verify that the 'page not found' event was recorded.
$this->assertText(t('node/@nid', array('@nid' => $node->nid)), t('DBLog event was recorded: [page not found]'));
}
/**
* Create content based on content type.
* Creates random content based on node content type.
*
* @param string $type Content type.
* @return array Content.
* @param string $type
* Node content type (e.g., 'article').
*
* @return array
* Random content needed by various node types.
*/
private function getContent($type) {
$langcode = LANGUAGE_NONE;
@@ -350,10 +380,13 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
* Create content update based on content type.
* Creates random content as an update based on node content type.
*
* @param string $type Content type.
* @return array Content.
* @param string $type
* Node content type (e.g., 'article').
*
* @return array
* Random content needed by various node types.
*/
private function getContentUpdate($type) {
switch ($type) {
@@ -375,11 +408,14 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
* Login an admin user, create dblog event, and test clearing dblog functionality through the admin interface.
* Tests the addition and clearing of log events through the admin interface.
*
* Logs in the admin user, creates a database log event, and tests the
* functionality of clearing the database log through the admin interface.
*/
protected function testDBLogAddAndClear() {
global $base_root;
// Get a count of how many watchdog entries there are.
// Get a count of how many watchdog entries already exist.
$count = db_query('SELECT COUNT(*) FROM {watchdog}')->fetchField();
$log = array(
'type' => 'custom',
@@ -396,27 +432,27 @@ class DBLogTestCase extends DrupalWebTestCase {
);
// Add a watchdog entry.
dblog_watchdog($log);
// Make sure the table count has actually incremented.
// Make sure the table count has actually been incremented.
$this->assertEqual($count + 1, db_query('SELECT COUNT(*) FROM {watchdog}')->fetchField(), t('dblog_watchdog() added an entry to the dblog :count', array(':count' => $count)));
// Login the admin user.
$this->drupalLogin($this->big_user);
// Now post to clear the db table.
// Post in order to clear the database table.
$this->drupalPost('admin/reports/dblog', array(), t('Clear log messages'));
// Count rows in watchdog that previously related to the deleted user.
// Count the rows in watchdog that previously related to the deleted user.
$count = db_query('SELECT COUNT(*) FROM {watchdog}')->fetchField();
$this->assertEqual($count, 0, t('DBLog contains :count records after a clear.', array(':count' => $count)));
}
/**
* Test the dblog filter on admin/reports/dblog.
* Tests the database log filter functionality at admin/reports/dblog.
*/
protected function testFilter() {
$this->drupalLogin($this->big_user);
// Clear log to ensure that only generated entries are found.
// Clear the log to ensure that only generated entries will be found.
db_delete('watchdog')->execute();
// Generate watchdog entries.
// Generate 9 random watchdog entries.
$type_names = array();
$types = array();
for ($i = 0; $i < 3; $i++) {
@@ -432,10 +468,10 @@ class DBLogTestCase extends DrupalWebTestCase {
}
}
// View the dblog.
// View the database log page.
$this->drupalGet('admin/reports/dblog');
// Confirm all the entries are displayed.
// Confirm that all the entries are displayed.
$count = $this->getTypeCount($types);
foreach ($types as $key => $type) {
$this->assertEqual($count[$key], $type['count'], 'Count matched');
@@ -461,8 +497,8 @@ class DBLogTestCase extends DrupalWebTestCase {
$this->assertEqual(array_sum($count), $type_count, 'Count matched');
}
// Set filter to match each of the three type attributes and confirm the
// number of entries displayed.
// Set the filter to match each of the two filter-type attributes and
// confirm the correct number of entries are displayed.
foreach ($types as $key => $type) {
$edit = array(
'type[]' => array($type['type']),
@@ -480,10 +516,14 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
* Get the log entry information form the page.
* Gets the database log event information from the browser page.
*
* @return
* List of entries and their information.
* @return array
* List of log events where each event is an array with following keys:
* - severity: (int) A database log severity constant.
* - type: (string) The type of database log event.
* - message: (string) The message for this database log event.
* - user: (string) The user associated with this database log event.
*/
protected function getLogEntries() {
$entries = array();
@@ -502,11 +542,12 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
* Get the count of entries per type.
* Gets the count of database log entries by database log event type.
*
* @param $types
* @param array $types
* The type information to compare against.
* @return
*
* @return array
* The count of each type keyed by the key of the $types array.
*/
protected function getTypeCount(array $types) {
@@ -524,11 +565,12 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
* Get the watchdog severity constant corresponding to the CSS class.
* Gets the watchdog severity constant corresponding to the CSS class.
*
* @param $class
* @param string $class
* CSS class attribute.
* @return
*
* @return int|null
* The watchdog severity constant or NULL if not found.
*
* @ingroup logging_severity_levels
@@ -557,11 +599,12 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
* Extract the text contained by the element.
* Extracts the text contained by the XHTML element.
*
* @param $element
* @param SimpleXMLElement $element
* Element to extract text from.
* @return
*
* @return string
* Extracted text.
*/
protected function asText(SimpleXMLElement $element) {
@@ -572,21 +615,22 @@ class DBLogTestCase extends DrupalWebTestCase {
}
/**
* Assert messages appear on the log overview screen.
* Confirms that a log message appears on the database log overview screen.
*
* This function should be used only for admin/reports/dblog page, because it
* check for the message link text truncated to 56 characters. Other dblog
* pages have no detail links so contains a full message text.
* This function should only be used for the admin/reports/dblog page, because
* it checks for the message link text truncated to 56 characters. Other log
* pages have no detail links so they contain the full message text.
*
* @param $log_message
* The message to check.
* @param $message
* @param string $log_message
* The database log message to check.
* @param string $message
* The message to pass to simpletest.
*/
protected function assertLogMessage($log_message, $message) {
$message_text = truncate_utf8(filter_xss($log_message, array()), 56, TRUE, TRUE);
// After filter_xss() HTML entities should be converted to their characters
// because assertLink() uses this string in xpath() to query DOM.
// After filter_xss(), HTML entities should be converted to their character
// equivalents because assertLink() uses this string in xpath() to query the
// Document Object Model (DOM).
$this->assertLink(html_entity_decode($message_text), 0, $message);
}
}
+18 -11
View File
@@ -690,11 +690,10 @@ function hook_field_is_empty($item, $field) {
* which widget to use. Widget types are defined by implementing
* hook_field_widget_info().
*
* Widgets are
* @link http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html Form API @endlink
* elements with additional processing capabilities. Widget hooks are typically
* called by the Field Attach API during the creation of the field form
* structure with field_attach_form().
* Widgets are @link forms_api_reference.html Form API @endlink elements with
* additional processing capabilities. Widget hooks are typically called by the
* Field Attach API during the creation of the field form structure with
* field_attach_form().
*
* @see field
* @see field_types
@@ -729,6 +728,9 @@ function hook_field_is_empty($item, $field) {
* - FIELD_BEHAVIOR_DEFAULT: (default) If the widget accepts default
* values.
* - FIELD_BEHAVIOR_NONE: if the widget does not support default values.
* - weight: (optional) An integer to determine the weight of this widget
* relative to other widgets in the Field UI when selecting a widget for a
* given field instance.
*
* @see hook_field_widget_info_alter()
* @see hook_field_widget_form()
@@ -738,7 +740,7 @@ function hook_field_is_empty($item, $field) {
* @see hook_field_widget_settings_form()
*/
function hook_field_widget_info() {
return array(
return array(
'text_textfield' => array(
'label' => t('Text field'),
'field types' => array('text'),
@@ -765,6 +767,8 @@ function hook_field_widget_info() {
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
// As an advanced widget, force it to sink to the bottom of the choices.
'weight' => 2,
),
);
}
@@ -869,7 +873,7 @@ function hook_field_widget_form(&$form, &$form_state, $field, $instance, $langco
'#type' => $instance['widget']['type'],
'#default_value' => isset($items[$delta]) ? $items[$delta] : '',
);
return $element;
return array('value' => $element);
}
/**
@@ -1072,8 +1076,8 @@ function hook_field_formatter_info() {
* Perform alterations on Field API formatter types.
*
* @param $info
* Array of informations on formatter types exposed by
* hook_field_field_formatter_info() implementations.
* An array of information on formatter types exposed by
* hook_field_formatter_info() implementations.
*/
function hook_field_formatter_info_alter(&$info) {
// Add a setting to a formatter type.
@@ -1731,11 +1735,14 @@ function hook_field_storage_details_alter(&$details, $field) {
* loaded.
*/
function hook_field_storage_load($entity_type, $entities, $age, $fields, $options) {
$field_info = field_info_field_by_ids();
$load_current = $age == FIELD_LOAD_CURRENT;
foreach ($fields as $field_id => $ids) {
$field = $field_info[$field_id];
// By the time this hook runs, the relevant field definitions have been
// populated and cached in FieldInfo, so calling field_info_field_by_id()
// on each field individually is more efficient than loading all fields in
// memory upfront with field_info_field_by_ids().
$field = field_info_field_by_id($field_id);
$field_name = $field['field_name'];
$table = $load_current ? _field_sql_storage_tablename($field) : _field_sql_storage_revision_tablename($field);

Some files were not shown because too many files have changed in this diff Show More